From d2f86f92fd11a220399d726f7f5f7a8375737619 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Mon, 21 Jun 2021 07:21:25 -0300 Subject: [PATCH 01/72] Initial commit --- src/events/mod-tools/ModToolsEvent.ts | 8 +++ src/views/mod-tools/ModToolsView.tsx | 59 +++++++++++++++++++ src/views/mod-tools/ModToolsView.types.ts | 2 + .../mod-tools/context/ModToolsContext.tsx | 14 +++++ .../context/ModToolsContext.types.ts | 13 ++++ .../mod-tools/reducers/ModToolsReducer.tsx | 30 ++++++++++ 6 files changed, 126 insertions(+) create mode 100644 src/events/mod-tools/ModToolsEvent.ts create mode 100644 src/views/mod-tools/ModToolsView.tsx create mode 100644 src/views/mod-tools/ModToolsView.types.ts create mode 100644 src/views/mod-tools/context/ModToolsContext.tsx create mode 100644 src/views/mod-tools/context/ModToolsContext.types.ts create mode 100644 src/views/mod-tools/reducers/ModToolsReducer.tsx diff --git a/src/events/mod-tools/ModToolsEvent.ts b/src/events/mod-tools/ModToolsEvent.ts new file mode 100644 index 00000000..dec4fdb8 --- /dev/null +++ b/src/events/mod-tools/ModToolsEvent.ts @@ -0,0 +1,8 @@ +import { NitroEvent } from 'nitro-renderer'; + +export class ModToolsEvent extends NitroEvent +{ + public static SHOW_MOD_TOOLS: string = 'MTE_SHOW_MOD_TOOLS'; + public static HIDE_MOD_TOOLS: string = 'MTE_HIDE_MOD_TOOLS'; + public static TOGGLE_MOD_TOOLS: string = 'MTE_TOGGLE_MOD_TOOLS'; +} diff --git a/src/views/mod-tools/ModToolsView.tsx b/src/views/mod-tools/ModToolsView.tsx new file mode 100644 index 00000000..aefe75f5 --- /dev/null +++ b/src/views/mod-tools/ModToolsView.tsx @@ -0,0 +1,59 @@ +import { FC, useCallback, useEffect, useReducer, useState } from 'react'; +import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent'; +import { useUiEvent } from '../../hooks/events/ui/ui-event'; +import { NitroCardContentView, NitroCardTabsView, NitroCardView } from '../../layout'; +import { NitroCardSimpleHeaderView } from '../../layout/card/simple-header'; +import { LocalizeText } from '../../utils/LocalizeText'; +import { ModToolsContextProvider } from './context/ModToolsContext'; +import { ModToolsViewProps } from './ModToolsView.types'; +import { initialModTools, ModToolsReducer } from './reducers/ModToolsReducer'; + +export const ModToolsView: FC = props => +{ + const [ isVisible, setIsVisible ] = useState(false); + const [ modToolsState, dispatchModToolsState ] = useReducer(ModToolsReducer, initialModTools); + + const onModToolsEvent = useCallback((event: ModToolsEvent) => + { + switch(event.type) + { + case ModToolsEvent.SHOW_MOD_TOOLS: + setIsVisible(true); + return; + case ModToolsEvent.HIDE_MOD_TOOLS: + setIsVisible(false); + return; + case ModToolsEvent.TOGGLE_MOD_TOOLS: + setIsVisible(value => !value); + return; + } + }, []); + + useUiEvent(ModToolsEvent.SHOW_MOD_TOOLS, onModToolsEvent); + useUiEvent(ModToolsEvent.HIDE_MOD_TOOLS, onModToolsEvent); + useUiEvent(ModToolsEvent.TOGGLE_MOD_TOOLS, onModToolsEvent); + + useEffect(() => + { + if(!isVisible) return; + }, [ isVisible ]); + + return ( + + { isVisible && + + setIsVisible(false) } /> + + + +
+
+
+
+
+
+
+
} +
+ ); +} diff --git a/src/views/mod-tools/ModToolsView.types.ts b/src/views/mod-tools/ModToolsView.types.ts new file mode 100644 index 00000000..3aa7691f --- /dev/null +++ b/src/views/mod-tools/ModToolsView.types.ts @@ -0,0 +1,2 @@ +export interface ModToolsViewProps +{} diff --git a/src/views/mod-tools/context/ModToolsContext.tsx b/src/views/mod-tools/context/ModToolsContext.tsx new file mode 100644 index 00000000..97873603 --- /dev/null +++ b/src/views/mod-tools/context/ModToolsContext.tsx @@ -0,0 +1,14 @@ +import { createContext, FC, useContext } from 'react'; +import { IModToolsContext, ModToolsContextProps } from './ModToolsContext.types'; + +const ModToolsContext = createContext({ + modToolsState: null, + dispatchModToolsState: null +}); + +export const ModToolsContextProvider: FC = props => +{ + return { props.children } +} + +export const useModToolsContext = () => useContext(ModToolsContext); diff --git a/src/views/mod-tools/context/ModToolsContext.types.ts b/src/views/mod-tools/context/ModToolsContext.types.ts new file mode 100644 index 00000000..46c6a9b8 --- /dev/null +++ b/src/views/mod-tools/context/ModToolsContext.types.ts @@ -0,0 +1,13 @@ +import { Dispatch, ProviderProps } from 'react'; +import { IModToolsAction, IModToolsState } from '../reducers/ModToolsReducer'; + +export interface IModToolsContext +{ + modToolsState: IModToolsState; + dispatchModToolsState: Dispatch; +} + +export interface ModToolsContextProps extends ProviderProps +{ + +} diff --git a/src/views/mod-tools/reducers/ModToolsReducer.tsx b/src/views/mod-tools/reducers/ModToolsReducer.tsx new file mode 100644 index 00000000..cc09498c --- /dev/null +++ b/src/views/mod-tools/reducers/ModToolsReducer.tsx @@ -0,0 +1,30 @@ +import { Reducer } from 'react'; + +export interface IModToolsState +{ + +} + +export interface IModToolsAction +{ + type: string; + payload: { + } +} + +export class ModToolsActions +{ + +} + +export const initialModTools: IModToolsState = { +} + +export const ModToolsReducer: Reducer = (state, action) => +{ + switch(action.type) + { + default: + return state; + } +} From 6f4839dd6e2f5b3c5bffa2ba088c96226f1832e0 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Tue, 22 Jun 2021 08:10:01 -0300 Subject: [PATCH 02/72] DONT USE IT --- src/events/mod-tools/ModToolsEvent.ts | 2 + .../mod-tools/ModToolsOpenRoomInfoEvent.ts | 18 ++ .../mod-tools/ModToolsSelectUserEvent.ts | 25 +++ .../NitroCardSimpleHeaderView.scss | 2 + .../NitroCardSimpleHeaderView.tsx | 2 - src/views/Styles.scss | 1 + src/views/main/MainView.tsx | 2 + src/views/mod-tools/ModToolsView.scss | 6 + src/views/mod-tools/ModToolsView.tsx | 156 ++++++++++++++++-- .../mod-tools/reducers/ModToolsReducer.tsx | 39 ++++- .../views/chatlog/ModToolsChatlogView.scss | 26 +++ .../views/chatlog/ModToolsChatlogView.tsx | 85 ++++++++++ .../chatlog/ModToolsChatlogView.types.ts | 5 + .../views/room/ModToolsRoomView.scss | 3 + .../mod-tools/views/room/ModToolsRoomView.tsx | 105 ++++++++++++ .../views/room/ModToolsRoomView.types.ts | 5 + .../views/tickets/ModToolsTicketsView.tsx | 16 ++ .../tickets/ModToolsTicketsView.types.ts | 2 + .../mod-tools/views/user/ModToolsUserView.tsx | 16 ++ .../views/user/ModToolsUserView.types.ts | 2 + src/views/room/RoomView.tsx | 15 +- src/views/toolbar/ToolbarView.tsx | 7 + src/views/toolbar/ToolbarView.types.ts | 1 + 23 files changed, 518 insertions(+), 23 deletions(-) create mode 100644 src/events/mod-tools/ModToolsOpenRoomInfoEvent.ts create mode 100644 src/events/mod-tools/ModToolsSelectUserEvent.ts create mode 100644 src/views/mod-tools/ModToolsView.scss create mode 100644 src/views/mod-tools/views/chatlog/ModToolsChatlogView.scss create mode 100644 src/views/mod-tools/views/chatlog/ModToolsChatlogView.tsx create mode 100644 src/views/mod-tools/views/chatlog/ModToolsChatlogView.types.ts create mode 100644 src/views/mod-tools/views/room/ModToolsRoomView.scss create mode 100644 src/views/mod-tools/views/room/ModToolsRoomView.tsx create mode 100644 src/views/mod-tools/views/room/ModToolsRoomView.types.ts create mode 100644 src/views/mod-tools/views/tickets/ModToolsTicketsView.tsx create mode 100644 src/views/mod-tools/views/tickets/ModToolsTicketsView.types.ts create mode 100644 src/views/mod-tools/views/user/ModToolsUserView.tsx create mode 100644 src/views/mod-tools/views/user/ModToolsUserView.types.ts diff --git a/src/events/mod-tools/ModToolsEvent.ts b/src/events/mod-tools/ModToolsEvent.ts index dec4fdb8..fca082ec 100644 --- a/src/events/mod-tools/ModToolsEvent.ts +++ b/src/events/mod-tools/ModToolsEvent.ts @@ -5,4 +5,6 @@ export class ModToolsEvent extends NitroEvent public static SHOW_MOD_TOOLS: string = 'MTE_SHOW_MOD_TOOLS'; public static HIDE_MOD_TOOLS: string = 'MTE_HIDE_MOD_TOOLS'; public static TOGGLE_MOD_TOOLS: string = 'MTE_TOGGLE_MOD_TOOLS'; + public static SELECT_USER: string = 'MTE_SELECT_USER'; + public static OPEN_ROOM_INFO: string = 'MTE_OPEN_ROOM_INFO'; } diff --git a/src/events/mod-tools/ModToolsOpenRoomInfoEvent.ts b/src/events/mod-tools/ModToolsOpenRoomInfoEvent.ts new file mode 100644 index 00000000..24465610 --- /dev/null +++ b/src/events/mod-tools/ModToolsOpenRoomInfoEvent.ts @@ -0,0 +1,18 @@ +import { ModToolsEvent } from './ModToolsEvent'; + +export class ModToolsOpenRoomInfoEvent extends ModToolsEvent +{ + private _roomId: number; + + constructor(roomId: number) + { + super(ModToolsEvent.OPEN_ROOM_INFO); + + this._roomId = roomId; + } + + public get roomId(): number + { + return this._roomId; + } +} diff --git a/src/events/mod-tools/ModToolsSelectUserEvent.ts b/src/events/mod-tools/ModToolsSelectUserEvent.ts new file mode 100644 index 00000000..148ffe28 --- /dev/null +++ b/src/events/mod-tools/ModToolsSelectUserEvent.ts @@ -0,0 +1,25 @@ +import { ModToolsEvent } from './ModToolsEvent'; + +export class ModToolsSelectUserEvent extends ModToolsEvent +{ + private _webID: number; + private _name: string; + + constructor(webID: number, name: string) + { + super(ModToolsEvent.SELECT_USER); + + this._webID = webID; + this._name = name; + } + + public get webID(): number + { + return this._webID; + } + + public get name(): string + { + return this._name; + } +} diff --git a/src/layout/card/simple-header/NitroCardSimpleHeaderView.scss b/src/layout/card/simple-header/NitroCardSimpleHeaderView.scss index 4b1439a6..47c578b5 100644 --- a/src/layout/card/simple-header/NitroCardSimpleHeaderView.scss +++ b/src/layout/card/simple-header/NitroCardSimpleHeaderView.scss @@ -5,4 +5,6 @@ .bg-tertiary-split { border: 2px solid darken($quaternary,4); box-shadow:0 0 0 2px $white; + margin-left: 24px; + margin-right: 24px; } diff --git a/src/layout/card/simple-header/NitroCardSimpleHeaderView.tsx b/src/layout/card/simple-header/NitroCardSimpleHeaderView.tsx index d71306b3..e7d0d79f 100644 --- a/src/layout/card/simple-header/NitroCardSimpleHeaderView.tsx +++ b/src/layout/card/simple-header/NitroCardSimpleHeaderView.tsx @@ -7,11 +7,9 @@ export const NitroCardSimpleHeaderView: FC = pro return (
-
{ headerText }
-
diff --git a/src/views/Styles.scss b/src/views/Styles.scss index 657a17c8..f43f2f31 100644 --- a/src/views/Styles.scss +++ b/src/views/Styles.scss @@ -20,3 +20,4 @@ @import './room-host/RoomHostView'; @import './room-previewer/RoomPreviewerView'; @import './toolbar/ToolbarView'; +@import './mod-tools/ModToolsView'; diff --git a/src/views/main/MainView.tsx b/src/views/main/MainView.tsx index ecf77d91..feb9cf6f 100644 --- a/src/views/main/MainView.tsx +++ b/src/views/main/MainView.tsx @@ -8,6 +8,7 @@ import { CatalogView } from '../catalog/CatalogView'; import { FriendListView } from '../friend-list/FriendListView'; import { HotelView } from '../hotel-view/HotelView'; import { InventoryView } from '../inventory/InventoryView'; +import { ModToolsView } from '../mod-tools/ModToolsView'; import { NavigatorView } from '../navigator/NavigatorView'; import { RightSideView } from '../right-side/RightSideView'; import { RoomHostView } from '../room-host/RoomHostView'; @@ -45,6 +46,7 @@ export function MainView(props: MainViewProps): JSX.Element return (
{ landingViewVisible && } + diff --git a/src/views/mod-tools/ModToolsView.scss b/src/views/mod-tools/ModToolsView.scss new file mode 100644 index 00000000..9f5554e9 --- /dev/null +++ b/src/views/mod-tools/ModToolsView.scss @@ -0,0 +1,6 @@ +.nitro-mod-tools { + width: 200px; +} + +@import './views/chatlog/ModToolsChatlogView'; +@import './views/room/ModToolsRoomView'; diff --git a/src/views/mod-tools/ModToolsView.tsx b/src/views/mod-tools/ModToolsView.tsx index aefe75f5..0b2a49c3 100644 --- a/src/views/mod-tools/ModToolsView.tsx +++ b/src/views/mod-tools/ModToolsView.tsx @@ -1,18 +1,28 @@ +import { RoomEngineEvent } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent'; -import { useUiEvent } from '../../hooks/events/ui/ui-event'; -import { NitroCardContentView, NitroCardTabsView, NitroCardView } from '../../layout'; +import { ModToolsOpenRoomInfoEvent } from '../../events/mod-tools/ModToolsOpenRoomInfoEvent'; +import { ModToolsSelectUserEvent } from '../../events/mod-tools/ModToolsSelectUserEvent'; +import { useRoomEngineEvent } from '../../hooks/events'; +import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event'; +import { NitroCardContentView, NitroCardView } from '../../layout'; import { NitroCardSimpleHeaderView } from '../../layout/card/simple-header'; -import { LocalizeText } from '../../utils/LocalizeText'; import { ModToolsContextProvider } from './context/ModToolsContext'; import { ModToolsViewProps } from './ModToolsView.types'; -import { initialModTools, ModToolsReducer } from './reducers/ModToolsReducer'; +import { initialModTools, ModToolsActions, ModToolsReducer } from './reducers/ModToolsReducer'; +import { ModToolsRoomView } from './views/room/ModToolsRoomView'; +import { ModToolsTicketsView } from './views/tickets/ModToolsTicketsView'; +import { ModToolsUserView } from './views/user/ModToolsUserView'; export const ModToolsView: FC = props => { const [ isVisible, setIsVisible ] = useState(false); const [ modToolsState, dispatchModToolsState ] = useReducer(ModToolsReducer, initialModTools); - + const { currentRoomId = null, selectedUser = null, openRooms = null, openChatlogs = null } = modToolsState; + + const [ isUserVisible, setIsUserVisible ] = useState(false); + const [ isTicketsVisible, setIsTicketsVisible ] = useState(false); + const onModToolsEvent = useCallback((event: ModToolsEvent) => { switch(event.type) @@ -26,12 +36,123 @@ export const ModToolsView: FC = props => case ModToolsEvent.TOGGLE_MOD_TOOLS: setIsVisible(value => !value); return; + case ModToolsEvent.SELECT_USER: { + const castedEvent = (event as ModToolsSelectUserEvent); + + dispatchModToolsState({ + type: ModToolsActions.SET_SELECTED_USER, + payload: { + selectedUser: { + webID: castedEvent.webID, + name: castedEvent.name + } + } + }); + return; + } + case ModToolsEvent.OPEN_ROOM_INFO: { + const castedEvent = (event as ModToolsOpenRoomInfoEvent); + + if(openRooms && openRooms.includes(castedEvent.roomId)) return; + + dispatchModToolsState({ + type: ModToolsActions.SET_OPEN_ROOMS, + payload: { + openRooms: [...openRooms, castedEvent.roomId] + } + }); + return; + } } - }, []); + }, [ dispatchModToolsState, setIsVisible, openRooms ]); useUiEvent(ModToolsEvent.SHOW_MOD_TOOLS, onModToolsEvent); useUiEvent(ModToolsEvent.HIDE_MOD_TOOLS, onModToolsEvent); useUiEvent(ModToolsEvent.TOGGLE_MOD_TOOLS, onModToolsEvent); + useUiEvent(ModToolsEvent.SELECT_USER, onModToolsEvent); + useUiEvent(ModToolsEvent.OPEN_ROOM_INFO, onModToolsEvent); + + const onRoomEngineEvent = useCallback((event: RoomEngineEvent) => + { + switch(event.type) + { + case RoomEngineEvent.INITIALIZED: + dispatchModToolsState({ + type: ModToolsActions.SET_CURRENT_ROOM_ID, + payload: { + currentRoomId: event.roomId + } + }); + return; + case RoomEngineEvent.DISPOSED: + dispatchModToolsState({ + type: ModToolsActions.SET_CURRENT_ROOM_ID, + payload: { + currentRoomId: null + } + }); + return; + } + }, [ dispatchModToolsState ]); + + useRoomEngineEvent(RoomEngineEvent.INITIALIZED, onRoomEngineEvent); + useRoomEngineEvent(RoomEngineEvent.DISPOSED, onRoomEngineEvent); + + const handleClick = useCallback((action: string, value?: string) => + { + if(!action) return; + + switch(action) + { + case 'toggle_room': { + if(!openRooms) + { + dispatchUiEvent(new ModToolsOpenRoomInfoEvent(currentRoomId)); + return; + } + + const itemIndex = openRooms.indexOf(currentRoomId); + + if(itemIndex > -1) + { + handleClick('close_room', currentRoomId.toString()); + } + else + { + dispatchUiEvent(new ModToolsOpenRoomInfoEvent(currentRoomId)); + } + return; + } + case 'close_room': { + const itemIndex = openRooms.indexOf(Number(value)); + + const clone = Array.from(openRooms); + clone.splice(itemIndex, 1); + + dispatchModToolsState({ + type: ModToolsActions.SET_OPEN_ROOMS, + payload: { + openRooms: clone + } + }); + return; + } + case 'close_chatlog': { + const itemIndex = openChatlogs.indexOf(Number(value)); + + const clone = Array.from(openChatlogs); + clone.splice(itemIndex, 1); + + dispatchModToolsState({ + type: ModToolsActions.SET_OPEN_CHATLOGS, + payload: { + openChatlogs: clone + } + }); + return; + } + } + }, [ dispatchModToolsState, openRooms, openChatlogs, currentRoomId ]); useEffect(() => { @@ -42,18 +163,21 @@ export const ModToolsView: FC = props => { isVisible && - setIsVisible(false) } /> - - - -
-
-
-
-
-
+ setIsVisible(false) } /> + + + + +
} + { openRooms && openRooms.map(roomId => + { + return handleClick('close_room', roomId.toString()) } />; + }) } + + { isUserVisible && } + { isTicketsVisible && }
); } diff --git a/src/views/mod-tools/reducers/ModToolsReducer.tsx b/src/views/mod-tools/reducers/ModToolsReducer.tsx index cc09498c..955d70b9 100644 --- a/src/views/mod-tools/reducers/ModToolsReducer.tsx +++ b/src/views/mod-tools/reducers/ModToolsReducer.tsx @@ -2,28 +2,61 @@ import { Reducer } from 'react'; export interface IModToolsState { - + selectedUser: {webID: number, name: string}; + currentRoomId: number; + openRooms: number[]; + openChatlogs: number[]; } export interface IModToolsAction { type: string; payload: { + selectedUser?: {webID: number, name: string}; + currentRoomId?: number; + openRooms?: number[]; + openChatlogs?: number[]; } } export class ModToolsActions { - + public static SET_SELECTED_USER: string = 'MTA_SET_SELECTED_USER'; + public static SET_CURRENT_ROOM_ID: string = 'MTA_SET_CURRENT_ROOM_ID'; + public static SET_OPEN_ROOMS: string = 'MTA_SET_OPEN_ROOMS'; + public static SET_OPEN_CHATLOGS: string = 'MTA_SET_OPEN_CHATLOGS'; + public static RESET_STATE: string = 'MTA_RESET_STATE'; } export const initialModTools: IModToolsState = { -} + selectedUser: null, + currentRoomId: null, + openRooms: null, + openChatlogs: null +}; export const ModToolsReducer: Reducer = (state, action) => { switch(action.type) { + case ModToolsActions.SET_SELECTED_USER: { + const selectedUser = (action.payload.selectedUser || state.selectedUser || null); + + return { ...state, selectedUser }; + } + case ModToolsActions.SET_CURRENT_ROOM_ID: { + const currentRoomId = (action.payload.currentRoomId || state.currentRoomId || null); + + return { ...state, currentRoomId }; + } + case ModToolsActions.SET_OPEN_ROOMS: { + const openRooms = (action.payload.openRooms || state.openRooms || null); + + return { ...state, openRooms }; + } + case ModToolsActions.RESET_STATE: { + return { ...initialModTools }; + } default: return state; } diff --git a/src/views/mod-tools/views/chatlog/ModToolsChatlogView.scss b/src/views/mod-tools/views/chatlog/ModToolsChatlogView.scss new file mode 100644 index 00000000..7a2ddc8a --- /dev/null +++ b/src/views/mod-tools/views/chatlog/ModToolsChatlogView.scss @@ -0,0 +1,26 @@ +.nitro-mod-tools-chatlog { + width: 480px; + + .chatlog-messages { + height: 300px; + max-height: 300px; + + .table { + color: $black; + + > :not(caption) > * > * { + box-shadow: none; + border-bottom: 1px solid rgba(0, 0, 0, .2); + } + + &.table-striped > tbody > tr:nth-of-type(odd) { + color: $black; + background: rgba(0, 0, 0, .05); + } + + td { + padding: 0px 5px; + } + } + } +} diff --git a/src/views/mod-tools/views/chatlog/ModToolsChatlogView.tsx b/src/views/mod-tools/views/chatlog/ModToolsChatlogView.tsx new file mode 100644 index 00000000..d34f1dd5 --- /dev/null +++ b/src/views/mod-tools/views/chatlog/ModToolsChatlogView.tsx @@ -0,0 +1,85 @@ +import { ModtoolRequestRoomChatlogComposer, ModtoolRoomChatlogEvent, ModtoolRoomChatlogLine } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { TryVisitRoom } from '../../../../api/navigator/TryVisitRoom'; +import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages'; +import { NitroCardContentView, NitroCardView } from '../../../../layout'; +import { NitroCardSimpleHeaderView } from '../../../../layout/card/simple-header'; +import { ModToolsChatlogViewProps } from './ModToolsChatlogView.types'; + +export const ModToolsChatlogView: FC = props => +{ + const { roomId = null, onCloseClick = null } = props; + + const [ roomName, setRoomName ] = useState(null); + const [ messages, setMessages ] = useState(null); + const [ loadedRoomId, setLoadedRoomId ] = useState(null); + + const [ messagesRequested, setMessagesRequested ] = useState(false); + + useEffect(() => + { + if(messagesRequested) return; + + SendMessageHook(new ModtoolRequestRoomChatlogComposer(roomId)); + setMessagesRequested(true); + }, [ roomId, messagesRequested, setMessagesRequested ]); + + const onModtoolRoomChatlogEvent = useCallback((event: ModtoolRoomChatlogEvent) => + { + const parser = event.getParser(); + + setRoomName(parser.name); + setMessages(parser.chatlogs); + setLoadedRoomId(parser.id); + }, [ setRoomName, setMessages ]); + + CreateMessageHook(ModtoolRoomChatlogEvent, onModtoolRoomChatlogEvent); + + const handleClick = useCallback((action: string, value?: string) => + { + if(!action) return; + + switch(action) + { + case 'close': + onCloseClick(); + return; + case 'visit_room': + TryVisitRoom(loadedRoomId); + return; + } + }, [ onCloseClick, loadedRoomId ]); + + return ( + + handleClick('close') } /> + +
+ + +
+
+ { messages && + + + + + + + + + { messages.map((message, index) => + { + return + + + + ; + }) } + +
TimeUserMessage
{ message.timestamp }{ message.userName }{ message.message }
} +
+
+
+ ); +} diff --git a/src/views/mod-tools/views/chatlog/ModToolsChatlogView.types.ts b/src/views/mod-tools/views/chatlog/ModToolsChatlogView.types.ts new file mode 100644 index 00000000..0589cd02 --- /dev/null +++ b/src/views/mod-tools/views/chatlog/ModToolsChatlogView.types.ts @@ -0,0 +1,5 @@ +export interface ModToolsChatlogViewProps +{ + roomId: number; + onCloseClick: () => void; +} diff --git a/src/views/mod-tools/views/room/ModToolsRoomView.scss b/src/views/mod-tools/views/room/ModToolsRoomView.scss new file mode 100644 index 00000000..55ed938a --- /dev/null +++ b/src/views/mod-tools/views/room/ModToolsRoomView.scss @@ -0,0 +1,3 @@ +.nitro-mod-tools-room { + width: 240px; +} diff --git a/src/views/mod-tools/views/room/ModToolsRoomView.tsx b/src/views/mod-tools/views/room/ModToolsRoomView.tsx new file mode 100644 index 00000000..ad66e311 --- /dev/null +++ b/src/views/mod-tools/views/room/ModToolsRoomView.tsx @@ -0,0 +1,105 @@ +import { ModtoolRequestRoomInfoComposer, ModtoolRoomInfoEvent } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages'; +import { NitroCardContentView, NitroCardView } from '../../../../layout'; +import { NitroCardSimpleHeaderView } from '../../../../layout/card/simple-header'; +import { ModToolsRoomViewProps } from './ModToolsRoomView.types'; + +export const ModToolsRoomView: FC = props => +{ + const { roomId = null, onCloseClick = null } = props; + + const [ infoRequested, setInfoRequested ] = useState(false); + const [ loadedRoomId, setLoadedRoomId ] = useState(null); + + const [ name, setName ] = useState(null); + const [ ownerId, setOwnerId ] = useState(null); + const [ ownerName, setOwnerName ] = useState(null); + const [ ownerInRoom, setOwnerInRoom ] = useState(false); + const [ usersInRoom, setUsersInRoom ] = useState(0); + + useEffect(() => + { + if(infoRequested) return; + + SendMessageHook(new ModtoolRequestRoomInfoComposer(roomId)); + setInfoRequested(true); + }, [ roomId, infoRequested, setInfoRequested ]); + + const onModtoolRoomInfoEvent = useCallback((event: ModtoolRoomInfoEvent) => + { + const parser = event.getParser(); + + setLoadedRoomId(parser.id); + setName(parser.name); + setOwnerId(parser.ownerId); + setOwnerName(parser.ownerName); + setOwnerInRoom(parser.ownerInRoom); + setUsersInRoom(parser.playerAmount); + }, [ setLoadedRoomId, setName, setOwnerId, setOwnerName, setOwnerInRoom, setUsersInRoom ]); + + CreateMessageHook(ModtoolRoomInfoEvent, onModtoolRoomInfoEvent); + + const handleClick = useCallback((action: string, value?: string) => + { + if(!action) return; + + switch(action) + { + case 'close': + onCloseClick(); + return; + } + }, [ onCloseClick ]); + + return ( + + handleClick('close') } /> + +
+
+ Room Owner: { ownerName } +
+ +
+
+
+ Users in room: { usersInRoom } +
+ +
+
+
+ Owner in room: { ownerInRoom ? 'Yes' : 'No' } +
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + +
+
+
+ ); +} diff --git a/src/views/mod-tools/views/room/ModToolsRoomView.types.ts b/src/views/mod-tools/views/room/ModToolsRoomView.types.ts new file mode 100644 index 00000000..d096fcbe --- /dev/null +++ b/src/views/mod-tools/views/room/ModToolsRoomView.types.ts @@ -0,0 +1,5 @@ +export interface ModToolsRoomViewProps +{ + roomId: number; + onCloseClick: () => void; +} diff --git a/src/views/mod-tools/views/tickets/ModToolsTicketsView.tsx b/src/views/mod-tools/views/tickets/ModToolsTicketsView.tsx new file mode 100644 index 00000000..966b2b7d --- /dev/null +++ b/src/views/mod-tools/views/tickets/ModToolsTicketsView.tsx @@ -0,0 +1,16 @@ +import { FC } from 'react'; +import { NitroCardContentView, NitroCardView } from '../../../../layout'; +import { NitroCardSimpleHeaderView } from '../../../../layout/card/simple-header'; +import { ModToolsTicketsViewProps } from './ModToolsTicketsView.types'; + +export const ModToolsTicketsView: FC = props => +{ + return ( + + {} } /> + + + + + ); +} diff --git a/src/views/mod-tools/views/tickets/ModToolsTicketsView.types.ts b/src/views/mod-tools/views/tickets/ModToolsTicketsView.types.ts new file mode 100644 index 00000000..a8713d1f --- /dev/null +++ b/src/views/mod-tools/views/tickets/ModToolsTicketsView.types.ts @@ -0,0 +1,2 @@ +export interface ModToolsTicketsViewProps +{} diff --git a/src/views/mod-tools/views/user/ModToolsUserView.tsx b/src/views/mod-tools/views/user/ModToolsUserView.tsx new file mode 100644 index 00000000..34086081 --- /dev/null +++ b/src/views/mod-tools/views/user/ModToolsUserView.tsx @@ -0,0 +1,16 @@ +import { FC } from 'react'; +import { NitroCardContentView, NitroCardView } from '../../../../layout'; +import { NitroCardSimpleHeaderView } from '../../../../layout/card/simple-header'; +import { ModToolsUserViewProps } from './ModToolsUserView.types'; + +export const ModToolsUserView: FC = props => +{ + return ( + + {} } /> + + + + + ); +} diff --git a/src/views/mod-tools/views/user/ModToolsUserView.types.ts b/src/views/mod-tools/views/user/ModToolsUserView.types.ts new file mode 100644 index 00000000..55b9477c --- /dev/null +++ b/src/views/mod-tools/views/user/ModToolsUserView.types.ts @@ -0,0 +1,2 @@ +export interface ModToolsUserViewProps +{} diff --git a/src/views/room/RoomView.tsx b/src/views/room/RoomView.tsx index 19500aff..6fcf2ee8 100644 --- a/src/views/room/RoomView.tsx +++ b/src/views/room/RoomView.tsx @@ -1,4 +1,4 @@ -import { EventDispatcher, Nitro, RoomEngineEvent, RoomEngineObjectEvent, RoomGeometry, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomVariableEnum, Vector3d } from 'nitro-renderer'; +import { EventDispatcher, Nitro, RoomEngineEvent, RoomEngineObjectEvent, RoomGeometry, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomVariableEnum, Vector3d } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import { CanManipulateFurniture, IsFurnitureSelectionDisabled, ProcessRoomObjectOperation } from '../../api'; @@ -6,7 +6,8 @@ import { DispatchMouseEvent } from '../../api/nitro/room/DispatchMouseEvent'; import { WindowResizeEvent } from '../../api/nitro/room/DispatchResizeEvent'; import { DispatchTouchEvent } from '../../api/nitro/room/DispatchTouchEvent'; import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine'; -import { useRoomEngineEvent } from '../../hooks/events'; +import { ModToolsSelectUserEvent } from '../../events/mod-tools/ModToolsSelectUserEvent'; +import { dispatchUiEvent, useRoomEngineEvent } from '../../hooks/events'; import { RoomContextProvider } from './context/RoomContext'; import { RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent } from './events'; import { IRoomWidgetHandlerManager, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers'; @@ -123,6 +124,16 @@ export const RoomView: FC = props => { case RoomEngineObjectEvent.SELECTED: if(!IsFurnitureSelectionDisabled(event)) updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_SELECTED, objectId, category, event.roomId); + + if(category === RoomObjectCategory.UNIT) + { + const user = roomSession.userDataManager.getUserDataByIndex(objectId); + + if(user && user.type === RoomObjectType.USER) + { + dispatchUiEvent(new ModToolsSelectUserEvent(user.webID, user.name)); + } + } break; case RoomEngineObjectEvent.DESELECTED: updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, objectId, category, event.roomId); diff --git a/src/views/toolbar/ToolbarView.tsx b/src/views/toolbar/ToolbarView.tsx index f58c6327..05bf9446 100644 --- a/src/views/toolbar/ToolbarView.tsx +++ b/src/views/toolbar/ToolbarView.tsx @@ -2,6 +2,7 @@ import { UserInfoEvent } from 'nitro-renderer/src/nitro/communication/messages/i import { UserInfoDataParser } from 'nitro-renderer/src/nitro/communication/messages/parser/user/data/UserInfoDataParser'; import { FC, useCallback, useState } from 'react'; import { AvatarEditorEvent, CatalogEvent, FriendListEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent } from '../../events'; +import { ModToolsEvent } from '../../events/mod-tools/ModToolsEvent'; import { dispatchUiEvent } from '../../hooks/events/ui/ui-event'; import { CreateMessageHook } from '../../hooks/messages/message-event'; import { TransitionAnimation } from '../../layout/transitions/TransitionAnimation'; @@ -51,6 +52,9 @@ export const ToolbarView: FC = props => dispatchUiEvent(new AvatarEditorEvent(AvatarEditorEvent.TOGGLE_EDITOR)); setMeExpanded(false); return; + case ToolbarViewItems.MOD_TOOLS_ITEM: + dispatchUiEvent(new ModToolsEvent(ModToolsEvent.TOGGLE_MOD_TOOLS)); + return; } }, []); @@ -108,6 +112,9 @@ export const ToolbarView: FC = props =>
handleToolbarItemClick(ToolbarViewItems.CAMERA_ITEM) }>
) } +
handleToolbarItemClick(ToolbarViewItems.MOD_TOOLS_ITEM) }> + +
diff --git a/src/views/toolbar/ToolbarView.types.ts b/src/views/toolbar/ToolbarView.types.ts index 6c280e6c..d9ab106a 100644 --- a/src/views/toolbar/ToolbarView.types.ts +++ b/src/views/toolbar/ToolbarView.types.ts @@ -11,4 +11,5 @@ export class ToolbarViewItems public static FRIEND_LIST_ITEM: string = 'TVI_FRIEND_LIST_ITEM'; public static CLOTHING_ITEM: string = 'TVI_CLOTHING_ITEM'; public static CAMERA_ITEM: string = 'TVI_CAMERA_ITEM'; + public static MOD_TOOLS_ITEM: string = 'TVI_MOD_TOOLS_ITEM'; } From 51a9e34199981c7d8d72cafc25f191e16e1c423d Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Mon, 28 Jun 2021 00:47:55 -0300 Subject: [PATCH 03/72] Initial commit --- src/events/achievements/AchievementsEvent.ts | 8 +++ src/events/achievements/index.ts | 1 + src/views/Styles.scss | 1 + .../AchievementsMessageHandler.tsx | 70 +++++++++++++++++++ .../AchievementsMessageHandler.types.ts | 2 + src/views/achievements/AchievementsView.scss | 24 +++++++ src/views/achievements/AchievementsView.tsx | 66 +++++++++++++++++ .../achievements/AchievementsView.types.ts | 2 + .../context/AchievementsContext.tsx | 14 ++++ .../context/AchievementsContext.types.ts | 13 ++++ .../reducers/AchievementsReducer.tsx | 63 +++++++++++++++++ .../achievements/utils/AchievementCategory.ts | 33 +++++++++ .../views/list/AchievementListView.types.ts | 2 + .../views/list/AchievementsListView.tsx | 70 +++++++++++++++++++ src/views/main/MainView.tsx | 2 + src/views/toolbar/ToolbarView.tsx | 5 ++ src/views/toolbar/ToolbarView.types.ts | 1 + src/views/toolbar/me/ToolbarMeView.tsx | 2 +- 18 files changed, 378 insertions(+), 1 deletion(-) create mode 100644 src/events/achievements/AchievementsEvent.ts create mode 100644 src/events/achievements/index.ts create mode 100644 src/views/achievements/AchievementsMessageHandler.tsx create mode 100644 src/views/achievements/AchievementsMessageHandler.types.ts create mode 100644 src/views/achievements/AchievementsView.scss create mode 100644 src/views/achievements/AchievementsView.tsx create mode 100644 src/views/achievements/AchievementsView.types.ts create mode 100644 src/views/achievements/context/AchievementsContext.tsx create mode 100644 src/views/achievements/context/AchievementsContext.types.ts create mode 100644 src/views/achievements/reducers/AchievementsReducer.tsx create mode 100644 src/views/achievements/utils/AchievementCategory.ts create mode 100644 src/views/achievements/views/list/AchievementListView.types.ts create mode 100644 src/views/achievements/views/list/AchievementsListView.tsx diff --git a/src/events/achievements/AchievementsEvent.ts b/src/events/achievements/AchievementsEvent.ts new file mode 100644 index 00000000..79733bae --- /dev/null +++ b/src/events/achievements/AchievementsEvent.ts @@ -0,0 +1,8 @@ +import { NitroEvent } from 'nitro-renderer'; + +export class AchievementsEvent extends NitroEvent +{ + public static SHOW_ACHIEVEMENTS: string = 'AE_SHOW_ACHIEVEMENTS'; + public static HIDE_ACHIEVEMENTS: string = 'AE_HIDE_ACHIEVEMENTS'; + public static TOGGLE_ACHIEVEMENTS: string = 'AE_TOGGLE_ACHIEVEMENTS'; +} diff --git a/src/events/achievements/index.ts b/src/events/achievements/index.ts new file mode 100644 index 00000000..5f03e568 --- /dev/null +++ b/src/events/achievements/index.ts @@ -0,0 +1 @@ +export * from './AchievementsEvent'; diff --git a/src/views/Styles.scss b/src/views/Styles.scss index c6117f4c..cba0a476 100644 --- a/src/views/Styles.scss +++ b/src/views/Styles.scss @@ -14,3 +14,4 @@ @import './room/RoomView'; @import './room-host/RoomHostView'; @import './toolbar/ToolbarView'; +@import './achievements/AchievementsView'; diff --git a/src/views/achievements/AchievementsMessageHandler.tsx b/src/views/achievements/AchievementsMessageHandler.tsx new file mode 100644 index 00000000..d29009f0 --- /dev/null +++ b/src/views/achievements/AchievementsMessageHandler.tsx @@ -0,0 +1,70 @@ +import { AchievementEvent, AchievementsEvent, AchievementsScoreEvent } from 'nitro-renderer'; +import { FC, useCallback } from 'react'; +import { CreateMessageHook } from '../../hooks/messages'; +import { IAchievementsMessageHandlerProps } from './AchievementsMessageHandler.types'; +import { useAchievementsContext } from './context/AchievementsContext'; +import { AchievementsActions } from './reducers/AchievementsReducer'; +import { AchievementCategory } from './utils/AchievementCategory'; + +export const AchievementsMessageHandler: FC = props => +{ + const { achievementsState = null, dispatchAchievementsState = null } = useAchievementsContext(); + + const onAchievementEvent = useCallback((event: AchievementEvent) => + { + const parser = event.getParser(); + + console.log(parser); + + }, [ dispatchAchievementsState ]); + + const onAchievementsEvent = useCallback((event: AchievementsEvent) => + { + const parser = event.getParser(); + + const categories: AchievementCategory[] = []; + + for(const achievement of parser.achievements) + { + const categoryName = achievement.category; + + const existing = categories.find(category => category.name === categoryName); + + if(existing) + { + existing.achievements.push(achievement); + continue; + } + + const category = new AchievementCategory(categoryName); + category.achievements.push(achievement); + categories.push(category); + } + + dispatchAchievementsState({ + type: AchievementsActions.SET_CATEGORIES, + payload: { + categories: categories + } + }); + }, [ dispatchAchievementsState ]); + + const onAchievementsScoreEvent = useCallback((event: AchievementsScoreEvent) => + { + const parser = event.getParser(); + + dispatchAchievementsState({ + type: AchievementsActions.SET_SCORE, + payload: { + score: parser.score + } + }); + + }, [ dispatchAchievementsState ]); + + CreateMessageHook(AchievementEvent, onAchievementEvent); + CreateMessageHook(AchievementsEvent, onAchievementsEvent); + CreateMessageHook(AchievementsScoreEvent, onAchievementsScoreEvent); + + return null; +}; diff --git a/src/views/achievements/AchievementsMessageHandler.types.ts b/src/views/achievements/AchievementsMessageHandler.types.ts new file mode 100644 index 00000000..3de1326b --- /dev/null +++ b/src/views/achievements/AchievementsMessageHandler.types.ts @@ -0,0 +1,2 @@ +export interface IAchievementsMessageHandlerProps +{} diff --git a/src/views/achievements/AchievementsView.scss b/src/views/achievements/AchievementsView.scss new file mode 100644 index 00000000..c3901243 --- /dev/null +++ b/src/views/achievements/AchievementsView.scss @@ -0,0 +1,24 @@ +.nitro-achievements { + width: 600px; + + .score { + border-color: $grid-border-color !important; + background-color: $grid-bg-color; + } + + .category { + border-color: $grid-border-color !important; + background-color: $grid-bg-color; + cursor: pointer; + + &.active { + border-color: $grid-active-border-color !important; + background-color: $grid-active-bg-color; + } + + .category-score { + margin-top: 43.5px; + } + } + +} diff --git a/src/views/achievements/AchievementsView.tsx b/src/views/achievements/AchievementsView.tsx new file mode 100644 index 00000000..7741941d --- /dev/null +++ b/src/views/achievements/AchievementsView.tsx @@ -0,0 +1,66 @@ +import { FC, useCallback, useEffect, useReducer, useState } from 'react'; +import { AchievementsEvent } from '../../events/achievements'; +import { useUiEvent } from '../../hooks/events'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../layout'; +import { LocalizeText } from '../../utils/LocalizeText'; +import { AchievementsMessageHandler } from './AchievementsMessageHandler'; +import { AchievementsViewProps } from './AchievementsView.types'; +import { AchievementsContextProvider } from './context/AchievementsContext'; +import { AchievementsReducer, initialAchievements } from './reducers/AchievementsReducer'; +import { AchievementsListView } from './views/list/AchievementsListView'; + +export const AchievementsView: FC = props => +{ + const [ isVisible, setIsVisible ] = useState(false); + const [ achievementsState, dispatchAchievementsState ] = useReducer(AchievementsReducer, initialAchievements); + const { categories = null, score = null, selectedCategoryName = null } = achievementsState; + + const onAchievementsEvent = useCallback((event: AchievementsEvent) => + { + switch(event.type) + { + case AchievementsEvent.SHOW_ACHIEVEMENTS: + setIsVisible(true); + return; + case AchievementsEvent.HIDE_ACHIEVEMENTS: + setIsVisible(false); + return; + case AchievementsEvent.TOGGLE_ACHIEVEMENTS: + setIsVisible(value => !value); + return; + } + }, []); + + useUiEvent(AchievementsEvent.SHOW_ACHIEVEMENTS, onAchievementsEvent); + useUiEvent(AchievementsEvent.HIDE_ACHIEVEMENTS, onAchievementsEvent); + useUiEvent(AchievementsEvent.TOGGLE_ACHIEVEMENTS, onAchievementsEvent); + + useEffect(() => + { + if(!isVisible) return; + + }, [ isVisible ]); + + return ( + + + { isVisible && + + setIsVisible(false) } /> + +
+
+ +
+ { LocalizeText('achievements.categories.score', ['score'], [score.toString()]) } +
+
+
+ +
+
+
+
} +
+ ); +}; diff --git a/src/views/achievements/AchievementsView.types.ts b/src/views/achievements/AchievementsView.types.ts new file mode 100644 index 00000000..821d5c20 --- /dev/null +++ b/src/views/achievements/AchievementsView.types.ts @@ -0,0 +1,2 @@ +export class AchievementsViewProps +{} diff --git a/src/views/achievements/context/AchievementsContext.tsx b/src/views/achievements/context/AchievementsContext.tsx new file mode 100644 index 00000000..c1162f4d --- /dev/null +++ b/src/views/achievements/context/AchievementsContext.tsx @@ -0,0 +1,14 @@ +import { createContext, FC, useContext } from 'react'; +import { AchievementsContextProps, IAchievementsContext } from './AchievementsContext.types'; + +const AchievementsContext = createContext({ + achievementsState: null, + dispatchAchievementsState: null +}); + +export const AchievementsContextProvider: FC = props => +{ + return { props.children } +} + +export const useAchievementsContext = () => useContext(AchievementsContext); diff --git a/src/views/achievements/context/AchievementsContext.types.ts b/src/views/achievements/context/AchievementsContext.types.ts new file mode 100644 index 00000000..320cd787 --- /dev/null +++ b/src/views/achievements/context/AchievementsContext.types.ts @@ -0,0 +1,13 @@ +import { Dispatch, ProviderProps } from 'react'; +import { IAchievementsAction, IAchievementsState } from '../reducers/AchievementsReducer'; + +export interface IAchievementsContext +{ + achievementsState: IAchievementsState; + dispatchAchievementsState: Dispatch; +} + +export interface AchievementsContextProps extends ProviderProps +{ + +} diff --git a/src/views/achievements/reducers/AchievementsReducer.tsx b/src/views/achievements/reducers/AchievementsReducer.tsx new file mode 100644 index 00000000..4b4ddbf1 --- /dev/null +++ b/src/views/achievements/reducers/AchievementsReducer.tsx @@ -0,0 +1,63 @@ +import { Reducer } from 'react'; +import { AchievementCategory } from '../utils/AchievementCategory'; + +export interface IAchievementsState +{ + categories: AchievementCategory[], + score: number, + selectedCategoryName: string +} + +export interface IAchievementsAction +{ + type: string; + payload: { + categories?: AchievementCategory[], + score?: number, + selectedCategoryName?: string + } +} + +export class AchievementsActions +{ + public static SET_CATEGORIES: string = 'AA_SET_CATEGORIES'; + public static SET_SCORE: string = 'AA_SET_SCORE'; + public static SELECT_CATEGORY: string = 'AA_SELECT_CATEGORY'; +} + +export const initialAchievements: IAchievementsState = { + categories: null, + score: null, + selectedCategoryName: null +} + +export const AchievementsReducer: Reducer = (state, action) => +{ + switch(action.type) + { + case AchievementsActions.SET_CATEGORIES: { + const categories = (action.payload.categories || state.categories || null); + + let selectedCategoryName = null; + + if(categories.length > 0) + { + selectedCategoryName = categories[0].name; + } + + return { ...state, categories, selectedCategoryName }; + } + case AchievementsActions.SET_SCORE: { + const score = (action.payload.score || state.score || null); + + return { ...state, score }; + } + case AchievementsActions.SELECT_CATEGORY: { + const selectedCategoryName = (action.payload.selectedCategoryName || state.selectedCategoryName || null); + + return { ...state, selectedCategoryName }; + } + default: + return state; + } +} diff --git a/src/views/achievements/utils/AchievementCategory.ts b/src/views/achievements/utils/AchievementCategory.ts new file mode 100644 index 00000000..bcf4f7f6 --- /dev/null +++ b/src/views/achievements/utils/AchievementCategory.ts @@ -0,0 +1,33 @@ +import { AchievementData } from 'nitro-renderer'; + +export class AchievementCategory +{ + private _name: string; + private _achievements: AchievementData[]; + + constructor(name: string) + { + this._name = name; + this._achievements = []; + } + + public get name(): string + { + return this._name; + } + + public set name(name: string) + { + this._name = name; + } + + public get achievements(): AchievementData[] + { + return this._achievements; + } + + public set achievements(achievements: AchievementData[]) + { + this._achievements = achievements; + } +} diff --git a/src/views/achievements/views/list/AchievementListView.types.ts b/src/views/achievements/views/list/AchievementListView.types.ts new file mode 100644 index 00000000..047bd157 --- /dev/null +++ b/src/views/achievements/views/list/AchievementListView.types.ts @@ -0,0 +1,2 @@ +export class AchievementListViewProps +{} diff --git a/src/views/achievements/views/list/AchievementsListView.tsx b/src/views/achievements/views/list/AchievementsListView.tsx new file mode 100644 index 00000000..a2615ab8 --- /dev/null +++ b/src/views/achievements/views/list/AchievementsListView.tsx @@ -0,0 +1,70 @@ +import classNames from 'classnames'; +import { FC, useCallback } from 'react'; +import { GetConfiguration } from '../../../../api'; +import { useAchievementsContext } from '../../context/AchievementsContext'; +import { AchievementsActions } from '../../reducers/AchievementsReducer'; +import { AchievementCategory } from '../../utils/AchievementCategory'; +import { AchievementListViewProps } from './AchievementListView.types'; + +export const AchievementsListView: FC = props => +{ + const achievementsContext = useAchievementsContext(); + + const { achievementsState = null, dispatchAchievementsState = null } = achievementsContext; + const { categories = null, selectedCategoryName = null } = achievementsState; + + const getCategoryImage = useCallback((category: AchievementCategory) => + { + let level = 0; + + for(const achievement of category.achievements) + { + level = (level + ((achievement.finalLevel) ? achievement.level : (achievement.level - 1))); + } + + const isActive = ((level > 0) ? 'active' : 'inactive'); + + return GetConfiguration('achievements.images.url', GetConfiguration('achievements.images.url') + `quests/achcategory_${category.name}_${isActive}.png`).replace('%image%',`achcategory_${category.name}_${isActive}`); + }, []); + + const getCategoryProgress = useCallback((category: AchievementCategory) => + { + let completed = 0; + let total = 0; + + for(const achievement of category.achievements) + { + if(!achievement) continue; + + if(achievement.finalLevel) completed = completed + 1 + achievement.level; + + total = (total + achievement.scoreLimit); + } + + return (completed + ' / ' + total); + }, []); + + const selectCategory = useCallback((name: string) => + { + dispatchAchievementsState({ + type: AchievementsActions.SELECT_CATEGORY, + payload: { + selectedCategoryName: name + } + }); + }, [ dispatchAchievementsState ]); + + return ( +
+ { categories && categories.map((category, index) => + { + return
+
selectCategory(category.name)}> + +
{ getCategoryProgress(category) }
+
+
+ }) } +
+ ); +}; diff --git a/src/views/main/MainView.tsx b/src/views/main/MainView.tsx index 3d06d83d..8b8a2346 100644 --- a/src/views/main/MainView.tsx +++ b/src/views/main/MainView.tsx @@ -1,6 +1,7 @@ import { Nitro, RoomSessionEvent } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; +import { AchievementsView } from '../achievements/AchievementsView'; import { AvatarEditorView } from '../avatar-editor/AvatarEditorView'; import { CatalogView } from '../catalog/CatalogView'; import { FriendListView } from '../friend-list/FriendListView'; @@ -47,6 +48,7 @@ export const MainView: FC = props => + diff --git a/src/views/toolbar/ToolbarView.tsx b/src/views/toolbar/ToolbarView.tsx index ac6e325d..cb932c9e 100644 --- a/src/views/toolbar/ToolbarView.tsx +++ b/src/views/toolbar/ToolbarView.tsx @@ -2,6 +2,7 @@ import { UserInfoEvent } from 'nitro-renderer/src/nitro/communication/messages/i import { UserInfoDataParser } from 'nitro-renderer/src/nitro/communication/messages/parser/user/data/UserInfoDataParser'; import { FC, useCallback, useState } from 'react'; import { AvatarEditorEvent, CatalogEvent, FriendListEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent } from '../../events'; +import { AchievementsEvent } from '../../events/achievements'; import { dispatchUiEvent } from '../../hooks/events/ui/ui-event'; import { CreateMessageHook } from '../../hooks/messages/message-event'; import { TransitionAnimation } from '../../layout/transitions/TransitionAnimation'; @@ -51,6 +52,10 @@ export const ToolbarView: FC = props => dispatchUiEvent(new AvatarEditorEvent(AvatarEditorEvent.TOGGLE_EDITOR)); setMeExpanded(false); return; + case ToolbarViewItems.ACHIEVEMENTS_ITEM: + dispatchUiEvent(new AchievementsEvent(AchievementsEvent.TOGGLE_ACHIEVEMENTS)); + setMeExpanded(false); + return; } }, []); diff --git a/src/views/toolbar/ToolbarView.types.ts b/src/views/toolbar/ToolbarView.types.ts index 6c280e6c..c8ec4010 100644 --- a/src/views/toolbar/ToolbarView.types.ts +++ b/src/views/toolbar/ToolbarView.types.ts @@ -11,4 +11,5 @@ export class ToolbarViewItems public static FRIEND_LIST_ITEM: string = 'TVI_FRIEND_LIST_ITEM'; public static CLOTHING_ITEM: string = 'TVI_CLOTHING_ITEM'; public static CAMERA_ITEM: string = 'TVI_CAMERA_ITEM'; + public static ACHIEVEMENTS_ITEM: string = 'TVI_ACHIEVEMENTS_ITEM'; } diff --git a/src/views/toolbar/me/ToolbarMeView.tsx b/src/views/toolbar/me/ToolbarMeView.tsx index 31cc71ab..e77e7489 100644 --- a/src/views/toolbar/me/ToolbarMeView.tsx +++ b/src/views/toolbar/me/ToolbarMeView.tsx @@ -38,7 +38,7 @@ export const ToolbarMeView: FC = props =>
-
+
handleToolbarItemClick(ToolbarViewItems.ACHIEVEMENTS_ITEM) }>
From 061424d26c4bb59e5bc0efb4dd305bd2a0c2a7f2 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Mon, 28 Jun 2021 14:13:33 -0300 Subject: [PATCH 04/72] Updates --- src/views/achievements/AchievementsView.scss | 30 ++++++- src/views/achievements/AchievementsView.tsx | 5 +- .../reducers/AchievementsReducer.tsx | 29 ++++++- .../category/AchievementCategoryView.tsx | 82 +++++++++++++++++++ .../category/AchievementCategoryView.types.ts | 2 + 5 files changed, 141 insertions(+), 7 deletions(-) create mode 100644 src/views/achievements/views/category/AchievementCategoryView.tsx create mode 100644 src/views/achievements/views/category/AchievementCategoryView.types.ts diff --git a/src/views/achievements/AchievementsView.scss b/src/views/achievements/AchievementsView.scss index c3901243..902968b8 100644 --- a/src/views/achievements/AchievementsView.scss +++ b/src/views/achievements/AchievementsView.scss @@ -1,5 +1,6 @@ .nitro-achievements { - width: 600px; + width: 650px; + height: 376px; .score { border-color: $grid-border-color !important; @@ -20,5 +21,32 @@ margin-top: 43.5px; } } + + .achievements { + height: 230px; + overflow-y: auto; + overflow-x: hidden; + + .achievement { + border-color: $grid-border-color !important; + background-color: $grid-bg-color; + cursor: pointer; + + &.active { + border-color: $grid-active-border-color !important; + background-color: $grid-active-bg-color; + } + &.gray { + div { + filter: grayscale(1); + opacity: .5; + } + } + + div { + height: 40px; + } + } + } } diff --git a/src/views/achievements/AchievementsView.tsx b/src/views/achievements/AchievementsView.tsx index 7741941d..76981157 100644 --- a/src/views/achievements/AchievementsView.tsx +++ b/src/views/achievements/AchievementsView.tsx @@ -7,13 +7,14 @@ import { AchievementsMessageHandler } from './AchievementsMessageHandler'; import { AchievementsViewProps } from './AchievementsView.types'; import { AchievementsContextProvider } from './context/AchievementsContext'; import { AchievementsReducer, initialAchievements } from './reducers/AchievementsReducer'; +import { AchievementCategoryView } from './views/category/AchievementCategoryView'; import { AchievementsListView } from './views/list/AchievementsListView'; export const AchievementsView: FC = props => { const [ isVisible, setIsVisible ] = useState(false); const [ achievementsState, dispatchAchievementsState ] = useReducer(AchievementsReducer, initialAchievements); - const { categories = null, score = null, selectedCategoryName = null } = achievementsState; + const { score = null } = achievementsState; const onAchievementsEvent = useCallback((event: AchievementsEvent) => { @@ -56,7 +57,7 @@ export const AchievementsView: FC = props =>
- +
diff --git a/src/views/achievements/reducers/AchievementsReducer.tsx b/src/views/achievements/reducers/AchievementsReducer.tsx index 4b4ddbf1..1224a86b 100644 --- a/src/views/achievements/reducers/AchievementsReducer.tsx +++ b/src/views/achievements/reducers/AchievementsReducer.tsx @@ -5,7 +5,8 @@ export interface IAchievementsState { categories: AchievementCategory[], score: number, - selectedCategoryName: string + selectedCategoryName: string, + selectedAchievementId: number } export interface IAchievementsAction @@ -14,7 +15,8 @@ export interface IAchievementsAction payload: { categories?: AchievementCategory[], score?: number, - selectedCategoryName?: string + selectedCategoryName?: string, + selectedAchievementId?: number } } @@ -23,12 +25,14 @@ export class AchievementsActions public static SET_CATEGORIES: string = 'AA_SET_CATEGORIES'; public static SET_SCORE: string = 'AA_SET_SCORE'; public static SELECT_CATEGORY: string = 'AA_SELECT_CATEGORY'; + public static SELECT_ACHIEVEMENT: string = 'AA_SELECT_ACHIEVEMENT'; } export const initialAchievements: IAchievementsState = { categories: null, score: null, - selectedCategoryName: null + selectedCategoryName: null, + selectedAchievementId: null } export const AchievementsReducer: Reducer = (state, action) => @@ -55,7 +59,24 @@ export const AchievementsReducer: Reducer category.name === selectedCategoryName); + + if(category && category.achievements.length > 0) + { + selectedAchievementId = category.achievements[0].achievementId; + } + } + + return { ...state, selectedCategoryName, selectedAchievementId }; + } + case AchievementsActions.SELECT_ACHIEVEMENT: { + const selectedAchievementId = (action.payload.selectedAchievementId || state.selectedAchievementId || null); + + return { ...state, selectedAchievementId }; } default: return state; diff --git a/src/views/achievements/views/category/AchievementCategoryView.tsx b/src/views/achievements/views/category/AchievementCategoryView.tsx new file mode 100644 index 00000000..91ba95e0 --- /dev/null +++ b/src/views/achievements/views/category/AchievementCategoryView.tsx @@ -0,0 +1,82 @@ +import classNames from 'classnames'; +import { AchievementData } from 'nitro-renderer'; +import { FC, useCallback } from 'react'; +import { LocalizeText } from '../../../../utils/LocalizeText'; +import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView'; +import { useAchievementsContext } from '../../context/AchievementsContext'; +import { AchievementsActions } from '../../reducers/AchievementsReducer'; +import { AchievementCategoryViewProps } from './AchievementCategoryView.types'; + +export const AchievementCategoryView: FC = props => +{ + const achievementsContext = useAchievementsContext(); + + const { achievementsState = null, dispatchAchievementsState = null } = achievementsContext; + const { categories = null, selectedCategoryName = null, selectedAchievementId = null } = achievementsState; + + const getSelectedCategory = useCallback(() => + { + return categories.find(category => category.name === selectedCategoryName); + }, [ categories, selectedCategoryName ]); + + const getAchievementImage = useCallback((achievement: AchievementData) => + { + if(!achievement) return null; + + let badgeId = achievement.badgeId; + + if(achievement.levelCount > 1) + { + badgeId = badgeId.replace(/[0-9]/g, ''); + badgeId = (badgeId + (((achievement.level - 1) > 0) ? (achievement.level - 1) : achievement.level)); + } + + return badgeId; + }, []); + + const getSelectedAchievement = useCallback(() => + { + if(!getSelectedCategory()) return null; + + return getSelectedCategory().achievements.find(achievement => achievement.achievementId === selectedAchievementId); + }, [ getSelectedCategory, selectedAchievementId ]); + + const selectAchievement = useCallback((id: number) => + { + dispatchAchievementsState({ + type: AchievementsActions.SELECT_ACHIEVEMENT, + payload: { + selectedAchievementId: id + } + }); + }, [ dispatchAchievementsState ]); + + + return ( +
+
+
{ LocalizeText('quests.' + selectedCategoryName + '.name') }
+
IMAGE
+
+
+
+ +
+
+
+
+ { getSelectedCategory().achievements.map((achievement, index) => + { + return ( +
+
selectAchievement(achievement.achievementId)}> + +
+
+ ) + }) } +
+
+
+ ); +} diff --git a/src/views/achievements/views/category/AchievementCategoryView.types.ts b/src/views/achievements/views/category/AchievementCategoryView.types.ts new file mode 100644 index 00000000..d6c378d4 --- /dev/null +++ b/src/views/achievements/views/category/AchievementCategoryView.types.ts @@ -0,0 +1,2 @@ +export class AchievementCategoryViewProps +{} From ff206386f1de534152a69b55a9b790a869b8b8df Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Wed, 30 Jun 2021 14:08:24 -0300 Subject: [PATCH 05/72] Room Tools --- src/views/room/RoomView.tsx | 18 +++++- .../handlers/RoomWidgetRoomToolsHandler.ts | 33 +++++++++++ .../messages/RoomWidgetZoomToggleMessage.ts | 18 ++++++ src/views/room/messages/index.ts | 1 + src/views/room/widgets/RoomWidgets.scss | 1 + src/views/room/widgets/RoomWidgetsView.tsx | 2 + .../room-tools/RoomToolsWidgetView.scss | 15 +++++ .../room-tools/RoomToolsWidgetView.tsx | 58 +++++++++++++++++++ .../room-tools/RoomToolsWidgetView.types.ts | 4 ++ 9 files changed, 148 insertions(+), 2 deletions(-) create mode 100644 src/views/room/handlers/RoomWidgetRoomToolsHandler.ts create mode 100644 src/views/room/messages/RoomWidgetZoomToggleMessage.ts create mode 100644 src/views/room/widgets/room-tools/RoomToolsWidgetView.scss create mode 100644 src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx create mode 100644 src/views/room/widgets/room-tools/RoomToolsWidgetView.types.ts diff --git a/src/views/room/RoomView.tsx b/src/views/room/RoomView.tsx index f0afb252..5f1cdf3b 100644 --- a/src/views/room/RoomView.tsx +++ b/src/views/room/RoomView.tsx @@ -1,4 +1,4 @@ -import { EventDispatcher, Nitro, RoomEngineEvent, RoomEngineObjectEvent, RoomGeometry, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomVariableEnum, Vector3d } from 'nitro-renderer'; +import { EventDispatcher, Nitro, RoomEngineEvent, RoomEngineObjectEvent, RoomGeometry, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomVariableEnum, RoomZoomEvent, Vector3d } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; import { CanManipulateFurniture, IsFurnitureSelectionDisabled, ProcessRoomObjectOperation } from '../../api'; @@ -10,6 +10,7 @@ import { useRoomEngineEvent } from '../../hooks/events'; import { RoomContextProvider } from './context/RoomContext'; import { RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent } from './events'; import { IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers'; +import { RoomWidgetRoomToolsHandler } from './handlers/RoomWidgetRoomToolsHandler'; import { RoomViewProps } from './RoomView.types'; import { RoomWidgetsView } from './widgets/RoomWidgetsView'; @@ -35,6 +36,7 @@ export const RoomView: FC = props => widgetHandlerManager.registerHandler(new RoomWidgetAvatarInfoHandler()); widgetHandlerManager.registerHandler(new RoomWidgetInfostandHandler()); + widgetHandlerManager.registerHandler(new RoomWidgetRoomToolsHandler()); setWidgetHandler(widgetHandlerManager); @@ -96,7 +98,7 @@ export const RoomView: FC = props => const onRoomEngineEvent = useCallback((event: RoomEngineEvent) => { if(!widgetHandler || RoomId.isRoomPreviewerId(event.roomId)) return; - + switch(event.type) { case RoomEngineEvent.NORMAL_MODE: @@ -105,11 +107,23 @@ export const RoomView: FC = props => case RoomEngineEvent.GAME_MODE: widgetHandler.eventDispatcher.dispatchEvent(new RoomWidgetRoomEngineUpdateEvent(RoomWidgetRoomEngineUpdateEvent.GAME_MODE, event.roomId)); return; + case RoomZoomEvent.ROOM_ZOOM: + const zoomEvent = (event as RoomZoomEvent); + + let zoomLevel = ((zoomEvent.level < 1) ? 0.5 : (1 << (Math.floor(zoomEvent.level) - 1))); + + if(zoomEvent.forceFlip || zoomEvent.asDelta) zoomLevel = zoomEvent.level; + + const canvasId = 1; + + GetRoomEngine().setRoomInstanceRenderingCanvasScale(GetRoomEngine().activeRoomId, canvasId, zoomLevel, null, null, false, zoomEvent.asDelta); + return; } }, [ widgetHandler ]); useRoomEngineEvent(RoomEngineEvent.NORMAL_MODE, onRoomEngineEvent); useRoomEngineEvent(RoomEngineEvent.GAME_MODE, onRoomEngineEvent); + useRoomEngineEvent(RoomZoomEvent.ROOM_ZOOM, onRoomEngineEvent); const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) => { diff --git a/src/views/room/handlers/RoomWidgetRoomToolsHandler.ts b/src/views/room/handlers/RoomWidgetRoomToolsHandler.ts new file mode 100644 index 00000000..9f5d8ccc --- /dev/null +++ b/src/views/room/handlers/RoomWidgetRoomToolsHandler.ts @@ -0,0 +1,33 @@ +import { NitroEvent, RoomZoomEvent } from 'nitro-renderer'; +import { GetRoomEngine } from '../../../api'; +import { RoomWidgetUpdateEvent } from '../events'; +import { RoomWidgetMessage, RoomWidgetZoomToggleMessage } from '../messages'; +import { RoomWidgetHandler } from './RoomWidgetHandler'; + +export class RoomWidgetRoomToolsHandler extends RoomWidgetHandler +{ + public processEvent(event: NitroEvent): void + {} + + public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent + { + if(message instanceof RoomWidgetZoomToggleMessage) + { + GetRoomEngine().events.dispatchEvent(new RoomZoomEvent(GetRoomEngine().activeRoomId, message.zoomedIn ? 0 : 1, false)); + } + + return null; + } + + public get eventTypes(): string[] + { + return []; + } + + public get messageTypes(): string[] + { + return [ + RoomWidgetZoomToggleMessage.ZOOM_TOGGLE + ]; + } +} diff --git a/src/views/room/messages/RoomWidgetZoomToggleMessage.ts b/src/views/room/messages/RoomWidgetZoomToggleMessage.ts new file mode 100644 index 00000000..dae47e5b --- /dev/null +++ b/src/views/room/messages/RoomWidgetZoomToggleMessage.ts @@ -0,0 +1,18 @@ +import { RoomWidgetMessage } from '.'; + +export class RoomWidgetZoomToggleMessage extends RoomWidgetMessage +{ + public static ZOOM_TOGGLE: string = 'RWZTM_ZOOM_TOGGLE'; + private _zoomedIn: boolean; + + constructor(zoomedIn: boolean) + { + super(RoomWidgetZoomToggleMessage.ZOOM_TOGGLE); + this._zoomedIn = zoomedIn; + } + + public get zoomedIn(): boolean + { + return this._zoomedIn; + } +} diff --git a/src/views/room/messages/index.ts b/src/views/room/messages/index.ts index 320b77c2..c256d9d4 100644 --- a/src/views/room/messages/index.ts +++ b/src/views/room/messages/index.ts @@ -6,3 +6,4 @@ export * from './RoomWidgetFurniActionMessage'; export * from './RoomWidgetMessage'; export * from './RoomWidgetRoomObjectMessage'; export * from './RoomWidgetUserActionMessage'; +export * from './RoomWidgetZoomToggleMessage'; diff --git a/src/views/room/widgets/RoomWidgets.scss b/src/views/room/widgets/RoomWidgets.scss index 982c8ade..6f4cfbb9 100644 --- a/src/views/room/widgets/RoomWidgets.scss +++ b/src/views/room/widgets/RoomWidgets.scss @@ -5,3 +5,4 @@ @import './furniture/FurnitureWidgets'; @import './infostand/InfoStandWidgetView'; @import './object-location/ObjectLocationView'; +@import './room-tools/RoomToolsWidgetView'; diff --git a/src/views/room/widgets/RoomWidgetsView.tsx b/src/views/room/widgets/RoomWidgetsView.tsx index e0cd7f19..c95aaaa1 100644 --- a/src/views/room/widgets/RoomWidgetsView.tsx +++ b/src/views/room/widgets/RoomWidgetsView.tsx @@ -9,6 +9,7 @@ import { ChatInputView } from './chat-input/ChatInputView'; import { ChatWidgetView } from './chat/ChatWidgetView'; import { FurnitureWidgetsView } from './furniture/FurnitureWidgetsView'; import { InfoStandWidgetView } from './infostand/InfoStandWidgetView'; +import { RoomToolsWidgetView } from './room-tools/RoomToolsWidgetView'; import { RoomWidgetViewProps } from './RoomWidgets.types'; export const RoomWidgetsView: FC = props => @@ -108,6 +109,7 @@ export const RoomWidgetsView: FC = props => + ); } diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss b/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss new file mode 100644 index 00000000..1f15d7c7 --- /dev/null +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss @@ -0,0 +1,15 @@ +.nitro-room-tools { + position: fixed; + bottom: 125px; + left: -133px; + background: rgba(20, 20, 20, .95); + border: 1px solid #101010; + box-shadow: inset 0px 2px rgba(255, 255, 255, .1), inset -2px -2px rgba(255, 255, 255, .1); + border-top-right-radius: $border-radius; + border-bottom-right-radius: $border-radius; + transition: all .2s ease; + + &.open { + left: 0px; + } +} diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx new file mode 100644 index 00000000..b3c32b35 --- /dev/null +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx @@ -0,0 +1,58 @@ +import classNames from 'classnames'; +import { FC, useCallback, useState } from 'react'; +import { LocalizeText } from '../../../../utils/LocalizeText'; +import { useRoomContext } from '../../context/RoomContext'; +import { RoomWidgetZoomToggleMessage } from '../../messages'; +import { RoomToolsWidgetViewProps } from './RoomToolsWidgetView.types'; + +export const RoomToolsWidgetView: FC = props => +{ + const { widgetHandler = null } = useRoomContext(); + + const [ isExpended, setIsExpanded ] = useState(false); + const [ isZoomedIn, setIsZoomedIn ] = useState(false); + + const handleToolClick = useCallback((action: string) => + { + switch(action) + { + case 'settings': + return; + case 'zoom': + widgetHandler.processWidgetMessage(new RoomWidgetZoomToggleMessage(!isZoomedIn)); + setIsZoomedIn(value => !value); + return; + case 'chat_history': + return; + case 'like_room': + return; + case 'room_link': + return; + } + }, [ isZoomedIn, widgetHandler ]); + + return ( +
+
+
handleToolClick('settings') }> + { LocalizeText('room.settings.button.text') } +
+
handleToolClick('zoom') }> + { LocalizeText('room.zoom.button.text') } +
+
handleToolClick('chat_history') }> + { LocalizeText('room.chathistory.button.text') } +
+
handleToolClick('like_room') }> + { LocalizeText('room.like.button.text') } +
+
handleToolClick('room_link') }> + { LocalizeText('navigator.embed.caption') } +
+
+
setIsExpanded(value => !value)}> + +
+
+ ); +}; diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.types.ts b/src/views/room/widgets/room-tools/RoomToolsWidgetView.types.ts new file mode 100644 index 00000000..f539ea58 --- /dev/null +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.types.ts @@ -0,0 +1,4 @@ +import { RoomWidgetProps } from '../RoomWidgets.types'; + +export class RoomToolsWidgetViewProps implements RoomWidgetProps +{} From 226c280fdabd175bf0261c57dd156884126ec847 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Wed, 30 Jun 2021 14:13:29 -0300 Subject: [PATCH 06/72] Updates --- .../widgets/room-tools/RoomToolsWidgetView.scss | 16 +++++++++++++--- .../widgets/room-tools/RoomToolsWidgetView.tsx | 12 ++++++------ 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss b/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss index 1f15d7c7..088ab7c2 100644 --- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss @@ -2,9 +2,8 @@ position: fixed; bottom: 125px; left: -133px; - background: rgba(20, 20, 20, .95); - border: 1px solid #101010; - box-shadow: inset 0px 2px rgba(255, 255, 255, .1), inset -2px -2px rgba(255, 255, 255, .1); + background: rgba($dark,.95); + box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4); border-top-right-radius: $border-radius; border-bottom-right-radius: $border-radius; transition: all .2s ease; @@ -12,4 +11,15 @@ &.open { left: 0px; } + + .list-group-item { + background: transparent; + padding: 3px 0px; + color: $white; + border-color: rgba($black, 0.3); + + &:last-child { + border-bottom: none; + } + } } diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx index b3c32b35..d3fd1fee 100644 --- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx @@ -33,20 +33,20 @@ export const RoomToolsWidgetView: FC = props => return (
-
-
handleToolClick('settings') }> +
+
handleToolClick('settings') }> { LocalizeText('room.settings.button.text') }
-
handleToolClick('zoom') }> +
handleToolClick('zoom') }> { LocalizeText('room.zoom.button.text') }
-
handleToolClick('chat_history') }> +
handleToolClick('chat_history') }> { LocalizeText('room.chathistory.button.text') }
-
handleToolClick('like_room') }> +
handleToolClick('like_room') }> { LocalizeText('room.like.button.text') }
-
handleToolClick('room_link') }> +
handleToolClick('room_link') }> { LocalizeText('navigator.embed.caption') }
From 876ef7ac1fa7b3d43dd2b5f90170251e8aa4062c Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Wed, 30 Jun 2021 14:21:50 -0300 Subject: [PATCH 07/72] Updates --- .../room/widgets/room-tools/RoomToolsWidgetView.scss | 10 ++++++++++ .../room/widgets/room-tools/RoomToolsWidgetView.tsx | 12 ++++++------ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss b/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss index 088ab7c2..7f313a8c 100644 --- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss @@ -17,9 +17,19 @@ padding: 3px 0px; color: $white; border-color: rgba($black, 0.3); + cursor: pointer; + + &:hover { + text-decoration: underline; + } + + &:first-child { + padding-top: 8px; + } &:last-child { border-bottom: none; + padding-bottom: 8px; } } } diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx index d3fd1fee..fb800bfe 100644 --- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx @@ -32,21 +32,21 @@ export const RoomToolsWidgetView: FC = props => }, [ isZoomedIn, widgetHandler ]); return ( -
+
-
handleToolClick('settings') }> +
handleToolClick('settings') }> { LocalizeText('room.settings.button.text') }
-
handleToolClick('zoom') }> +
handleToolClick('zoom') }> { LocalizeText('room.zoom.button.text') }
-
handleToolClick('chat_history') }> +
handleToolClick('chat_history') }> { LocalizeText('room.chathistory.button.text') }
-
handleToolClick('like_room') }> +
handleToolClick('like_room') }> { LocalizeText('room.like.button.text') }
-
handleToolClick('room_link') }> +
handleToolClick('room_link') }> { LocalizeText('navigator.embed.caption') }
From ce613166cac3f1f4a9b2231630c18ba2f4a491e2 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Wed, 30 Jun 2021 14:29:07 -0300 Subject: [PATCH 08/72] Room Like button --- .../room/widgets/room-tools/RoomToolsWidgetView.scss | 4 ++++ .../room/widgets/room-tools/RoomToolsWidgetView.tsx | 11 +++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss b/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss index 7f313a8c..33313ed6 100644 --- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.scss @@ -31,5 +31,9 @@ border-bottom: none; padding-bottom: 8px; } + + &.disabled { + opacity: .5; + } } } diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx index fb800bfe..0ce23306 100644 --- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx @@ -1,5 +1,7 @@ import classNames from 'classnames'; +import { RoomLikeRoomComposer } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; +import { SendMessageHook } from '../../../../hooks/messages'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { useRoomContext } from '../../context/RoomContext'; import { RoomWidgetZoomToggleMessage } from '../../messages'; @@ -11,6 +13,7 @@ export const RoomToolsWidgetView: FC = props => const [ isExpended, setIsExpanded ] = useState(false); const [ isZoomedIn, setIsZoomedIn ] = useState(false); + const [ liked, setLiked ] = useState(false); const handleToolClick = useCallback((action: string) => { @@ -25,11 +28,15 @@ export const RoomToolsWidgetView: FC = props => case 'chat_history': return; case 'like_room': + if(liked) return; + + SendMessageHook(new RoomLikeRoomComposer(1)); + setLiked(true); return; case 'room_link': return; } - }, [ isZoomedIn, widgetHandler ]); + }, [ isZoomedIn, liked, widgetHandler ]); return (
@@ -43,7 +50,7 @@ export const RoomToolsWidgetView: FC = props =>
handleToolClick('chat_history') }> { LocalizeText('room.chathistory.button.text') }
-
handleToolClick('like_room') }> +
handleToolClick('like_room') }> { LocalizeText('room.like.button.text') }
handleToolClick('room_link') }> From efa0994d3038e52380cc5173418705225a8154d3 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Fri, 2 Jul 2021 01:37:31 -0300 Subject: [PATCH 09/72] updates --- public/configuration.json | 2 +- src/assets/images/icons/arrows.png | Bin 0 -> 222 bytes src/assets/images/icons/camera-small.png | Bin 0 -> 296 bytes src/assets/images/icons/house-small.png | Bin 0 -> 361 bytes .../navigator/thumbnail_placeholder.png | Bin 3313 -> 1801 bytes src/assets/styles/icons.scss | 18 +++ src/events/navigator/NavigatorEvent.ts | 2 + .../navigator/NavigatorMessageHandler.tsx | 61 ++++++--- src/views/navigator/NavigatorView.tsx | 14 ++ src/views/navigator/common/RoomInfoData.ts | 60 ++++++++ .../navigator/reducers/NavigatorReducer.tsx | 21 ++- src/views/navigator/views/NavigatorViews.scss | 2 + .../room-info/NavigatorRoomInfoView.scss | 20 +++ .../views/room-info/NavigatorRoomInfoView.tsx | 129 ++++++++++++++++++ .../room-info/NavigatorRoomInfoView.types.ts | 5 + .../room-link/NavigatorRoomLinkView.scss | 14 ++ .../views/room-link/NavigatorRoomLinkView.tsx | 70 ++++++++++ .../room-link/NavigatorRoomLinkView.types.ts | 5 + .../room-tools/RoomToolsWidgetView.tsx | 18 ++- 19 files changed, 416 insertions(+), 25 deletions(-) create mode 100644 src/assets/images/icons/arrows.png create mode 100644 src/assets/images/icons/camera-small.png create mode 100644 src/assets/images/icons/house-small.png create mode 100644 src/views/navigator/common/RoomInfoData.ts create mode 100644 src/views/navigator/views/room-info/NavigatorRoomInfoView.scss create mode 100644 src/views/navigator/views/room-info/NavigatorRoomInfoView.tsx create mode 100644 src/views/navigator/views/room-info/NavigatorRoomInfoView.types.ts create mode 100644 src/views/navigator/views/room-link/NavigatorRoomLinkView.scss create mode 100644 src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx create mode 100644 src/views/navigator/views/room-link/NavigatorRoomLinkView.types.ts diff --git a/public/configuration.json b/public/configuration.json index 965bc29c..35ba1570 100644 --- a/public/configuration.json +++ b/public/configuration.json @@ -19,7 +19,7 @@ "avatar.asset.url": "${asset.url}/bundled/figure/%libname%.nitro", "avatar.asset.effect.url": "${asset.url}/bundled/effect/%libname%.nitro", "furni.extras.url": "${asset.url}/images/furniextras/%image%.png", - "url.prefix": "", + "url.prefix": "http://localhost:3000", "chat.viewer.height.percentage": 0.40, "auth.system.enabled": true, "auth.system.http.enabled": true, diff --git a/src/assets/images/icons/arrows.png b/src/assets/images/icons/arrows.png new file mode 100644 index 0000000000000000000000000000000000000000..47a833ce7ac60dea4318cfe4659d7876fec1db7d GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^fanMpx^{g z7srr_TgeqaKPfVEFdwX!kd}Qsnfdf#5z8-Y{`dPD+F7cY3b=OOewUanMpx`Y} z7srr_TggApf0*Cc*!a@E?o3ZG-y-=F6<=NmdP=O|>^%ELe!b!eGbQN-nK_*19Lp77 zNL@U-VHb;Rvx>M*Y?Bh(qr*pRn4K?tVc=YUAYcc}CdRONj{kLSnGc$nH4C&k@;-bj z&cdzJqP6J@$DjM=x!3;RTWS2ze*;i#dn0VMaPS0RS zX1J-~(KF$J&4{_+Xc+UuoWirlCoaA^TiDwDlYVQe#Ra=yn3rDO;IKro? qDYjcGKy4921FxcpG8%ab#RCwB*l1~o7KorJ%50urP_03t*v%M6j@s zXhi2_X+HZj)0tS<40t3`I`Xwi8yqf-H27P&1ajGlb+57&h;CN(~)7YwlwK z7`EK*U@#u(gg689pf74E>>3xqRtapfSwM8YSi6T^4|)ppygC$rhGq3I$83-+XGO<6 z=;|ekjrf@8j_g2qjnz!va1 zi&rtbrvN=&*+ZUjAtK!i%B6Cy$K4IJE>H1iLjd2d2}@+dIv`n_{;__5mLq z9WDO5^~@pDXaU{?yA`qz`0()11wv!A2Cs_U0yzZigB}9B8g@-&O9oq@TZ0#eu9eLe zV2p!HGVi z{l55N87a_bXJ@_OQ!aQ`R+m7w07LdtY|LgFfQ-=anhRY6JQ+I&IVOX7S0UA84h>NP zx-@t+bZR!o4060KYlGi?0$c+cBe#Y}XLT%cN*5v3WnV^1*fpR_44PG-t$T9Pj)#=p zp-#h?&4_JO5Br+}NwhlXqgrk#V9$)TMRUpbMW zHLz4@{+Sg#2(4vvs6=3!CY1%gD=jS}wRO^lfaP+bL!WD9$Oj&k)uC+0Rwz_cIT~N) z=JpF0A3u2^{yjIh|LM)+dx}Fs^R^KFJ<(a63vH>n0LX)`&*w@1OInr=ZNnr%hXz3o z9qJlx{sF7+K!F|x`%D)G^C6U)l{i$NZ1q==lkmUMS%8Zbu6@2 zlO=4r49{kY&r6Y%^(zIf^~;tvjsnuGrr5rky^r<}n{N<|3kz-C z8}yY9X@`T>U9B_W87sAZysn3!wN7CuXoqb%wxMOTY0v~Nem*NxED4?p|mi>Dn3{CU#Q+VNxlXWquq z8tlX7T?w{!2u*{7O){hD0VSzCz|+pRP&9bJY4_%eKho(~W+n;+-Ea>Icke*Nl?E)d*O zI!XNc;_(ySc1mD4$H5q zKKbj03+)&N1^)8i&s|)5u(SB!!JlSeTpp**%}p1jU}FyaSKDFnwR;Zv?~gj{^O=1f zmFDBheZ~$1mvP7l{rVNl$>uk2x>)SKB?iTY_xnFzTI~IFsRIUF zK&GgCBhjfecouZZ(YwQ~^*%Hk5PQ(e2my0!{uy8+Fh|v(W5GimO7uac+ynm<_~7BX z*jEGayWhRj0|qb%D>PjmKEM9-stb}qd5&sqfcO@K>*`E>8f9T($-raLE|(t*IfL5>H2(hTMAL%~6L220l{(%|4F zOGi;?c!h|m!BXI$XBi~Vl?iEm12PA<)bMO*(|H|Rq!vGtfh{#yD|C`(4^L2YX-x73drHQlA-;4rG#)`YnRgGOeOdM8(+tjh^UP9 ztna|JK~Bm3*cu)JF9I!{5P5#1No)~{TH5j+Ms8`^SZ z7XAZ{AHM=e^b}xPbHxp&Oi;6Px{8zx&c3KK=Q=~o@RO4h7nTgt2DK1a?)+TftZTw^ zE>Z3>{P_6QzzJQ703HGkEk8sJ9_97m6da%tedsw<~^0LoM1^ATMce@^Qzjn zW1|_4=$4XFt4*8yz3-$9xAfsHfhTo0$Jjx$74T&5Pbz`a3~vd%5_jC?B?Vqv0i~F00000NkvXXu0mjfBEV%1 literal 3313 zcmcImX;f2Z8ot30DFUW~Hq=x@3doj?>``P3N`OF&LB(;&&CLa32?L8s` zgo271S(I(Wg^m=pKtWNfBDT1Wf?z>#K}AsTSm#E8>6z2^_-F1p_vTxk?|Gkh`QDSi ziz1iW+kR>b0D!$9lrKhpLy5Zln2_2i>of-+ZpA zDWI9==IrL%kpzEm2QLgi3sbP|=uqq2BRHeuo+BGxqWSe}@_WWp9Q^CQOVbZQ=jl9G}_ zPN9=knm7uL%SAYRDZaiW1VPdo5_O=Sl&JlDl7SCvA&o+YRN7DiB}O4j)i5vA{4 zP^zbB6SWgzLIOt7gK7$mOtrW)2^0$d8md%Ip|!e@jfj;Ay?;ool^E18MGR|I$r=a_ z*$5}nuu86oHGBwEDC7wewK^~nf(3j(A|i^cP{?_{4A7S&&m=KFa=dhS04hYjp z3>kw%;xIUJ5<|}B%3|pn8qM6SaO&I z!oJ9e4l>ztUp7+zG9p0^@nTgPC5TjtLJ7vf6m?=8k?>zN!Kwt6MyQe_F{l52U4XPk zjVe}=fNV^(NK3gR#t|n&6>hKUQb98Q`TB`65*s*(pnmdoHrge+A6%ZU@qia!YM zhq>{dHYFZLNdKZX-ov!2SX~OJfdk`^M0`N?QT|N67ToyP;y4||K{x7-tT(WBphjkmf=(fMkZ4|98N^2HAsi9ZfXff8vkYiKTx8- z^|-h(%4r$4ZER+ZU2EeR?3=kZOC0Upz1&-IbL*b2KSEr(;H!=z(T#Xxkd03EB;Kbk z|Gt^KoyA~0ykxq0(P6mn((V02v)ImscQ#kQT%6Xw@Ob}|NH~U75SH`FtIxv+>28>_ zB+v9PTf4QF3rBYX1x`i1y}gfydiI%uOT$G1BbUe1q#LPXpa6}VZ*~euK8%}TCI=>C zFc1gdXAUwp0G-Y_yDC?2Gb`}BK3d*tR}sy43+T*lQ`_h^Jw9Lf=rQL4z+1S`8@+xI z=)~bfGqN%V51`aoY)!S*1}h1aeJ?ufIo`ph#33L#qv}rD_e1dqPc3O;plnLBmv*iz zaP4~L8Jh76+Uym(u5!5G)5QYefeXK0ee^7DHg<1(OaL6vd95vTH0yGw)BQcjoMtX* zx)N6Ax!@PO@vD(mWx_fi!Vgi?n6ty&e6EYfpN3-;Ig-0>M(SZN^OY^6wX;Rb4FWp@ zX1~w;<3~0>=(%_Kz^j)&32({x-o43%M*SvWf1BO89#3l0yccO(BE;|>&x5FFR901P zdp>wo5?Fr;Rg#_7StATsZE}`~&e6+W4*v)#(y;HvzE@_1JCjcB&-hG zW8Z3dNmWGK^Zf$HazZ7)h2<4&3VpNWxvRr0s7D;J;YCGle8E4w`5RF6sw_ZJaLCa* z=Gv`7a2DR7$mCOUz50z&$jt*VI~#|5lIYo1z$=)*UmVJ-_O%udNAJyY+5mZh73G-*htz zT@iMx)4^j%cj939S`%oPS!n}}j%4pBpWjdRsNex-R`_ePf6cZM^*-HoRMk`Ay5+O2 ziu26@X{pahGtsc%XoHpj-cFjzt+bgVDR+WjN` za_w|(S#?;0?bhiLtEZi5?luV1y;7K84*0L?Q0JITM)LKdjn%b>zdtw5ZZ+phUw5~R zBs~2s)d6D$@V2Iw^6)$6NA9P&YtgMa4M05Jg^HimH9Z$=x9tEb+j@4Del*s1Pxv9AceIa$&^v|7lrGqz%$*)AAw8bJ$ z$EHo%tll+lHWy9+PPSVq-p79;4_fp01Vv@L;P#I_2e6Wl(-u16(JOOwUo-6;s#a%z zWR%)}+)ERio&R?6br?_3Ket;gn)CJ5>KpFQc9WcQ&OmjN54Ts&iHNy!dR==63VYh$ z2H5-LV*L?gPhVwfZZ6s7xV^A$Fv$T^s{S%px6Rq=dAjYcTFyNGioRv`o~`V4)1Zc> z-(+NLXRcptcp3QJ@Z3=x8b&!L7e0LO(Apz28e=!&^l{xWjKD z*01b?yOi-I(O<7bEgy({-4U+?ABaZKA{Xj`XUf!w()JC22atKB;fd*jKEgZdwTOwT ztCF6obbMOFYi2w@g-dm`s%|N@ZSynk27Z3vxXnf6X^1$~UL(5&4wgTl2^NjyZ1^$x zX1S2McM&^kHat+;fc|-4&nGppcioCy@7@UvTozIexL2NN6nz = props => { - const { dispatchNavigatorState = null } = useNavigatorContext(); + const { navigatorState = null, dispatchNavigatorState = null } = useNavigatorContext(); const onUserInfoEvent = useCallback((event: UserInfoEvent) => { @@ -28,8 +28,19 @@ export const NavigatorMessageHandler: FC = props = { const parser = event.getParser(); + const roomInfoData = navigatorState.roomInfoData; + roomInfoData.currentRoomOwner = parser.isOwner; + roomInfoData.currentRoomId = parser.roomId; + + dispatchNavigatorState({ + type: NavigatorActions.SET_ROOM_INFO_DATA, + payload: { + roomInfoData: roomInfoData + } + }); + SendMessageHook(new RoomInfoComposer(parser.roomId, true, false)); - }, []); + }, [ navigatorState, dispatchNavigatorState ]); const onRoomInfoEvent = useCallback((event: RoomInfoEvent) => { @@ -37,17 +48,15 @@ export const NavigatorMessageHandler: FC = props = if(parser.roomEnter) { - // this._data.enteredGuestRoom = parser.data; - // this._data.staffPick = parser.data.roomPicker; + const roomInfoData = navigatorState.roomInfoData; + roomInfoData.enteredGuestRoom = parser.data; - // const isCreatedRoom = (this._data.createdRoomId === parser.data.roomId); - - // if(!isCreatedRoom && parser.data.displayRoomEntryAd) - // { - // // display ad - // } - - // this._data.createdRoomId = 0; + dispatchNavigatorState({ + type: NavigatorActions.SET_ROOM_INFO_DATA, + payload: { + roomInfoData: roomInfoData + } + }); } else if(parser.roomForward) { @@ -66,10 +75,17 @@ export const NavigatorMessageHandler: FC = props = } else { - // this._data.enteredGuestRoom = parser.data; - // this._data.staffPick = parser.data.roomPicker; + const roomInfoData = navigatorState.roomInfoData; + roomInfoData.enteredGuestRoom = parser.data; + + dispatchNavigatorState({ + type: NavigatorActions.SET_ROOM_INFO_DATA, + payload: { + roomInfoData: roomInfoData + } + }); } - }, []); + }, [ dispatchNavigatorState, navigatorState ]); const onRoomDoorbellEvent = useCallback((event: RoomDoorbellEvent) => { @@ -146,6 +162,18 @@ export const NavigatorMessageHandler: FC = props = VisitRoom(parser.roomId); }, []); + const onNavigatorHomeRoomEvent = useCallback((event: NavigatorHomeRoomEvent) => + { + const parser = event.getParser(); + + dispatchNavigatorState({ + type: NavigatorActions.SET_HOME_ROOM_ID, + payload: { + homeRoomId: parser.homeRoomId + } + }); + }, [ dispatchNavigatorState ]); + CreateMessageHook(UserInfoEvent, onUserInfoEvent); CreateMessageHook(RoomForwardEvent, onRoomForwardEvent); CreateMessageHook(RoomInfoOwnerEvent, onRoomInfoOwnerEvent); @@ -157,6 +185,7 @@ export const NavigatorMessageHandler: FC = props = CreateMessageHook(NavigatorSearchEvent, onNavigatorSearchEvent); CreateMessageHook(NavigatorCategoriesEvent, onNavigatorCategoriesEvent); CreateMessageHook(RoomCreatedEvent, onRoomCreatedEvent); + CreateMessageHook(NavigatorHomeRoomEvent, onNavigatorHomeRoomEvent); return null; } diff --git a/src/views/navigator/NavigatorView.tsx b/src/views/navigator/NavigatorView.tsx index e1c1ecb3..123b4044 100644 --- a/src/views/navigator/NavigatorView.tsx +++ b/src/views/navigator/NavigatorView.tsx @@ -11,6 +11,8 @@ import { NavigatorMessageHandler } from './NavigatorMessageHandler'; import { NavigatorViewProps } from './NavigatorView.types'; import { initialNavigator, NavigatorActions, NavigatorReducer } from './reducers/NavigatorReducer'; import { NavigatorRoomCreatorView } from './views/creator/NavigatorRoomCreatorView'; +import { NavigatorRoomInfoView } from './views/room-info/NavigatorRoomInfoView'; +import { NavigatorRoomLinkView } from './views/room-link/NavigatorRoomLinkView'; import { NavigatorSearchResultSetView } from './views/search-result-set/NavigatorSearchResultSetView'; import { NavigatorSearchView } from './views/search/NavigatorSearchView'; @@ -18,6 +20,8 @@ export const NavigatorView: FC = props => { const [ isVisible, setIsVisible ] = useState(false); const [ isCreatorOpen, setCreatorOpen ] = useState(false); + const [ isRoomInfoOpen, setRoomInfoOpen ] = useState(false); + const [ isRoomLinkOpen, setRoomLinkOpen ] = useState(false); const [ navigatorState, dispatchNavigatorState ] = useReducer(NavigatorReducer, initialNavigator); const { needsNavigatorUpdate = false, topLevelContext = null, topLevelContexts = null } = navigatorState; @@ -34,12 +38,20 @@ export const NavigatorView: FC = props => case NavigatorEvent.TOGGLE_NAVIGATOR: setIsVisible(value => !value); return; + case NavigatorEvent.TOGGLE_ROOM_INFO: + setRoomInfoOpen(value => !value); + return; + case NavigatorEvent.TOGGLE_ROOM_LINK: + setRoomLinkOpen(value => !value); + return; } }, []); useUiEvent(NavigatorEvent.SHOW_NAVIGATOR, onNavigatorEvent); useUiEvent(NavigatorEvent.HIDE_NAVIGATOR, onNavigatorEvent); useUiEvent(NavigatorEvent.TOGGLE_NAVIGATOR, onNavigatorEvent); + useUiEvent(NavigatorEvent.TOGGLE_ROOM_INFO, onNavigatorEvent); + useUiEvent(NavigatorEvent.TOGGLE_ROOM_LINK, onNavigatorEvent); const onRoomSessionEvent = useCallback((event: RoomSessionEvent) => { @@ -110,6 +122,8 @@ export const NavigatorView: FC = props =>
} + { isRoomInfoOpen && setRoomInfoOpen(false) } /> } + { isRoomLinkOpen && setRoomLinkOpen(false) } /> } ); } diff --git a/src/views/navigator/common/RoomInfoData.ts b/src/views/navigator/common/RoomInfoData.ts new file mode 100644 index 00000000..3b251b1c --- /dev/null +++ b/src/views/navigator/common/RoomInfoData.ts @@ -0,0 +1,60 @@ +import { RoomDataParser } from 'nitro-renderer'; + +export class RoomInfoData +{ + private _enteredGuestRoom: RoomDataParser = null; + private _createdRoomId: number = 0; + private _currentRoomId: number = 0; + private _currentRoomOwner: boolean = false; + private _canRate: boolean = false; + + public get enteredGuestRoom(): RoomDataParser + { + return this._enteredGuestRoom; + } + + public set enteredGuestRoom(data: RoomDataParser) + { + this._enteredGuestRoom = data; + } + + public get createdRoomId(): number + { + return this._createdRoomId; + } + + public set createdRoomId(id: number) + { + this._createdRoomId = id; + } + + public get currentRoomId(): number + { + return this._currentRoomId; + } + + public set currentRoomId(id: number) + { + this._currentRoomId = id; + } + + public get currentRoomOwner(): boolean + { + return this._currentRoomOwner; + } + + public set currentRoomOwner(flag: boolean) + { + this._currentRoomOwner = flag; + } + + public get canRate(): boolean + { + return this._canRate; + } + + public set canRate(flag: boolean) + { + this._canRate = flag; + } +} diff --git a/src/views/navigator/reducers/NavigatorReducer.tsx b/src/views/navigator/reducers/NavigatorReducer.tsx index f6da40e4..16cdce5d 100644 --- a/src/views/navigator/reducers/NavigatorReducer.tsx +++ b/src/views/navigator/reducers/NavigatorReducer.tsx @@ -1,5 +1,6 @@ import { NavigatorCategoryDataParser, NavigatorSearchResultSet, NavigatorTopLevelContext } from 'nitro-renderer'; import { Reducer } from 'react'; +import { RoomInfoData } from '../common/RoomInfoData'; export interface INavigatorState { @@ -8,6 +9,8 @@ export interface INavigatorState topLevelContexts: NavigatorTopLevelContext[]; searchResult: NavigatorSearchResultSet; categories: NavigatorCategoryDataParser[]; + roomInfoData: RoomInfoData; + homeRoomId: number; } export interface INavigatorAction @@ -19,6 +22,8 @@ export interface INavigatorAction topLevelContexts?: NavigatorTopLevelContext[]; searchResult?: NavigatorSearchResultSet; categories?: NavigatorCategoryDataParser[]; + roomInfoData?: RoomInfoData; + homeRoomId?: number; } } @@ -29,6 +34,8 @@ export class NavigatorActions public static SET_TOP_LEVEL_CONTEXTS: string = 'NA_SET_TOP_LEVEL_CONTEXTS'; public static SET_SEARCH_RESULT: string = 'NA_SET_SEARCH_RESULT'; public static SET_CATEGORIES: string = 'NA_SET_CATEGORIES'; + public static SET_ROOM_INFO_DATA: string = 'NA_SET_ROOM_INFO_DATA'; + public static SET_HOME_ROOM_ID: string = 'NA_SET_HOME_ROOM_ID'; } export const initialNavigator: INavigatorState = { @@ -36,7 +43,9 @@ export const initialNavigator: INavigatorState = { topLevelContext: null, topLevelContexts: null, searchResult: null, - categories: null + categories: null, + roomInfoData: new RoomInfoData(), + homeRoomId: null } export const NavigatorReducer: Reducer = (state, action) => @@ -90,6 +99,16 @@ export const NavigatorReducer: Reducer = (sta return { ...state, categories }; } + case NavigatorActions.SET_ROOM_INFO_DATA: { + const roomInfoData = (action.payload.roomInfoData || state.roomInfoData || null); + + return { ...state, roomInfoData }; + } + case NavigatorActions.SET_HOME_ROOM_ID: { + const homeRoomId = (action.payload.homeRoomId || state.homeRoomId || null); + + return { ...state, homeRoomId }; + } default: return state; } diff --git a/src/views/navigator/views/NavigatorViews.scss b/src/views/navigator/views/NavigatorViews.scss index 60c10722..174445ad 100644 --- a/src/views/navigator/views/NavigatorViews.scss +++ b/src/views/navigator/views/NavigatorViews.scss @@ -2,3 +2,5 @@ @import './search/NavigatorSearchView'; @import './search-result/NavigatorSearchResultView'; @import './search-result-item/NavigatorSearchResultItemView'; +@import './room-info/NavigatorRoomInfoView'; +@import './room-link/NavigatorRoomLinkView'; diff --git a/src/views/navigator/views/room-info/NavigatorRoomInfoView.scss b/src/views/navigator/views/room-info/NavigatorRoomInfoView.scss new file mode 100644 index 00000000..9763a4fc --- /dev/null +++ b/src/views/navigator/views/room-info/NavigatorRoomInfoView.scss @@ -0,0 +1,20 @@ +.nitro-room-info { + width: 230px; + + .gray { + filter: grayscale(1); + opacity: .5; + } + + .room-thumbnail { + position: relative; + width: 110px; + height: 110px; + margin: 0 auto; + background-image: url(../../../../assets/images/navigator/thumbnail_placeholder.png); + background-repeat: no-repeat; + background-position: center; + background-color: rgba($black, .125); + border-color: $black !important; + } +} diff --git a/src/views/navigator/views/room-info/NavigatorRoomInfoView.tsx b/src/views/navigator/views/room-info/NavigatorRoomInfoView.tsx new file mode 100644 index 00000000..1f0e656d --- /dev/null +++ b/src/views/navigator/views/room-info/NavigatorRoomInfoView.tsx @@ -0,0 +1,129 @@ +import classNames from 'classnames'; +import { RoomMuteComposer, RoomStaffPickComposer, UserHomeRoomComposer } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { GetConfiguration } from '../../../../api'; +import { NavigatorEvent } from '../../../../events'; +import { dispatchUiEvent } from '../../../../hooks/events'; +import { SendMessageHook } from '../../../../hooks/messages'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; +import { LocalizeText } from '../../../../utils/LocalizeText'; +import { useNavigatorContext } from '../../context/NavigatorContext'; +import { NavigatorActions } from '../../reducers/NavigatorReducer'; +import { NavigatorRoomInfoViewProps } from './NavigatorRoomInfoView.types'; + +export const NavigatorRoomInfoView: FC = props => +{ + const { onCloseClick = null } = props; + + const { navigatorState = null, dispatchNavigatorState = null } = useNavigatorContext(); + const { roomInfoData = null, homeRoomId = null } = navigatorState; + const [ roomThumbnail, setRoomThumbnail ] = useState(null); + const [ isRoomPicked, setIsRoomPicked ] = useState(false); + const [ isRoomMuted, setIsRoomMuted ] = useState(false); + + useEffect(() => + { + if(!roomInfoData || !roomInfoData.enteredGuestRoom) return; + + if(roomInfoData.enteredGuestRoom.officialRoomPicRef) + { + setRoomThumbnail(GetConfiguration('image.library.url') + roomInfoData.enteredGuestRoom.officialRoomPicRef); + } + + setIsRoomPicked(roomInfoData.enteredGuestRoom.roomPicker); + setIsRoomMuted(roomInfoData.enteredGuestRoom.allInRoomMuted); + }, [ roomInfoData ]); + + const processAction = useCallback((action: string) => + { + if(!roomInfoData || !roomInfoData.enteredGuestRoom) return; + + switch(action) + { + case 'set_home_room': + let newRoomId = -1; + + if(homeRoomId !== roomInfoData.enteredGuestRoom.roomId) + { + newRoomId = roomInfoData.enteredGuestRoom.roomId; + } + + dispatchNavigatorState({ + type: NavigatorActions.SET_HOME_ROOM_ID, + payload: { + homeRoomId: newRoomId + } + }); + + SendMessageHook(new UserHomeRoomComposer(newRoomId)); + return; + case 'toggle_room_link': + dispatchUiEvent(new NavigatorEvent(NavigatorEvent.TOGGLE_ROOM_LINK)); + return; + case 'toggle_pick': + setIsRoomPicked(value => !value); + SendMessageHook(new RoomStaffPickComposer(roomInfoData.enteredGuestRoom.roomId)); + return; + case 'toggle_mute': + setIsRoomMuted(value => !value); + SendMessageHook(new RoomMuteComposer()); + return; + case 'close': + onCloseClick(); + return; + } + + }, [ onCloseClick, dispatchNavigatorState, roomInfoData, homeRoomId ]); + + if(!roomInfoData) return null; + + return ( + + processAction('close') } /> + + { roomInfoData.enteredGuestRoom && <> +
+
+ { roomInfoData.enteredGuestRoom.roomName } +
+ processAction('set_home_room') } className={ 'icon icon-house-small cursor-pointer' + classNames({' gray': homeRoomId !== roomInfoData.enteredGuestRoom.roomId }) } /> +
+
+ { roomInfoData.enteredGuestRoom.showOwner && <> +
{ LocalizeText('navigator.roomownercaption') }
+
+ +
{ roomInfoData.enteredGuestRoom.ownerName }
+
+ } +
+
+ { LocalizeText('navigator.roomrating') } { roomInfoData.enteredGuestRoom.score } +
+
+ { roomInfoData.enteredGuestRoom.tags.map(tag => + { + return
#{ tag }
+ }) } +
+
{ roomInfoData.enteredGuestRoom.description }
+
+ + { roomThumbnail && } +
+
processAction('toggle_room_link') }> + + { LocalizeText('navigator.embed.caption') } +
+ + + + + + + } + +
+
+ ); +}; diff --git a/src/views/navigator/views/room-info/NavigatorRoomInfoView.types.ts b/src/views/navigator/views/room-info/NavigatorRoomInfoView.types.ts new file mode 100644 index 00000000..a4b6b81b --- /dev/null +++ b/src/views/navigator/views/room-info/NavigatorRoomInfoView.types.ts @@ -0,0 +1,5 @@ + +export class NavigatorRoomInfoViewProps +{ + onCloseClick: () => void; +} diff --git a/src/views/navigator/views/room-link/NavigatorRoomLinkView.scss b/src/views/navigator/views/room-link/NavigatorRoomLinkView.scss new file mode 100644 index 00000000..ae215535 --- /dev/null +++ b/src/views/navigator/views/room-link/NavigatorRoomLinkView.scss @@ -0,0 +1,14 @@ +.nitro-room-link { + width: 400px; + + .room-thumbnail { + position: relative; + width: 110px; + height: 110px; + background-image: url(../../../../assets/images/navigator/thumbnail_placeholder.png); + background-repeat: no-repeat; + background-position: center; + background-color: rgba($black, .125); + border-color: $black !important; + } +} diff --git a/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx b/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx new file mode 100644 index 00000000..c36f9d86 --- /dev/null +++ b/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx @@ -0,0 +1,70 @@ +import { FC, useCallback, useEffect, useRef, useState } from 'react'; +import { GetConfiguration } from '../../../../api'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; +import { LocalizeText } from '../../../../utils/LocalizeText'; +import { useNavigatorContext } from '../../context/NavigatorContext'; +import { NavigatorRoomLinkViewProps } from './NavigatorRoomLinkView.types'; + +export const NavigatorRoomLinkView: FC = props => +{ + const { onCloseClick = null } = props; + const { navigatorState = null } = useNavigatorContext(); + const { roomInfoData = null } = navigatorState; + + const [ roomThumbnail, setRoomThumbnail ] = useState(null); + const [ roomLink, setRoomLink ] = useState(null); + + const elementRef = useRef(); + + useEffect(() => + { + if(!roomInfoData || !roomInfoData.enteredGuestRoom) return; + + if(roomInfoData.enteredGuestRoom.officialRoomPicRef) + { + setRoomThumbnail(GetConfiguration('image.library.url') + roomInfoData.enteredGuestRoom.officialRoomPicRef); + } + + const urlPrefix = GetConfiguration('url.prefix'); + const roomLinkRaw = LocalizeText('navigator.embed.src', ['roomId'], [roomInfoData.enteredGuestRoom.roomId.toString()]).replace('${url.prefix}', urlPrefix); + + setRoomLink(roomLinkRaw); + }, [ roomInfoData ]); + + const processAction = useCallback((action: string) => + { + if(!roomInfoData || !roomInfoData.enteredGuestRoom) return; + + switch(action) + { + case 'copy_room_link': + elementRef.current.select(); + document.execCommand('copy'); + return; + case 'close': + onCloseClick(); + return; + } + + }, [onCloseClick, roomInfoData]); + + if(!roomInfoData) return null; + + return ( + + processAction('close') } /> + +
+
+ { roomThumbnail && } +
+
+
+
{ LocalizeText('navigator.embed.headline') }
+
{ LocalizeText('navigator.embed.info') }
+ { roomLink && } +
+
+
+ ); +}; diff --git a/src/views/navigator/views/room-link/NavigatorRoomLinkView.types.ts b/src/views/navigator/views/room-link/NavigatorRoomLinkView.types.ts new file mode 100644 index 00000000..3c206b6f --- /dev/null +++ b/src/views/navigator/views/room-link/NavigatorRoomLinkView.types.ts @@ -0,0 +1,5 @@ + +export class NavigatorRoomLinkViewProps +{ + onCloseClick: () => void; +} diff --git a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx index 0ce23306..1146b4a4 100644 --- a/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx +++ b/src/views/room/widgets/room-tools/RoomToolsWidgetView.tsx @@ -1,6 +1,8 @@ import classNames from 'classnames'; import { RoomLikeRoomComposer } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; +import { NavigatorEvent } from '../../../../events'; +import { dispatchUiEvent } from '../../../../hooks/events'; import { SendMessageHook } from '../../../../hooks/messages'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { useRoomContext } from '../../context/RoomContext'; @@ -13,13 +15,14 @@ export const RoomToolsWidgetView: FC = props => const [ isExpended, setIsExpanded ] = useState(false); const [ isZoomedIn, setIsZoomedIn ] = useState(false); - const [ liked, setLiked ] = useState(false); + const [ isLiked, setIsLiked ] = useState(false); const handleToolClick = useCallback((action: string) => { switch(action) { case 'settings': + dispatchUiEvent(new NavigatorEvent(NavigatorEvent.TOGGLE_ROOM_INFO)); return; case 'zoom': widgetHandler.processWidgetMessage(new RoomWidgetZoomToggleMessage(!isZoomedIn)); @@ -28,15 +31,16 @@ export const RoomToolsWidgetView: FC = props => case 'chat_history': return; case 'like_room': - if(liked) return; + if(isLiked) return; SendMessageHook(new RoomLikeRoomComposer(1)); - setLiked(true); + setIsLiked(true); return; - case 'room_link': + case 'toggle_room_link': + dispatchUiEvent(new NavigatorEvent(NavigatorEvent.TOGGLE_ROOM_LINK)); return; } - }, [ isZoomedIn, liked, widgetHandler ]); + }, [ isZoomedIn, isLiked, widgetHandler ]); return (
@@ -50,10 +54,10 @@ export const RoomToolsWidgetView: FC = props =>
handleToolClick('chat_history') }> { LocalizeText('room.chathistory.button.text') }
-
handleToolClick('like_room') }> +
handleToolClick('like_room') }> { LocalizeText('room.like.button.text') }
-
handleToolClick('room_link') }> +
handleToolClick('toggle_room_link') }> { LocalizeText('navigator.embed.caption') }
From a25e84c7fbae188fc3215a37fa629eda3a404ad7 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sat, 3 Jul 2021 17:08:05 -0300 Subject: [PATCH 10/72] Updates --- .../thumbnail-camera-spritesheet.png | Bin 0 -> 883 bytes .../views/room-info/NavigatorRoomInfoView.tsx | 20 +++++- src/views/room/widgets/RoomWidgets.scss | 1 + src/views/room/widgets/RoomWidgetsView.tsx | 3 +- .../room-thumbnail/RoomThumbnailView.scss | 14 ++++ .../room-thumbnail/RoomThumbnailView.types.ts | 4 ++ .../RoomThumbnailWidgetView.tsx | 44 ++++++++++++ .../RoomThumbnailWidgetBuilderView.props.ts | 4 ++ .../RoomThumbnailWidgetBuilderView.scss | 3 + .../RoomThumbnailWidgetBuilderView.tsx | 63 ++++++++++++++++++ .../camera/RoomThumbnailWidgetCameraView.scss | 13 ++++ .../camera/RoomThumbnailWidgetCameraView.tsx | 39 +++++++++++ .../RoomThumbnailWidgetCameraView.types.ts | 4 ++ 13 files changed, 208 insertions(+), 4 deletions(-) create mode 100644 src/assets/images/room-widgets/thumbnail-widget/thumbnail-camera-spritesheet.png create mode 100644 src/views/room/widgets/room-thumbnail/RoomThumbnailView.scss create mode 100644 src/views/room/widgets/room-thumbnail/RoomThumbnailView.types.ts create mode 100644 src/views/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx create mode 100644 src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.props.ts create mode 100644 src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.scss create mode 100644 src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.tsx create mode 100644 src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.scss create mode 100644 src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.tsx create mode 100644 src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.types.ts diff --git a/src/assets/images/room-widgets/thumbnail-widget/thumbnail-camera-spritesheet.png b/src/assets/images/room-widgets/thumbnail-widget/thumbnail-camera-spritesheet.png new file mode 100644 index 0000000000000000000000000000000000000000..63a9397f20e4cedf864e6111ce0bd850044caaba GIT binary patch literal 883 zcmeAS@N?(olHy`uVBq!ia0vp^EkJyLgAGU??LB=LNO2Z;L>4nJa0`Jj~)z5CGjwu3~&!|3L`3*X{5dqp$~ewyAF_-w~YBi2$S9>0Q1Y`rw`FhJ+3mYt`#1Emm*(1S@9pcB?R#5R{pLp@-=hDgOXk1s zF74j^tIa^KiD6+aN3wyNDJTIkwikl7b4s3}RGN0Ly|*?NH;J z5VMm>kiq5OBhd~v$0sw_IfU>iiSJ@!be^lx5W(im#?+=2=)yj6Aw!Z@*K+RbY5_9@ zE(@5nD;ag{G`!Qr+~FWG&!^*?noA~+WQT=>Pe+$SiblhZ>n$tzS~(e;IT=|6zT5mv zaWXMbJhaF_F~LAl?9P%Lr!AjndkG(EnNhp>&$3G`E55%xRM}B9`>Bn~;pd7)B0OqG zYBc7oEP1u-Z1XmU0}L(VuNfXbt#PP0s4sAji-99wim7G0D98gG5Z`Rr;lRMiB7h*6 zoVc4$i0xeW{}ww!6*MG4T3~ALuqEX$T%DQkbRxLz9seR1vkxV<--_3+4!$1s?8??x zxnTnBeDw=ny}fmhiSbB@K){yHL?Mo?l8`8Y*o|Z=G_oRO6tD$0)U9CkAlEWE{bylh z<&l^8^;?sH@rb|?PA-E-4i@#RB<__y73SJ{|KxsYKE88#M<@TX-Vm`yKp@VZw{7BY jW7X{{T$ef9oa-6y>7~B8=s#DM0SG)@{an^LB{Ts5nJ6~q literal 0 HcmV?d00001 diff --git a/src/views/navigator/views/room-info/NavigatorRoomInfoView.tsx b/src/views/navigator/views/room-info/NavigatorRoomInfoView.tsx index 1f0e656d..d7c483aa 100644 --- a/src/views/navigator/views/room-info/NavigatorRoomInfoView.tsx +++ b/src/views/navigator/views/room-info/NavigatorRoomInfoView.tsx @@ -7,6 +7,7 @@ import { dispatchUiEvent } from '../../../../hooks/events'; import { SendMessageHook } from '../../../../hooks/messages'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; import { LocalizeText } from '../../../../utils/LocalizeText'; +import { BadgeImageView } from '../../../shared/badge-image/BadgeImageView'; import { useNavigatorContext } from '../../context/NavigatorContext'; import { NavigatorActions } from '../../reducers/NavigatorReducer'; import { NavigatorRoomInfoViewProps } from './NavigatorRoomInfoView.types'; @@ -34,7 +35,7 @@ export const NavigatorRoomInfoView: FC = props => setIsRoomMuted(roomInfoData.enteredGuestRoom.allInRoomMuted); }, [ roomInfoData ]); - const processAction = useCallback((action: string) => + const processAction = useCallback((action: string, value?: string) => { if(!roomInfoData || !roomInfoData.enteredGuestRoom) return; @@ -57,6 +58,12 @@ export const NavigatorRoomInfoView: FC = props => SendMessageHook(new UserHomeRoomComposer(newRoomId)); return; + case 'navigator_search_tag': + return; + case 'open_room_thumbnail_camera': + return; + case 'open_group_info': + return; case 'toggle_room_link': dispatchUiEvent(new NavigatorEvent(NavigatorEvent.TOGGLE_ROOM_LINK)); return; @@ -103,7 +110,7 @@ export const NavigatorRoomInfoView: FC = props =>
{ roomInfoData.enteredGuestRoom.tags.map(tag => { - return
#{ tag }
+ return
processAction('navigator_search_tag', tag) }>#{ tag }
}) }
{ roomInfoData.enteredGuestRoom.description }
@@ -111,12 +118,19 @@ export const NavigatorRoomInfoView: FC = props => { roomThumbnail && }
+ { roomInfoData.enteredGuestRoom.habboGroupId > 0 &&
processAction('open_group_info') }> +
+ +
+
+ { LocalizeText('navigator.guildbase', ['groupName'], [roomInfoData.enteredGuestRoom.groupName]) } +
+
}
processAction('toggle_room_link') }> { LocalizeText('navigator.embed.caption') }
- diff --git a/src/views/room/widgets/RoomWidgets.scss b/src/views/room/widgets/RoomWidgets.scss index 6f4cfbb9..5ebe757a 100644 --- a/src/views/room/widgets/RoomWidgets.scss +++ b/src/views/room/widgets/RoomWidgets.scss @@ -6,3 +6,4 @@ @import './infostand/InfoStandWidgetView'; @import './object-location/ObjectLocationView'; @import './room-tools/RoomToolsWidgetView'; +@import './room-thumbnail/RoomThumbnailView'; diff --git a/src/views/room/widgets/RoomWidgetsView.tsx b/src/views/room/widgets/RoomWidgetsView.tsx index c95aaaa1..66fe44cd 100644 --- a/src/views/room/widgets/RoomWidgetsView.tsx +++ b/src/views/room/widgets/RoomWidgetsView.tsx @@ -9,9 +9,9 @@ import { ChatInputView } from './chat-input/ChatInputView'; import { ChatWidgetView } from './chat/ChatWidgetView'; import { FurnitureWidgetsView } from './furniture/FurnitureWidgetsView'; import { InfoStandWidgetView } from './infostand/InfoStandWidgetView'; +import { RoomThumbnailWidgetView } from './room-thumbnail/RoomThumbnailWidgetView'; import { RoomToolsWidgetView } from './room-tools/RoomToolsWidgetView'; import { RoomWidgetViewProps } from './RoomWidgets.types'; - export const RoomWidgetsView: FC = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); @@ -110,6 +110,7 @@ export const RoomWidgetsView: FC = props => + ); } diff --git a/src/views/room/widgets/room-thumbnail/RoomThumbnailView.scss b/src/views/room/widgets/room-thumbnail/RoomThumbnailView.scss new file mode 100644 index 00000000..0e39af10 --- /dev/null +++ b/src/views/room/widgets/room-thumbnail/RoomThumbnailView.scss @@ -0,0 +1,14 @@ +.nitro-room-thumbnail { + width: 300px; + + .option { + font-size: 30px; + height: 50px; + display: flex; + align-items: center; + cursor: pointer; + } +} + +@import './views/builder/RoomThumbnailWidgetBuilderView'; +@import './views/camera/RoomThumbnailWidgetCameraView'; diff --git a/src/views/room/widgets/room-thumbnail/RoomThumbnailView.types.ts b/src/views/room/widgets/room-thumbnail/RoomThumbnailView.types.ts new file mode 100644 index 00000000..68969857 --- /dev/null +++ b/src/views/room/widgets/room-thumbnail/RoomThumbnailView.types.ts @@ -0,0 +1,4 @@ +import { RoomWidgetProps } from '../RoomWidgets.types'; + +export class RoomThumbnailWidgetViewProps implements RoomWidgetProps +{} diff --git a/src/views/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx b/src/views/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx new file mode 100644 index 00000000..90d7fb63 --- /dev/null +++ b/src/views/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx @@ -0,0 +1,44 @@ +import { FC, useCallback, useState } from 'react'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; +import { LocalizeText } from '../../../../utils/LocalizeText'; +import { RoomThumbnailWidgetViewProps } from './RoomThumbnailView.types'; +import { RoomThumbnailWidgetBuilderView } from './views/builder/RoomThumbnailWidgetBuilderView'; +import { RoomThumbnailWidgetCameraView } from './views/camera/RoomThumbnailWidgetCameraView'; + +export const RoomThumbnailWidgetView: FC = props => +{ + const [ isSelectorVisible, setIsSelectorVisible ] = useState(false); + const [ isBuilderVisible, setIsBuilderVisible ] = useState(false); + const [ isCameraVisible, setIsCameraVisible ] = useState(false); + + const handleAction = useCallback((action: string) => + { + switch(action) + { + case 'camera': + setIsSelectorVisible(false); + setIsCameraVisible(true); + return; + case 'builder': + setIsSelectorVisible(false); + setIsBuilderVisible(true); + return; + } + }, [ setIsSelectorVisible, setIsCameraVisible, setIsBuilderVisible ]); + + return (<> + { isSelectorVisible && + setIsSelectorVisible(false) } /> + +
handleAction('camera') }> + +
+
handleAction('builder') }> + +
+
+
} + { isBuilderVisible && setIsBuilderVisible(false) } /> } + { isCameraVisible && setIsCameraVisible(false) } /> } + ); +}; diff --git a/src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.props.ts b/src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.props.ts new file mode 100644 index 00000000..77c8b94b --- /dev/null +++ b/src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.props.ts @@ -0,0 +1,4 @@ +export class RoomThumbnailWidgetBuilderViewProps +{ + onCloseClick: () => void; +} diff --git a/src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.scss b/src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.scss new file mode 100644 index 00000000..d011f674 --- /dev/null +++ b/src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.scss @@ -0,0 +1,3 @@ +.nitro-room-thumbnail-builder { + width: 600px; +} diff --git a/src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.tsx b/src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.tsx new file mode 100644 index 00000000..f5061555 --- /dev/null +++ b/src/views/room/widgets/room-thumbnail/views/builder/RoomThumbnailWidgetBuilderView.tsx @@ -0,0 +1,63 @@ +import { FC, useCallback, useState } from 'react'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../../../layout'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { RoomThumbnailWidgetBuilderViewProps } from './RoomThumbnailWidgetBuilderView.props'; + +const TABS: string[] = [ + 'navigator.thumbeditor.bgtab', + 'navigator.thumbeditor.objtab', + 'navigator.thumbeditor.toptab', +]; + +export const RoomThumbnailWidgetBuilderView: FC = props => +{ + const { onCloseClick = null } = props; + + const [ currentTab, setCurrentTab ] = useState(TABS[0]); + + const processAction = useCallback((action: string, value?: string) => + { + switch(action) + { + case 'change_tab': + setCurrentTab(value); + return; + } + }, [ setCurrentTab ]); + + return ( + + +
+
+ + { TABS.map(tab => + { + return processAction('change_tab', tab) }> + { LocalizeText(tab) } + + }) } + + +
+
+ +
+
+
+
+
+ + +
+
+ + +
+
+
+
+
+
+ ); +}; diff --git a/src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.scss b/src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.scss new file mode 100644 index 00000000..b472dcda --- /dev/null +++ b/src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.scss @@ -0,0 +1,13 @@ +.nitro-room-thumbnail-camera { + width: 132px; + height: 192px; + background-image: url('../../../../../../assets/images/room-widgets/thumbnail-widget/thumbnail-camera-spritesheet.png'); + + .camera-frame { + position: absolute; + width: 110px; + height: 110px; + margin-top: 38px; + margin-left: 3px; + } +} diff --git a/src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.tsx b/src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.tsx new file mode 100644 index 00000000..ffe7439d --- /dev/null +++ b/src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.tsx @@ -0,0 +1,39 @@ +import { NitroRectangle } from 'nitro-renderer'; +import { FC, useCallback, useRef } from 'react'; +import { GetRoomEngine, GetRoomSession } from '../../../../../../api'; +import { DraggableWindow } from '../../../../../../layout'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { RoomThumbnailWidgetCameraViewProps } from './RoomThumbnailWidgetCameraView.types'; + +export const RoomThumbnailWidgetCameraView: FC = props => +{ + const { onCloseClick = null } = props; + + const cameraFrameRef = useRef(); + + const takePicture = useCallback(() => + { + const frameBounds = cameraFrameRef.current.getBoundingClientRect(); + + if(!frameBounds) return; + + const rectangle = new NitroRectangle(Math.floor(frameBounds.x), Math.floor(frameBounds.y), Math.floor(frameBounds.width), Math.floor(frameBounds.height)); + + const image = GetRoomEngine().createRoomScreenshot(GetRoomSession().roomId, 1, rectangle); + + //SendMessageHook(new RoomWidgetCameraRoomThumbnailComposer(0, [])); + onCloseClick(); + }, [ onCloseClick ]); + + return ( + +
+
+
+ + +
+
+
+ ); +}; diff --git a/src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.types.ts b/src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.types.ts new file mode 100644 index 00000000..ec49ac02 --- /dev/null +++ b/src/views/room/widgets/room-thumbnail/views/camera/RoomThumbnailWidgetCameraView.types.ts @@ -0,0 +1,4 @@ +export class RoomThumbnailWidgetCameraViewProps +{ + onCloseClick: () => void; +} From b2009d3553e10be8ef50c446eba5d6426a538035 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sat, 3 Jul 2021 22:35:48 -0300 Subject: [PATCH 11/72] Updates --- .../navigator/views/room-link/NavigatorRoomLinkView.tsx | 4 ++-- .../views/room-settings/NavigatorRoomSettingsView.tsx | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) create mode 100644 src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx diff --git a/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx b/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx index c36f9d86..cf697e19 100644 --- a/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx +++ b/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx @@ -1,3 +1,4 @@ +import { Nitro } from 'nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { GetConfiguration } from '../../../../api'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; @@ -25,8 +26,7 @@ export const NavigatorRoomLinkView: FC = props => setRoomThumbnail(GetConfiguration('image.library.url') + roomInfoData.enteredGuestRoom.officialRoomPicRef); } - const urlPrefix = GetConfiguration('url.prefix'); - const roomLinkRaw = LocalizeText('navigator.embed.src', ['roomId'], [roomInfoData.enteredGuestRoom.roomId.toString()]).replace('${url.prefix}', urlPrefix); + const roomLinkRaw = Nitro.instance.core.configuration.interpolate(LocalizeText('navigator.embed.src', ['roomId'], [roomInfoData.enteredGuestRoom.roomId.toString()])); setRoomLink(roomLinkRaw); }, [ roomInfoData ]); diff --git a/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx new file mode 100644 index 00000000..a214d88e --- /dev/null +++ b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx @@ -0,0 +1,6 @@ +import { FC } from 'react'; + +export const NavigatorRoomSettingsView: FC<{}> = props => +{ + return null; +}; From 5ca61ece5e33fd0159d0e6f0a754bbd063eada32 Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 3 Jul 2021 22:07:29 -0400 Subject: [PATCH 12/72] Add subscription to purse --- src/views/purse/PurseMessageHandler.tsx | 20 +++++++++++++++++++- src/views/purse/reducers/PurseReducer.tsx | 16 +++++++++++++--- 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/src/views/purse/PurseMessageHandler.tsx b/src/views/purse/PurseMessageHandler.tsx index 17c5ba4f..23d474e2 100644 --- a/src/views/purse/PurseMessageHandler.tsx +++ b/src/views/purse/PurseMessageHandler.tsx @@ -1,4 +1,4 @@ -import { UserCreditsEvent, UserCurrencyEvent, UserCurrencyUpdateEvent } from 'nitro-renderer'; +import { UserCreditsEvent, UserCurrencyEvent, UserCurrencyUpdateEvent, UserSubscriptionEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; import { CreateMessageHook } from '../../hooks/messages/message-event'; import { Currency } from './common/Currency'; @@ -48,9 +48,27 @@ export const PurseMessageHandler: FC = props => }); }, [ dispatchPurseState ]); + const onUserSubscriptionEvent = useCallback((event: UserSubscriptionEvent) => + { + const parser = event.getParser(); + + switch(parser.name) + { + case 'habbo_club': + dispatchPurseState({ + type: PurseActions.SET_CLUB_SUBSCRIPTION, + payload: { + clubSubscription: parser + } + }); + return; + } + }, [ dispatchPurseState ]); + CreateMessageHook(UserCreditsEvent, onUserCreditsEvent); CreateMessageHook(UserCurrencyEvent, onUserCurrencyEvent); CreateMessageHook(UserCurrencyUpdateEvent, onUserCurrencyUpdateEvent); + CreateMessageHook(UserSubscriptionEvent, onUserSubscriptionEvent); return null; } diff --git a/src/views/purse/reducers/PurseReducer.tsx b/src/views/purse/reducers/PurseReducer.tsx index 1a84005f..3e9d5f5b 100644 --- a/src/views/purse/reducers/PurseReducer.tsx +++ b/src/views/purse/reducers/PurseReducer.tsx @@ -1,9 +1,11 @@ +import { UserSubscriptionParser } from 'nitro-renderer'; import { Reducer } from 'react'; import { Currency } from '../common/Currency'; export interface IPurseState { currencies: Currency[]; + clubSubscription: UserSubscriptionParser; } export interface IPurseAction @@ -12,6 +14,7 @@ export interface IPurseAction payload: { currency?: Currency; currencies?: Currency[]; + clubSubscription?: UserSubscriptionParser; } } @@ -19,10 +22,12 @@ export class PurseActions { public static SET_CURRENCY: string = 'PA_SET_CURRENCY'; public static SET_CURRENCIES: string = 'PA_SET_CURRENCIES'; + public static SET_CLUB_SUBSCRIPTION: string = 'PA_SET_CLUB_SUBSCRIPTION'; } export const initialPurse: IPurseState = { - currencies: [] + currencies: [], + clubSubscription: null } export const PurseReducer: Reducer = (state, action) => @@ -34,7 +39,7 @@ export const PurseReducer: Reducer = (state, action) let didSet = false; - const currencies = state.currencies.map((existing, index) => + const currencies = state.currencies.map(existing => { if(existing.type !== updated.type) return existing; @@ -50,7 +55,7 @@ export const PurseReducer: Reducer = (state, action) case PurseActions.SET_CURRENCIES: { const updated = action.payload.currencies; - const currencies = state.currencies.filter((existing, index) => + const currencies = state.currencies.filter(existing => { if(existing.type !== -1) return null; @@ -61,6 +66,11 @@ export const PurseReducer: Reducer = (state, action) return { ...state, currencies }; } + case PurseActions.SET_CLUB_SUBSCRIPTION: { + const clubSubscription = action.payload.clubSubscription; + + return { ...state, clubSubscription }; + } default: return state; } From 5fa79d6420542de0e3ab9a84e8a24a5fc0d89219 Mon Sep 17 00:00:00 2001 From: MyNameIsBatman Date: Sat, 3 Jul 2021 23:09:33 -0300 Subject: [PATCH 13/72] Engranving header --- .../furniture/engraving-lock/FurnitureEngravingLockView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.tsx b/src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.tsx index 80e87d07..b3df1687 100644 --- a/src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.tsx +++ b/src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.tsx @@ -104,7 +104,7 @@ export const FurnitureEngravingLockView: FC = p return ( <> - { engravingStage > 0 && + { engravingStage > 0 && processAction('close_request') } />
From 28060820b594b65baea3d83ee783248acbb16846 Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 3 Jul 2021 22:14:49 -0400 Subject: [PATCH 14/72] Update some maps --- src/views/catalog/CatalogView.tsx | 4 ++-- .../catalog/views/navigation/set/CatalogNavigationSetView.tsx | 4 ++-- .../badge/active-results/InventoryActiveBadgeResultsView.tsx | 4 ++-- .../views/badge/results/InventoryBadgeResultsView.tsx | 4 ++-- .../inventory/views/bot/results/InventoryBotResultsView.tsx | 4 ++-- .../inventory/views/pet/results/InventoryPetResultsView.tsx | 4 ++-- .../room/widgets/furniture/stickie/FurnitureStickieView.tsx | 4 ++-- .../widgets/infostand/views/bot/InfoStandWidgetBotView.tsx | 4 ++-- .../views/rentable-bot/InfoStandWidgetRentableBotView.tsx | 4 ++-- .../actor-has-hand-item/WiredConditionActorHasHandItem.tsx | 4 ++-- .../WiredConditionActorIsTeamMemberView.tsx | 4 ++-- 11 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/views/catalog/CatalogView.tsx b/src/views/catalog/CatalogView.tsx index 4ee80c6a..cbe8faab 100644 --- a/src/views/catalog/CatalogView.tsx +++ b/src/views/catalog/CatalogView.tsx @@ -93,10 +93,10 @@ export const CatalogView: FC = props => setIsVisible(false) } /> - { root && root.children.length && root.children.map((page, index) => + { root && root.children.length && root.children.map(page => { return ( - setCurrentTab(page) }> + setCurrentTab(page) }> { page.localization } ); diff --git a/src/views/catalog/views/navigation/set/CatalogNavigationSetView.tsx b/src/views/catalog/views/navigation/set/CatalogNavigationSetView.tsx index 32a8ec30..32d5e54d 100644 --- a/src/views/catalog/views/navigation/set/CatalogNavigationSetView.tsx +++ b/src/views/catalog/views/navigation/set/CatalogNavigationSetView.tsx @@ -35,11 +35,11 @@ export const CatalogNavigationSetView: FC = props return (
- { page && (page.children.length > 0) && page.children.map((page, index) => + { page && (page.children.length > 0) && page.children.map(page => { if(!page.visible) return null; - return + return }) }
); diff --git a/src/views/inventory/views/badge/active-results/InventoryActiveBadgeResultsView.tsx b/src/views/inventory/views/badge/active-results/InventoryActiveBadgeResultsView.tsx index d8f970af..75f3785d 100644 --- a/src/views/inventory/views/badge/active-results/InventoryActiveBadgeResultsView.tsx +++ b/src/views/inventory/views/badge/active-results/InventoryActiveBadgeResultsView.tsx @@ -8,9 +8,9 @@ export const InventoryActiveBadgeResultsView: FC - { badges && (badges.length > 0) && badges.map((code, index) => + { badges && (badges.length > 0) && badges.map(code => { - return + return }) }
); diff --git a/src/views/inventory/views/badge/results/InventoryBadgeResultsView.tsx b/src/views/inventory/views/badge/results/InventoryBadgeResultsView.tsx index d563979b..66215373 100644 --- a/src/views/inventory/views/badge/results/InventoryBadgeResultsView.tsx +++ b/src/views/inventory/views/badge/results/InventoryBadgeResultsView.tsx @@ -9,11 +9,11 @@ export const InventoryBadgeResultsView: FC = pro return (
- { badges && (badges.length > 0) && badges.map((code, index) => + { badges && (badges.length > 0) && badges.map(code => { if(activeBadges.indexOf(code) >= 0) return null; - return + return }) }
diff --git a/src/views/inventory/views/bot/results/InventoryBotResultsView.tsx b/src/views/inventory/views/bot/results/InventoryBotResultsView.tsx index 05e044fb..477c7bb4 100644 --- a/src/views/inventory/views/bot/results/InventoryBotResultsView.tsx +++ b/src/views/inventory/views/bot/results/InventoryBotResultsView.tsx @@ -9,9 +9,9 @@ export const InventoryBotResultsView: FC = props = return (
- { botItems && (botItems.length > 0) && botItems.map((item, index) => + { botItems && (botItems.length > 0) && botItems.map(item => { - return + return }) }
diff --git a/src/views/inventory/views/pet/results/InventoryPetResultsView.tsx b/src/views/inventory/views/pet/results/InventoryPetResultsView.tsx index 03fc893e..21e99114 100644 --- a/src/views/inventory/views/pet/results/InventoryPetResultsView.tsx +++ b/src/views/inventory/views/pet/results/InventoryPetResultsView.tsx @@ -9,9 +9,9 @@ export const InventoryPetResultsView: FC = props = return (
- { petItems && (petItems.length > 0) && petItems.map((item, index) => + { petItems && (petItems.length > 0) && petItems.map(item => { - return + return }) }
diff --git a/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx b/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx index 2c1a7a97..3a34020b 100644 --- a/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx +++ b/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx @@ -122,9 +122,9 @@ export const FurnitureStickieView: FC = props => { stickieData.canModify && <>
processAction('trash') }>
- { STICKIE_COLORS.map((color, index) => + { STICKIE_COLORS.map(color => { - return
processAction('changeColor', color) } style={ {backgroundColor: ColorUtils.makeColorHex(color) } } /> + return
processAction('changeColor', color) } style={ {backgroundColor: ColorUtils.makeColorHex(color) } } /> })} }
diff --git a/src/views/room/widgets/infostand/views/bot/InfoStandWidgetBotView.tsx b/src/views/room/widgets/infostand/views/bot/InfoStandWidgetBotView.tsx index 45c2eb20..dedf8822 100644 --- a/src/views/room/widgets/infostand/views/bot/InfoStandWidgetBotView.tsx +++ b/src/views/room/widgets/infostand/views/bot/InfoStandWidgetBotView.tsx @@ -24,9 +24,9 @@ export const InfoStandWidgetBotView: FC = props =>
- { (botData.badges.length > 0) && botData.badges.map((result, index) => + { (botData.badges.length > 0) && botData.badges.map(result => { - return ; + return ; }) }
diff --git a/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx b/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx index 258840ef..a25fc8d3 100644 --- a/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx +++ b/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx @@ -36,9 +36,9 @@ export const InfoStandWidgetRentableBotView: FC
- { (rentableBotData.badges.length > 0) && rentableBotData.badges.map((result, index) => + { (rentableBotData.badges.length > 0) && rentableBotData.badges.map(result => { - return ; + return ; }) }
diff --git a/src/views/wired/views/conditions/actor-has-hand-item/WiredConditionActorHasHandItem.tsx b/src/views/wired/views/conditions/actor-has-hand-item/WiredConditionActorHasHandItem.tsx index fe4aefe3..368b3114 100644 --- a/src/views/wired/views/conditions/actor-has-hand-item/WiredConditionActorHasHandItem.tsx +++ b/src/views/wired/views/conditions/actor-has-hand-item/WiredConditionActorHasHandItem.tsx @@ -26,9 +26,9 @@ export const WiredConditionActorHasHandItemView: FC<{}> = props =>
diff --git a/src/views/wired/views/conditions/actor-is-team-member/WiredConditionActorIsTeamMemberView.tsx b/src/views/wired/views/conditions/actor-is-team-member/WiredConditionActorIsTeamMemberView.tsx index 851088a3..b616db4b 100644 --- a/src/views/wired/views/conditions/actor-is-team-member/WiredConditionActorIsTeamMemberView.tsx +++ b/src/views/wired/views/conditions/actor-is-team-member/WiredConditionActorIsTeamMemberView.tsx @@ -25,10 +25,10 @@ export const WiredConditionActorIsTeamMemberView: FC<{}> = props =>
- { teamIds.map((value, index) => + { teamIds.map(value => { return ( -
+
setSelectedTeam(value) } />
{ roomInfoData.enteredGuestRoom.description }
- + processAction('open_room_thumbnail_camera') } /> { roomThumbnail && }
{ roomInfoData.enteredGuestRoom.habboGroupId > 0 &&
processAction('open_group_info') }> @@ -130,7 +135,7 @@ export const NavigatorRoomInfoView: FC = props => { LocalizeText('navigator.embed.caption') }
- + diff --git a/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.scss b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.scss new file mode 100644 index 00000000..ac5adf97 --- /dev/null +++ b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.scss @@ -0,0 +1,3 @@ +.nitro-room-settings { + width: 400px; +} diff --git a/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx index a214d88e..c9fe09a0 100644 --- a/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx +++ b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.tsx @@ -1,6 +1,127 @@ -import { FC } from 'react'; +import { RoomSettingsEvent, SaveRoomSettingsComposer } from 'nitro-renderer'; +import { FC, useCallback, useState } from 'react'; +import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../../../layout'; +import { LocalizeText } from '../../../../utils/LocalizeText'; +import RoomSettingsData from '../../common/RoomSettingsData'; +import { NavigatorRoomSettingsAccessTabView } from './views/tab-access/NavigatorRoomSettingsAccessTabView'; +import { NavigatorRoomSettingsBasicTabView } from './views/tab-basic/NavigatorRoomSettingsBasicTabView'; + +const TABS: string[] = [ + 'navigator.roomsettings.tab.1', + 'navigator.roomsettings.tab.2', + 'navigator.roomsettings.tab.3', + 'navigator.roomsettings.tab.4', + 'navigator.roomsettings.tab.5' +]; export const NavigatorRoomSettingsView: FC<{}> = props => { - return null; + const [ roomSettingsData, setRoomSettingsData ] = useState(null); + const [ currentTab, setCurrentTab ] = useState(TABS[0]); + + const updateSettings = useCallback((roomSettings: RoomSettingsData) => + { + console.log('update', roomSettings); + setRoomSettingsData(roomSettings); + }, [ setRoomSettingsData ]); + + const onRoomSettingsEvent = useCallback((event: RoomSettingsEvent) => + { + const parser = event.getParser(); + + const roomSettingsData = new RoomSettingsData(); + + roomSettingsData.roomId = parser.roomId; + roomSettingsData.roomName = parser.name; + roomSettingsData.roomOriginalName = parser.name; + roomSettingsData.roomDescription = parser.description; + roomSettingsData.categoryId = parser.categoryId; + roomSettingsData.userCount = parser.userCount; + roomSettingsData.tradeState = parser.tradeMode; + roomSettingsData.allowWalkthrough = parser.allowWalkthrough; + + roomSettingsData.lockState = parser.state; + roomSettingsData.originalLockState = parser.state; + roomSettingsData.allowPets = parser.allowPets; + + roomSettingsData.hideWalls = parser.hideWalls; + roomSettingsData.wallThickness = parser.thicknessWall; + roomSettingsData.floorThickness = parser.thicknessFloor; + roomSettingsData.chatBubbleMode = parser.chatSettings.mode; + roomSettingsData.chatBubbleWeight = parser.chatSettings.weight; + roomSettingsData.chatBubbleSpeed = parser.chatSettings.speed; + roomSettingsData.chatFloodProtection = parser.chatSettings.protection; + roomSettingsData.chatDistance = parser.chatSettings.distance; + + roomSettingsData.muteState = parser.moderationSettings.allowMute; + roomSettingsData.kickState = parser.moderationSettings.allowKick; + roomSettingsData.banState = parser.moderationSettings.allowBan; + + setRoomSettingsData(roomSettingsData); + }, []); + + CreateMessageHook(RoomSettingsEvent, onRoomSettingsEvent); + + const save = useCallback(() => + { + console.log('save', roomSettingsData) + const composer = new SaveRoomSettingsComposer( + roomSettingsData.roomId, + roomSettingsData.roomName, + roomSettingsData.roomDescription, + roomSettingsData.lockState, + roomSettingsData.password, + roomSettingsData.userCount, + roomSettingsData.categoryId, + roomSettingsData.tags.length, + roomSettingsData.tags, + roomSettingsData.tradeState, + roomSettingsData.allowPets, + roomSettingsData.allowPetsEat, + roomSettingsData.allowWalkthrough, + roomSettingsData.hideWalls, + roomSettingsData.wallThickness, + roomSettingsData.floorThickness, + roomSettingsData.muteState, + roomSettingsData.kickState, + roomSettingsData.banState, + roomSettingsData.chatBubbleMode, + roomSettingsData.chatBubbleWeight, + roomSettingsData.chatBubbleSpeed, + roomSettingsData.chatDistance, + roomSettingsData.chatFloodProtection + ); + + SendMessageHook(composer); + }, [ roomSettingsData ]); + + const processAction = useCallback((action: string) => + { + switch(action) + { + case 'close': + setRoomSettingsData(null); + setCurrentTab(TABS[0]); + return; + } + }, [ setRoomSettingsData ]); + + if(!roomSettingsData) return null; + + return ( + + processAction('close') } /> + + { TABS.map(tab => + { + return setCurrentTab(tab) }>{ LocalizeText(tab) } + }) } + + + { currentTab === TABS[0] && } + { currentTab === TABS[1] && } + + + ); }; diff --git a/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.types.ts b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.types.ts new file mode 100644 index 00000000..52eded57 --- /dev/null +++ b/src/views/navigator/views/room-settings/NavigatorRoomSettingsView.types.ts @@ -0,0 +1,8 @@ +import RoomSettingsData from '../../common/RoomSettingsData'; + +export class NavigatorRoomSettingsTabViewProps +{ + roomSettingsData: RoomSettingsData; + setRoomSettingsData: (roomSettings: RoomSettingsData) => void; + onSave: () => void; +} diff --git a/src/views/navigator/views/room-settings/views/tab-access/NavigatorRoomSettingsAccessTabView.tsx b/src/views/navigator/views/room-settings/views/tab-access/NavigatorRoomSettingsAccessTabView.tsx new file mode 100644 index 00000000..579f2e55 --- /dev/null +++ b/src/views/navigator/views/room-settings/views/tab-access/NavigatorRoomSettingsAccessTabView.tsx @@ -0,0 +1,96 @@ +import { FC, useCallback } from 'react'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import RoomSettingsData from '../../../../common/RoomSettingsData'; +import { NavigatorRoomSettingsTabViewProps } from '../../NavigatorRoomSettingsView.types'; + +export const NavigatorRoomSettingsAccessTabView: FC = props => +{ + const { roomSettingsData = null, setRoomSettingsData = null, onSave = null } = props; + + const handleChange = useCallback((field: string, value: string | number | boolean) => + { + const roomSettings = ({...roomSettingsData} as RoomSettingsData); + let save = true; + + switch(field) + { + case 'lock_state': + roomSettings.lockState = Number(value); + + if(Number(value) === 3) save = false; + break; + case 'password': + roomSettings.password = String(value); + save = false; + break; + case 'confirm_password': + roomSettings.confirmPassword = String(value); + save = false; + break; + case 'allow_pets': + roomSettings.allowPets = Boolean(value); + break; + case 'allow_pets_eat': + roomSettings.allowPetsEat = Boolean(value); + break; + } + + setRoomSettingsData(roomSettings); + + if(save) onSave(); + }, [ roomSettingsData, setRoomSettingsData, onSave ]); + + const isPasswordValid = useCallback(() => + { + return (roomSettingsData.password && roomSettingsData.password.length > 0 && roomSettingsData.password === roomSettingsData.confirmPassword); + }, [ roomSettingsData ]); + + const trySave = useCallback(() => + { + if(isPasswordValid()) onSave(); + }, [ isPasswordValid, onSave ]); + + return ( + <> +
{ LocalizeText('navigator.roomsettings.doormode') }
+
+ handleChange('lock_state', 0) } /> + +
+
+ handleChange('lock_state', 1) } /> + +
+
+ handleChange('lock_state', 2) } /> + +
+
+ handleChange('lock_state', 3) } /> + +
+ { roomSettingsData.lockState === 3 && <> +
+ + handleChange('password', e.target.value) } onBlur={ trySave } placeholder="*****" /> +
+
+ + handleChange('confirm_password', e.target.value) } onBlur={ trySave } placeholder="*****" /> + { !isPasswordValid() && + { LocalizeText('navigator.roomsettings.invalidconfirm') } + } +
+ } +
{ LocalizeText('navigator.roomsettings.pets') }
+
+ handleChange('allow_pets', e.target.checked) } /> + +
+
+ handleChange('allow_pets_eat', e.target.checked) } /> + +
+ + ); +}; diff --git a/src/views/navigator/views/room-settings/views/tab-basic/NavigatorRoomSettingsBasicTabView.tsx b/src/views/navigator/views/room-settings/views/tab-basic/NavigatorRoomSettingsBasicTabView.tsx new file mode 100644 index 00000000..1a362e82 --- /dev/null +++ b/src/views/navigator/views/room-settings/views/tab-basic/NavigatorRoomSettingsBasicTabView.tsx @@ -0,0 +1,107 @@ +import { FC, useCallback, useEffect, useState } from 'react'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import RoomSettingsData from '../../../../common/RoomSettingsData'; +import { useNavigatorContext } from '../../../../context/NavigatorContext'; +import { NavigatorRoomSettingsTabViewProps } from '../../NavigatorRoomSettingsView.types'; + +export const NavigatorRoomSettingsBasicTabView: FC = props => +{ + const { roomSettingsData = null, setRoomSettingsData = null, onSave = null } = props; + + const { navigatorState = null } = useNavigatorContext(); + const { categories = null } = navigatorState; + + const [ maxVisitorsList, setMaxVisitorsList ] = useState(null); + + useEffect(() => + { + if(!maxVisitorsList) + { + const list = []; + + for(let i = 10; i <= 100; i = i + 10) + { + list.push(i); + } + + setMaxVisitorsList(list); + } + }, [ maxVisitorsList ]); + + const handleChange = useCallback((field: string, value: string | number | boolean) => + { + const roomSettings = ({...roomSettingsData} as RoomSettingsData); + let save = true; + + switch(field) + { + case 'name': + roomSettings.roomName = String(value); + save = false; + break; + case 'description': + roomSettings.roomDescription = String(value); + save = false; + break; + case 'category': + roomSettings.categoryId = Number(value); + break; + case 'max_visitors': + roomSettings.userCount = Number(value); + break; + case 'trade_state': + roomSettings.tradeState = Number(value); + break; + case 'allow_walkthrough': + roomSettings.allowWalkthrough = Boolean(value); + break; + } + + setRoomSettingsData(roomSettings); + + if(save) onSave(); + }, [ roomSettingsData, setRoomSettingsData, onSave ]); + + return ( + <> +
+ + handleChange('name', e.target.value) } onBlur={ onSave } /> +
+
+ + handleChange('description', e.target.value) } onBlur={ () => onSave() } /> +
+
+ + +
+
+ + +
+
+ + +
+
+ handleChange('allow_walkthrough', e.target.checked) } /> + +
+ + ); +}; diff --git a/src/views/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx b/src/views/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx index 90d7fb63..29b94fed 100644 --- a/src/views/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx +++ b/src/views/room/widgets/room-thumbnail/RoomThumbnailWidgetView.tsx @@ -1,4 +1,6 @@ import { FC, useCallback, useState } from 'react'; +import { RoomWidgetThumbnailEvent } from '../../../../events/room-widgets/thumbnail'; +import { useUiEvent } from '../../../../hooks/events'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { RoomThumbnailWidgetViewProps } from './RoomThumbnailView.types'; @@ -11,6 +13,30 @@ export const RoomThumbnailWidgetView: FC = props = const [ isBuilderVisible, setIsBuilderVisible ] = useState(false); const [ isCameraVisible, setIsCameraVisible ] = useState(false); + const onNitroEvent = useCallback((event: RoomWidgetThumbnailEvent) => + { + switch(event.type) + { + case RoomWidgetThumbnailEvent.SHOW_THUMBNAIL: + setIsSelectorVisible(true); + return; + case RoomWidgetThumbnailEvent.HIDE_THUMBNAIL: + setIsSelectorVisible(false); + setIsBuilderVisible(false); + setIsCameraVisible(false); + return; + case RoomWidgetThumbnailEvent.TOGGLE_THUMBNAIL: + setIsSelectorVisible(value => !value); + setIsBuilderVisible(false); + setIsCameraVisible(false); + return; + } + }, []); + + useUiEvent(RoomWidgetThumbnailEvent.SHOW_THUMBNAIL, onNitroEvent); + useUiEvent(RoomWidgetThumbnailEvent.HIDE_THUMBNAIL, onNitroEvent); + useUiEvent(RoomWidgetThumbnailEvent.TOGGLE_THUMBNAIL, onNitroEvent); + const handleAction = useCallback((action: string) => { switch(action) From 86233806f29616505dceb46dc7528a6b78e7be26 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 5 Jul 2021 02:46:47 -0400 Subject: [PATCH 23/72] Trade updates --- src/assets/styles/utils.scss | 4 + .../inventory/InventoryTradeRequestEvent.ts | 27 ++++ .../inventory/InventoryTradeStartEvent.ts | 28 ++++ src/events/inventory/index.ts | 2 + .../inventory/InventoryMessageHandler.tsx | 117 ++++++++++++++- src/views/inventory/InventoryView.scss | 2 +- src/views/inventory/InventoryView.tsx | 31 +++- src/views/inventory/common/FurnitureItem.ts | 42 +++--- .../inventory/common/FurnitureUtilities.ts | 2 +- src/views/inventory/common/GroupItem.ts | 56 +++++-- src/views/inventory/common/TradeState.ts | 10 ++ src/views/inventory/common/TradeUserData.ts | 15 ++ .../inventory/common/TradingUtilities.ts | 73 +++++++++ .../reducers/InventoryFurnitureReducer.tsx | 139 +++++++++++++++++- .../furniture/InventoryFurnitureView.tsx | 125 ++++++++++++++-- .../item/InventoryFurnitureItemView.tsx | 3 +- .../results/InventoryFurnitureResultsView.tsx | 2 +- .../views/trade/InventoryTradeView.tsx | 37 +++++ .../views/trade/InventoryTradeView.types.ts | 4 + .../trade/item/InventoryTradeItemView.tsx | 37 +++++ .../item/InventoryTradeItemView.types.ts | 6 + src/views/purse/PurseView.tsx | 4 +- .../handlers/RoomWidgetInfostandHandler.ts | 4 +- 23 files changed, 709 insertions(+), 61 deletions(-) create mode 100644 src/events/inventory/InventoryTradeRequestEvent.ts create mode 100644 src/events/inventory/InventoryTradeStartEvent.ts create mode 100644 src/views/inventory/common/TradeState.ts create mode 100644 src/views/inventory/common/TradeUserData.ts create mode 100644 src/views/inventory/common/TradingUtilities.ts create mode 100644 src/views/inventory/views/trade/InventoryTradeView.tsx create mode 100644 src/views/inventory/views/trade/InventoryTradeView.types.ts create mode 100644 src/views/inventory/views/trade/item/InventoryTradeItemView.tsx create mode 100644 src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts diff --git a/src/assets/styles/utils.scss b/src/assets/styles/utils.scss index 69ce07fc..c2a43bac 100644 --- a/src/assets/styles/utils.scss +++ b/src/assets/styles/utils.scss @@ -14,6 +14,10 @@ transform: scale(2) translateZ(0); } +.opacity-0-5 { + opacity: 0.5; +} + .text-shadow { text-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); } diff --git a/src/events/inventory/InventoryTradeRequestEvent.ts b/src/events/inventory/InventoryTradeRequestEvent.ts new file mode 100644 index 00000000..8cc0ee9f --- /dev/null +++ b/src/events/inventory/InventoryTradeRequestEvent.ts @@ -0,0 +1,27 @@ +import { InventoryEvent } from './InventoryEvent'; + +export class InventoryTradeRequestEvent extends InventoryEvent +{ + public static REQUEST_TRADE: string = 'ITSE_REQUEST_TRADE'; + + private _objectId: number; + private _username: string; + + constructor(objectId: number, username: string) + { + super(InventoryTradeRequestEvent.REQUEST_TRADE); + + this._objectId = objectId; + this._username = username; + } + + public get objectId(): number + { + return this._objectId; + } + + public get username(): string + { + return this._username; + } +} diff --git a/src/events/inventory/InventoryTradeStartEvent.ts b/src/events/inventory/InventoryTradeStartEvent.ts new file mode 100644 index 00000000..1724979d --- /dev/null +++ b/src/events/inventory/InventoryTradeStartEvent.ts @@ -0,0 +1,28 @@ +import { TradeUserData } from '../../views/inventory/common/TradeUserData'; +import { InventoryEvent } from './InventoryEvent'; + +export class InventoryTradeStartEvent extends InventoryEvent +{ + public static START_TRADE: string = 'ITSE_START_TRADE'; + + private _ownUserTradeData: TradeUserData; + private _otherUserTradeData: TradeUserData; + + constructor(ownUserTradeData: TradeUserData, otherUserTradeData: TradeUserData) + { + super(InventoryTradeStartEvent.START_TRADE); + + this._ownUserTradeData = ownUserTradeData; + this._otherUserTradeData = otherUserTradeData; + } + + public get ownUserTradeData(): TradeUserData + { + return this._ownUserTradeData; + } + + public get otherUserTradeData(): TradeUserData + { + return this._otherUserTradeData; + } +} diff --git a/src/events/inventory/index.ts b/src/events/inventory/index.ts index 6b5cf8e6..e795837f 100644 --- a/src/events/inventory/index.ts +++ b/src/events/inventory/index.ts @@ -1 +1,3 @@ export * from './InventoryEvent'; +export * from './InventoryTradeRequestEvent'; +export * from './InventoryTradeStartEvent'; diff --git a/src/views/inventory/InventoryMessageHandler.tsx b/src/views/inventory/InventoryMessageHandler.tsx index af4e8eba..d28f0edf 100644 --- a/src/views/inventory/InventoryMessageHandler.tsx +++ b/src/views/inventory/InventoryMessageHandler.tsx @@ -1,15 +1,17 @@ -import { BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory } from 'nitro-renderer'; +import { AdvancedMap, BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory, TradingAcceptEvent, TradingCloseEvent, TradingCompletedEvent, TradingConfirmationEvent, TradingListItemEvent, TradingOpenEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; +import { GetRoomSession, GetSessionDataManager } from '../../api'; import { CreateMessageHook } from '../../hooks/messages/message-event'; import { mergeFurniFragments } from './common/FurnitureUtilities'; import { mergePetFragments } from './common/PetUtilities'; +import { TradeState } from './common/TradeState'; +import { TradeUserData } from './common/TradeUserData'; import { useInventoryContext } from './context/InventoryContext'; import { InventoryMessageHandlerProps } from './InventoryMessageHandler.types'; import { InventoryBadgeActions } from './reducers/InventoryBadgeReducer'; import { InventoryBotActions } from './reducers/InventoryBotReducer'; import { InventoryFurnitureActions } from './reducers/InventoryFurnitureReducer'; import { InventoryPetActions } from './reducers/InventoryPetReducer'; - let furniMsgFragments: Map[] = null; let petMsgFragments: Map[] = null; @@ -161,6 +163,111 @@ export const InventoryMessageHandler: FC = props = }); }, [ dispatchBadgeState ]); + const onTradingAcceptEvent = useCallback((event: TradingAcceptEvent) => + { + const parser = event.getParser(); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_TRADE_ACCEPTANCE, + payload: { + userId: parser.userID, + flag: parser.userAccepts + } + }); + }, [ dispatchFurnitureState ]); + + const onTradingOpenEvent = useCallback((event: TradingOpenEvent) => + { + const parser = event.getParser(); + + const ownUser = new TradeUserData(); + const otherUser = new TradeUserData(); + + ownUser.userItems = new AdvancedMap(); + otherUser.userItems = new AdvancedMap(); + + const userDataOne = GetRoomSession().userDataManager.getUserData(parser.userID); + const userDataTwo = GetRoomSession().userDataManager.getUserData(parser.otherUserID); + + if(userDataOne.webID === GetSessionDataManager().userId) + { + ownUser.userId = userDataOne.webID; + ownUser.userName = userDataOne.name; + ownUser.canTrade = parser.userCanTrade; + + otherUser.userId = userDataTwo.webID; + otherUser.userName = userDataTwo.name; + otherUser.canTrade = parser.otherUserCanTrade; + } + + else if(userDataTwo.webID === GetSessionDataManager().userId) + { + ownUser.userId = userDataTwo.webID; + ownUser.userName = userDataTwo.name; + ownUser.canTrade = parser.otherUserCanTrade; + + otherUser.userId = userDataOne.webID; + otherUser.userName = userDataOne.name; + otherUser.canTrade = parser.userCanTrade; + } + + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_TRADE_DATA, + payload: { + ownTradeUser: ownUser, + otherTradeUser: otherUser + } + }); + }, [ dispatchFurnitureState ]); + + const onTradingCloseEvent = useCallback((event: TradingCloseEvent) => + { + const parser = event.getParser(); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.CLOSE_TRADE, + payload: {} + }); + }, [ dispatchFurnitureState ]); + + const onTradingCompletedEvent = useCallback((event: TradingCompletedEvent) => + { + const parser = event.getParser(); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_TRADE_STATE, + payload: { + tradeState: TradeState.TRADING_STATE_COMPLETED + } + }); + }, [ dispatchFurnitureState ]); + + const onTradingConfirmationEvent = useCallback((event: TradingConfirmationEvent) => + { + const parser = event.getParser(); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_TRADE_STATE, + payload: { + tradeState: TradeState.TRADING_STATE_CONFIRMED + } + }); + }, [ dispatchFurnitureState ]); + + const onTradingListItemEvent = useCallback((event: TradingListItemEvent) => + { + const parser = event.getParser(); + + console.log(parser); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.UPDATE_TRADE, + payload: { + tradeParser: event.getParser() + } + }); + }, [ dispatchFurnitureState ]); + CreateMessageHook(FurnitureListAddOrUpdateEvent, onFurnitureListAddOrUpdateEvent); CreateMessageHook(FurnitureListEvent, onFurnitureListEvent); CreateMessageHook(FurnitureListInvalidateEvent, onFurnitureListInvalidateEvent); @@ -173,6 +280,12 @@ export const InventoryMessageHandler: FC = props = CreateMessageHook(PetRemovedFromInventory, onPetRemovedFromInventory); CreateMessageHook(PetAddedToInventoryEvent, onPetAddedToInventoryEvent); CreateMessageHook(BadgesEvent, onBadgesEvent); + CreateMessageHook(TradingAcceptEvent, onTradingAcceptEvent); + CreateMessageHook(TradingOpenEvent, onTradingOpenEvent); + CreateMessageHook(TradingCloseEvent, onTradingCloseEvent); + CreateMessageHook(TradingCompletedEvent, onTradingCompletedEvent); + CreateMessageHook(TradingConfirmationEvent, onTradingConfirmationEvent); + CreateMessageHook(TradingListItemEvent, onTradingListItemEvent); return null; } diff --git a/src/views/inventory/InventoryView.scss b/src/views/inventory/InventoryView.scss index 66c21ce4..4363c1d0 100644 --- a/src/views/inventory/InventoryView.scss +++ b/src/views/inventory/InventoryView.scss @@ -6,7 +6,7 @@ height: 240px; max-height: 430px; resize: vertical; - overflow:auto; + overflow: auto; } .empty-image { diff --git a/src/views/inventory/InventoryView.tsx b/src/views/inventory/InventoryView.tsx index a1ba407e..04f65231 100644 --- a/src/views/inventory/InventoryView.tsx +++ b/src/views/inventory/InventoryView.tsx @@ -1,7 +1,7 @@ -import { IRoomSession, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent } from 'nitro-renderer'; +import { IRoomSession, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent, TradingOpenComposer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; -import { GetRoomEngine } from '../../api'; -import { InventoryEvent } from '../../events'; +import { GetConnection, GetRoomEngine } from '../../api'; +import { InventoryEvent, InventoryTradeRequestEvent } from '../../events'; import { useRoomEngineEvent } from '../../hooks/events/nitro/room/room-engine-event'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; import { useUiEvent } from '../../hooks/events/ui/ui-event'; @@ -19,11 +19,12 @@ import { InventoryBadgeView } from './views/badge/InventoryBadgeView'; import { InventoryBotView } from './views/bot/InventoryBotView'; import { InventoryFurnitureView } from './views/furniture/InventoryFurnitureView'; import { InventoryPetView } from './views/pet/InventoryPetView'; +import { InventoryTradeView } from './views/trade/InventoryTradeView'; + +const tabs = [ InventoryTabs.FURNITURE, InventoryTabs.BOTS, InventoryTabs.PETS, InventoryTabs.BADGES ]; export const InventoryView: FC = props => { - const tabs = [ InventoryTabs.FURNITURE, InventoryTabs.BOTS, InventoryTabs.PETS, InventoryTabs.BADGES ]; - const [ isVisible, setIsVisible ] = useState(false); const [ currentTab, setCurrentTab ] = useState(tabs[0]); const [ roomSession, setRoomSession ] = useState(null); @@ -46,12 +47,18 @@ export const InventoryView: FC = props => case InventoryEvent.TOGGLE_INVENTORY: setIsVisible(value => !value); return; + case InventoryTradeRequestEvent.REQUEST_TRADE: { + const tradeEvent = (event as InventoryTradeRequestEvent); + + GetConnection().send(new TradingOpenComposer(tradeEvent.objectId)); + } } }, []); useUiEvent(InventoryEvent.SHOW_INVENTORY, onInventoryEvent); useUiEvent(InventoryEvent.HIDE_INVENTORY, onInventoryEvent); useUiEvent(InventoryEvent.TOGGLE_INVENTORY, onInventoryEvent); + useUiEvent(InventoryTradeRequestEvent.REQUEST_TRADE, onInventoryEvent); const onRoomEngineObjectPlacedEvent = useCallback((event: RoomEngineObjectPlacedEvent) => { @@ -96,6 +103,19 @@ export const InventoryView: FC = props => } }, []); + useEffect(() => + { + if(!isVisible) + { + if(furnitureState.tradeData) + { + setIsVisible(true); + + if(currentTab !== InventoryTabs.FURNITURE) setCurrentTab(InventoryTabs.FURNITURE); + } + } + }, [ furnitureState.tradeData, isVisible, currentTab ]); + return ( @@ -121,6 +141,7 @@ export const InventoryView: FC = props => } { (currentTab === InventoryTabs.BADGES ) && } + { furnitureState.tradeData && } } diff --git a/src/views/inventory/common/FurnitureItem.ts b/src/views/inventory/common/FurnitureItem.ts index 702b46c3..e063c9f0 100644 --- a/src/views/inventory/common/FurnitureItem.ts +++ b/src/views/inventory/common/FurnitureItem.ts @@ -28,6 +28,8 @@ export class FurnitureItem implements IFurnitureItem constructor(parser: IFurnitureItemData) { + if(!parser) return; + this._locked = false; this._id = parser.itemId; this._type = parser.spriteId; @@ -189,26 +191,26 @@ export class FurnitureItem implements IFurnitureItem public update(parser: IFurnitureItemData): void { - this._type = parser.spriteId; - this._ref = parser.ref; - this._category = parser.category; - this._groupable = (parser.isGroupable && !parser.rentable); - this._tradeable = parser.tradable; - this._recyclable = parser.isRecycleable; - this._sellable = parser.sellable; - this._stuffData = parser.stuffData; - this._extra = parser.extra; - this._secondsToExpiration = parser.secondsToExpiration; - this._expirationTimeStamp = parser.expirationTimeStamp; - this._hasRentPeriodStarted = parser.hasRentPeriodStarted; - this._creationDay = parser.creationDay; - this._creationMonth = parser.creationMonth; - this._creationYear = parser.creationYear; - this._slotId = parser.slotId; - this._songId = parser.songId; - this._flatId = parser.flatId; - this._isRented = parser.rentable; - this._isWallItem = parser.isWallItem; + this._type = parser.spriteId; + this._ref = parser.ref; + this._category = parser.category; + this._groupable = (parser.isGroupable && !parser.rentable); + this._tradeable = parser.tradable; + this._recyclable = parser.isRecycleable; + this._sellable = parser.sellable; + this._stuffData = parser.stuffData; + this._extra = parser.extra; + this._secondsToExpiration = parser.secondsToExpiration; + this._expirationTimeStamp = parser.expirationTimeStamp; + this._hasRentPeriodStarted = parser.hasRentPeriodStarted; + this._creationDay = parser.creationDay; + this._creationMonth = parser.creationMonth; + this._creationYear = parser.creationYear; + this._slotId = parser.slotId; + this._songId = parser.songId; + this._flatId = parser.flatId; + this._isRented = parser.rentable; + this._isWallItem = parser.isWallItem; } public clone(): FurnitureItem diff --git a/src/views/inventory/common/FurnitureUtilities.ts b/src/views/inventory/common/FurnitureUtilities.ts index dc2052d7..06b13a84 100644 --- a/src/views/inventory/common/FurnitureUtilities.ts +++ b/src/views/inventory/common/FurnitureUtilities.ts @@ -310,7 +310,7 @@ function addGroupableFurnitureItem(set: GroupItem[], item: FurnitureItem, unseen return existingGroup; } -function createGroupItem(type: number, category: number, stuffData: IObjectData, extra: number = NaN, flag: boolean = false): GroupItem +export function createGroupItem(type: number, category: number, stuffData: IObjectData, extra: number = NaN, flag: boolean = false): GroupItem { // const iconImage: HTMLImageElement = null; diff --git a/src/views/inventory/common/GroupItem.ts b/src/views/inventory/common/GroupItem.ts index a5f53234..80d081fa 100644 --- a/src/views/inventory/common/GroupItem.ts +++ b/src/views/inventory/common/GroupItem.ts @@ -20,21 +20,42 @@ export class GroupItem private _hasUnseenItems: boolean; private _items: FurnitureItem[]; - constructor(type: number, category: number, roomEngine: IRoomEngine, stuffData: IObjectData, extra: number) + constructor(type: number = -1, category: number = -1, roomEngine: IRoomEngine = null, stuffData: IObjectData = null, extra: number = -1) { - this._type = type; - this._category = category; - this._roomEngine = roomEngine; - this._stuffData = stuffData; - this._extra = extra; - this._isWallItem = false; - this._iconUrl = null; - this._name = null; - this._description = null; - this._locked = false; - this._selected = false; - this._hasUnseenItems = false; - this._items = []; + this._type = type; + this._category = category; + this._roomEngine = roomEngine; + this._stuffData = stuffData; + this._extra = extra; + this._isWallItem = false; + this._iconUrl = null; + this._name = null; + this._description = null; + this._locked = false; + this._selected = false; + this._hasUnseenItems = false; + this._items = []; + } + + public clone(): GroupItem + { + const groupItem = new GroupItem(); + + groupItem._type = this._type; + groupItem._category = this._category; + groupItem._roomEngine = this._roomEngine; + groupItem._stuffData = this._stuffData; + groupItem._extra = this._extra; + groupItem._isWallItem = this._isWallItem; + groupItem._iconUrl = this._iconUrl; + groupItem._name = this._name; + groupItem._description = this._description; + groupItem._locked = this._locked; + groupItem._selected = this._selected; + groupItem._hasUnseenItems = this._hasUnseenItems; + groupItem._items = this._items; + + return groupItem; } public prepareGroup(): void @@ -251,11 +272,12 @@ export class GroupItem this._items = items; } - public lockItemIds(itemIds: number[]): void + public lockItemIds(itemIds: number[]): boolean { const items = [ ...this._items ]; let index = 0; + let updated = false; while(index < items.length) { @@ -264,6 +286,8 @@ export class GroupItem if(item.locked !== locked) { + updated = true; + const newItem = item.clone(); newItem.locked = locked; @@ -275,6 +299,8 @@ export class GroupItem } this._items = items; + + return updated; } private setName(): void diff --git a/src/views/inventory/common/TradeState.ts b/src/views/inventory/common/TradeState.ts new file mode 100644 index 00000000..68253e87 --- /dev/null +++ b/src/views/inventory/common/TradeState.ts @@ -0,0 +1,10 @@ +export class TradeState +{ + public static TRADING_STATE_READY: number = 0; + public static TRADING_STATE_RUNNING: number = 1; + public static TRADING_STATE_COUNTDOWN: number = 2; + public static TRADING_STATE_CONFIRMING: number = 3; + public static TRADING_STATE_CONFIRMED: number = 4; + public static TRADING_STATE_COMPLETED: number = 5; + public static TRADING_STATE_CANCELLED: number = 6; +} diff --git a/src/views/inventory/common/TradeUserData.ts b/src/views/inventory/common/TradeUserData.ts new file mode 100644 index 00000000..5df557fb --- /dev/null +++ b/src/views/inventory/common/TradeUserData.ts @@ -0,0 +1,15 @@ +import { AdvancedMap } from 'nitro-renderer'; +import { GroupItem } from './GroupItem'; + +export class TradeUserData +{ + constructor( + public userId: number = -1, + public userName: string = '', + public userItems: AdvancedMap = null, + public itemCount: number = 0, + public creditsCount: number = 0, + public accepts: boolean = false, + public canTrade: boolean = false, + public items: AdvancedMap = new AdvancedMap()) {} +} diff --git a/src/views/inventory/common/TradingUtilities.ts b/src/views/inventory/common/TradingUtilities.ts new file mode 100644 index 00000000..be7fc72d --- /dev/null +++ b/src/views/inventory/common/TradingUtilities.ts @@ -0,0 +1,73 @@ +import { AdvancedMap, IObjectData, ItemDataStructure, StringDataType } from 'nitro-renderer'; +import { GetSessionDataManager } from '../../../api'; +import { FurniCategory } from './FurniCategory'; +import { FurnitureItem } from './FurnitureItem'; +import { createGroupItem } from './FurnitureUtilities'; +import { GroupItem } from './GroupItem'; + +function isExternalImage(spriteId: number): boolean +{ + const furnitureData = GetSessionDataManager().getWallItemData(spriteId); + + return (furnitureData && furnitureData.isExternalImage); +} + +export function parseTradeItems(items: ItemDataStructure[], _arg_2: AdvancedMap): void +{ + const totalItems = items.length; + + if(!totalItems) return; + + for(const item of items) + { + const spriteId = item.spriteId; + const category = item.category; + + let name = (item.furniType + spriteId); + + if(!item.isGroupable || isExternalImage(spriteId)) + { + name = ('itemid' + item.itemId); + } + + if(item.category === FurniCategory._Str_5186) + { + name = (item.itemId + 'poster' + item.stuffData.getLegacyString()); + } + + else if(item.category === FurniCategory._Str_12454) + { + name = ''; + } + + let groupItem = ((item.isGroupable && !isExternalImage(item.spriteId)) ? _arg_2.getValue(name) : null); + + if(!groupItem) + { + groupItem = createGroupItem(spriteId, category, item.stuffData); + + _arg_2.add(name, groupItem); + } + + groupItem.push(new FurnitureItem(item)); + } +} + +export function _Str_16998(spriteId: number, stuffData: IObjectData): string +{ + let type = spriteId.toString(); + const _local_4 = (stuffData as StringDataType); + + if(!(stuffData instanceof StringDataType)) return type; + + let _local_5 = 1; + + while(_local_5 < 5) + { + type = (type + (',' + _local_4.getValue(_local_5))); + + _local_5++; + } + + return type; +} diff --git a/src/views/inventory/reducers/InventoryFurnitureReducer.tsx b/src/views/inventory/reducers/InventoryFurnitureReducer.tsx index 865b9207..51b380c6 100644 --- a/src/views/inventory/reducers/InventoryFurnitureReducer.tsx +++ b/src/views/inventory/reducers/InventoryFurnitureReducer.tsx @@ -1,14 +1,22 @@ -import { FurnitureListItemParser } from 'nitro-renderer'; +import { AdvancedMap, FurnitureListItemParser, TradingListItemParser } from 'nitro-renderer'; import { Reducer } from 'react'; import { FurnitureItem } from '../common/FurnitureItem'; import { addFurnitureItem, processFurniFragment, removeFurniItemById } from '../common/FurnitureUtilities'; import { GroupItem } from '../common/GroupItem'; +import { TradeState } from '../common/TradeState'; +import { TradeUserData } from '../common/TradeUserData'; +import { parseTradeItems } from '../common/TradingUtilities'; export interface IInventoryFurnitureState { needsFurniUpdate: boolean; groupItem: GroupItem; groupItems: GroupItem[]; + tradeData: { + ownUser: TradeUserData; + otherUser: TradeUserData; + state: number; + } } export interface IInventoryFurnitureAction @@ -20,6 +28,11 @@ export interface IInventoryFurnitureAction parsers?: FurnitureListItemParser[]; itemId?: number; fragment?: Map; + ownTradeUser?: TradeUserData; + otherTradeUser?: TradeUserData; + tradeState?: number; + userId?: number; + tradeParser?: TradingListItemParser; } } @@ -30,12 +43,18 @@ export class InventoryFurnitureActions public static PROCESS_FRAGMENT: string = 'IFA_PROCESS_FRAGMENT'; public static ADD_OR_UPDATE_FURNITURE: string = 'IFA_ADD_OR_UPDATE_FURNITURE'; public static REMOVE_FURNITURE: string = 'IFA_REMOVE_FURNITURE'; + public static SET_TRADE_DATA: string = 'IFA_SET_TRADE_DATA'; + public static SET_TRADE_STATE: string = 'IFA_SET_TRADE_STATE'; + public static SET_TRADE_ACCEPTANCE: string = 'FA_SET_TRADE_ACCEPTANCE'; + public static CLOSE_TRADE: string = 'IFA_CLOSE_STRING'; + public static UPDATE_TRADE: string = 'IFA_UPDATE_TRADE'; } export const initialInventoryFurniture: IInventoryFurnitureState = { needsFurniUpdate: true, groupItem: null, - groupItems: [] + groupItems: [], + tradeData: null } export const InventoryFurnitureReducer: Reducer = (state, action) => @@ -131,6 +150,122 @@ export const InventoryFurnitureReducer: Reducer = new AdvancedMap(); + const secondUserItems: AdvancedMap = new AdvancedMap(); + + parseTradeItems(parser.firstUserItemArray, firstUserItems); + parseTradeItems(parser.secondUserItemArray, secondUserItems); + + const ownUserData = Object.assign({}, tradeData.ownUser); + const otherUserData = Object.assign({}, tradeData.otherUser); + + if(tradeData.ownUser.userId === parser.firstUserID) + { + ownUserData.creditsCount = parser.firstUserNumCredits; + ownUserData.itemCount = parser.firstUserNumItems; + ownUserData.items = firstUserItems; + } + + else if(tradeData.ownUser.userId === parser.secondUserID) + { + ownUserData.creditsCount = parser.secondUserNumCredits; + ownUserData.itemCount = parser.secondUserNumItems; + ownUserData.items = secondUserItems; + } + + if(tradeData.otherUser.userId === parser.firstUserID) + { + otherUserData.creditsCount = parser.firstUserNumCredits; + otherUserData.itemCount = parser.firstUserNumItems; + otherUserData.items = firstUserItems; + } + + else if(tradeData.otherUser.userId === parser.secondUserID) + { + otherUserData.creditsCount = parser.secondUserNumCredits; + otherUserData.itemCount = parser.secondUserNumItems; + otherUserData.items = secondUserItems; + } + + tradeData.ownUser = ownUserData; + tradeData.otherUser = otherUserData; + + const tradeIds: number[] = []; + + for(const groupItem of ownUserData.items.getValues()) + { + let i = 0; + + while(i < groupItem.getTotalCount()) + { + const item = groupItem.getItemByIndex(i); + + if(item) tradeIds.push(item.ref); + + i++; + } + } + + for(const groupItem of groupItems) groupItem.lockItemIds(tradeIds); + + } + + return { ...state, groupItems, tradeData }; + } default: return state; } diff --git a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx index 644af8a1..89cb22ac 100644 --- a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx +++ b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx @@ -1,6 +1,6 @@ -import { FurnitureListComposer, RoomObjectVariable, Vector3d } from 'nitro-renderer'; -import { FC, useEffect, useState } from 'react'; -import { GetRoomEngine } from '../../../../api'; +import { FurnitureListComposer, IObjectData, RoomObjectVariable, TradingListAddItemComposer, TradingListAddItemsComposer, Vector3d } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { GetConnection, GetRoomEngine } from '../../../../api'; import { SendMessageHook } from '../../../../hooks/messages/message-event'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { LimitedEditionCompactPlateView } from '../../../shared/limited-edition/compact-plate/LimitedEditionCompactPlateView'; @@ -8,19 +8,122 @@ import { RoomPreviewerView } from '../../../shared/room-previewer/RoomPreviewerV import { FurniCategory } from '../../common/FurniCategory'; import { attemptItemPlacement } from '../../common/FurnitureUtilities'; import { GroupItem } from '../../common/GroupItem'; +import { IFurnitureItem } from '../../common/IFurnitureItem'; +import { TradeState } from '../../common/TradeState'; +import { _Str_16998 } from '../../common/TradingUtilities'; import { useInventoryContext } from '../../context/InventoryContext'; import { InventoryFurnitureActions } from '../../reducers/InventoryFurnitureReducer'; import { InventoryFurnitureViewProps } from './InventoryFurnitureView.types'; import { InventoryFurnitureResultsView } from './results/InventoryFurnitureResultsView'; import { InventoryFurnitureSearchView } from './search/InventoryFurnitureSearchView'; +const MAX_ITEMS_TO_TRADE: number = 3; + export const InventoryFurnitureView: FC = props => { const { roomSession = null, roomPreviewer = null } = props; const { furnitureState = null, dispatchFurnitureState = null } = useInventoryContext(); - const { needsFurniUpdate = false, groupItem = null, groupItems = [] } = furnitureState; + const { needsFurniUpdate = false, groupItem = null, groupItems = [], tradeData = null } = furnitureState; const [ filteredGroupItems, setFilteredGroupItems ] = useState(groupItems); + const isTrading = useMemo(() => + { + if(!tradeData) return false; + + return (tradeData.state >= TradeState.TRADING_STATE_RUNNING); + }, [ tradeData ]); + + const canTradeItem = useCallback((isWallItem: boolean, spriteId: number, category: number, groupable: boolean, stuffData: IObjectData) => + { + if(!tradeData || !tradeData.ownUser || tradeData.ownUser.accepts || !tradeData.ownUser.items) return false; + + if(tradeData.ownUser.items.length < MAX_ITEMS_TO_TRADE) return true; + + if(!groupable) return false; + + let type = spriteId.toString(); + + if(category === FurniCategory._Str_5186) + { + type = ((type + 'poster') + stuffData.getLegacyString()); + } + else + { + if(category === FurniCategory._Str_12454) + { + type = _Str_16998(spriteId, stuffData); + } + else + { + type = (((isWallItem) ? 'I' : 'S') + type); + } + } + + return !!tradeData.ownUser.items.getValue(type); + }, [ tradeData ]); + + const attemptItemOffer = useCallback((count: number) => + { + if(!tradeData || !groupItem || !isTrading) return; + + const tradeItems = groupItem.getTradeItems(count); + + if(!tradeItems || !tradeItems.length) return; + + let coreItem: IFurnitureItem = null; + const itemIds: number[] = []; + + for(const item of tradeItems) + { + itemIds.push(item.id); + + if(!coreItem) coreItem = item; + } + + const tradedIds: number[] = []; + + if(isTrading) + { + const ownItemCount = tradeData.ownUser.items.length; + + if((ownItemCount + itemIds.length) <= 1500) + { + if(!coreItem.isGroupable && (itemIds.length)) + { + GetConnection().send(new TradingListAddItemComposer(itemIds.pop())); + } + else + { + const tradeIds: number[] = []; + + for(const itemId of itemIds) + { + if(canTradeItem(coreItem.isWallItem, coreItem.type, coreItem.category, coreItem.isGroupable, coreItem.stuffData)) + { + tradedIds.push(itemId); + } + } + + if(tradedIds.length) + { + if(tradedIds.length === 1) + { + GetConnection().send(new TradingListAddItemComposer(tradedIds.pop())); + } + else + { + GetConnection().send(new TradingListAddItemsComposer(...tradedIds)); + } + } + } + } + else + { + //this._notificationService.alert('${trading.items.too_many_items.desc}', '${trading.items.too_many_items.title}'); + } + } + }, [ canTradeItem, groupItem, isTrading, tradeData ]); + useEffect(() => { if(needsFurniUpdate) @@ -123,14 +226,18 @@ export const InventoryFurnitureView: FC = props =>
- { groupItem && groupItem.stuffData.isUnique && + { groupItem &&groupItem.stuffData.isUnique &&
} - { groupItem &&
-

{ groupItem.name }

- { !!roomSession && } -
} + { groupItem && +
+

{ groupItem.name }

+ { !!roomSession && !isTrading && + } + { isTrading && + } +
}
); diff --git a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx index 97d174c6..5079f367 100644 --- a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx +++ b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx @@ -10,6 +10,7 @@ export const InventoryFurnitureItemView: FC = p { const { groupItem } = props; const { furnitureState, dispatchFurnitureState } = useInventoryContext(); + const { tradeData = null } = furnitureState; const [ isMouseDown, setMouseDown ] = useState(false); const isActive = (furnitureState.groupItem === groupItem); @@ -40,7 +41,7 @@ export const InventoryFurnitureItemView: FC = p return (
-
+
{groupItem.getUnlockedCount() > 1 && {groupItem.getUnlockedCount()} } { groupItem.stuffData.isUnique && diff --git a/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx b/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx index 4b3ae59b..9df3889c 100644 --- a/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx +++ b/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx @@ -9,7 +9,7 @@ export const InventoryFurnitureResultsView: FC
- { groupItems && (groupItems.length > 0) && groupItems.map((item, index) => + { groupItems && (groupItems.length > 0) && groupItems.map((item, index) => { return }) } diff --git a/src/views/inventory/views/trade/InventoryTradeView.tsx b/src/views/inventory/views/trade/InventoryTradeView.tsx new file mode 100644 index 00000000..88fe8f7f --- /dev/null +++ b/src/views/inventory/views/trade/InventoryTradeView.tsx @@ -0,0 +1,37 @@ +import { FC } from 'react'; +import { LocalizeText } from '../../../../utils/LocalizeText'; +import { useInventoryContext } from '../../context/InventoryContext'; +import { InventoryTradeViewProps } from './InventoryTradeView.types'; +import { InventoryTradeItemView } from './item/InventoryTradeItemView'; + +const MAX_ITEMS_COUNT: number = 9; + +export const InventoryTradeView: FC = props => +{ + const { isInFurnitureView = false } = props; + const { furnitureState = null } = useInventoryContext(); + const { tradeData = null } = furnitureState; + + return ( +
+
+
{ LocalizeText('inventory.trading.you') }
+
+ { Array.from(Array(MAX_ITEMS_COUNT), (e, i) => + { + return ; + }) } +
+
+
+
{ tradeData.otherUser.userName }
+
+ { Array.from(Array(MAX_ITEMS_COUNT), (e, i) => + { + return ; + }) } +
+
+
+ ); +} diff --git a/src/views/inventory/views/trade/InventoryTradeView.types.ts b/src/views/inventory/views/trade/InventoryTradeView.types.ts new file mode 100644 index 00000000..aa863e89 --- /dev/null +++ b/src/views/inventory/views/trade/InventoryTradeView.types.ts @@ -0,0 +1,4 @@ +export interface InventoryTradeViewProps +{ + isInFurnitureView: boolean; +} diff --git a/src/views/inventory/views/trade/item/InventoryTradeItemView.tsx b/src/views/inventory/views/trade/item/InventoryTradeItemView.tsx new file mode 100644 index 00000000..75627b04 --- /dev/null +++ b/src/views/inventory/views/trade/item/InventoryTradeItemView.tsx @@ -0,0 +1,37 @@ +import { FC, useCallback } from 'react'; +import { LimitedEditionStyledNumberView } from '../../../../shared/limited-edition/styled-number/LimitedEditionStyledNumberView'; +import { InventoryTradeItemViewProps } from './InventoryTradeItemView.types'; + +export const InventoryTradeItemView: FC = props => +{ + const { groupItem = null } = props; + + const onClick = useCallback(() => + { + + }, []); + + if(!groupItem) + { + return ( +
+
+
+ ); + } + + const imageUrl = `url(${ groupItem.iconUrl })`; + + return ( +
+
+ { groupItem.getUnlockedCount() > 1 && + { groupItem.getUnlockedCount() } } + { groupItem.stuffData.isUnique && +
+ +
} +
+
+ ); +} diff --git a/src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts b/src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts new file mode 100644 index 00000000..29740d21 --- /dev/null +++ b/src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts @@ -0,0 +1,6 @@ +import { GroupItem } from '../../../common/GroupItem'; + +export interface InventoryTradeItemViewProps +{ + groupItem: GroupItem; +} diff --git a/src/views/purse/PurseView.tsx b/src/views/purse/PurseView.tsx index 15932d13..8ab722ca 100644 --- a/src/views/purse/PurseView.tsx +++ b/src/views/purse/PurseView.tsx @@ -37,11 +37,11 @@ export const PurseView: FC = props =>
- { currencies && currencies.map((currency, index) => + { currencies && currencies.map(currency => { if(displayedCurrencies.indexOf(currency.type) === -1) return null; - return ; + return ; }) }
diff --git a/src/views/room/handlers/RoomWidgetInfostandHandler.ts b/src/views/room/handlers/RoomWidgetInfostandHandler.ts index 868911a7..9ad903bf 100644 --- a/src/views/room/handlers/RoomWidgetInfostandHandler.ts +++ b/src/views/room/handlers/RoomWidgetInfostandHandler.ts @@ -1,6 +1,6 @@ import { IFurnitureData, Nitro, NitroEvent, ObjectDataFactory, PetFigureData, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer'; import { GetConnection, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; -import { WiredSelectObjectEvent } from '../../../events'; +import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../events'; import { dispatchUiEvent } from '../../../hooks/events'; import { LocalizeText } from '../../../utils/LocalizeText'; import { RoomWidgetObjectNameEvent, RoomWidgetUpdateChatInputContentEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events'; @@ -114,7 +114,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler this.container.roomSession.sendTakeRightsMessage((message as RoomWidgetUserActionMessage).userId); break; case RoomWidgetUserActionMessage.START_TRADING: - //if(userData) this._widget.inventoryTrading.startTrade(userData.roomIndex, userData.name); + dispatchUiEvent(new InventoryTradeRequestEvent(userData.roomIndex, userData.name)); break; // case RoomWidgetUserActionMessage.RWUAM_OPEN_HOME_PAGE: // this._container.sessionDataManager._Str_21275((message as RoomWidgetUserActionMessage).userId, _local_3.name); From 9080e5b5f2f678bcea04668fd76b937669dca8bd Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 5 Jul 2021 12:10:32 -0400 Subject: [PATCH 24/72] Mannequin view updates --- .../mannequin/FurnitureMannequinView.tsx | 57 +++++++++---------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx b/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx index d2c762ba..a07a6cba 100644 --- a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx +++ b/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx @@ -178,39 +178,38 @@ export const FurnitureMannequinView: FC = props =>
-
- { viewMode === FurnitureMannequinViewMode.EDIT && <> - processAction('set_name', event.target.value) } onKeyDown={ event => handleKeyDown(event) } /> -
processAction('load_figure') }>{ LocalizeText('mannequin.widget.style') }
-
processAction('wear') }>{ LocalizeText('mannequin.widget.wear') }
- } - { viewMode === FurnitureMannequinViewMode.SAVE && <> -
+
+ { viewMode === FurnitureMannequinViewMode.DEFAULT && + <>
-
{ mannequinData.name }
-
{ LocalizeText('mannequin.widget.savetext') }
-
-
-
processAction('back') }>{ LocalizeText('mannequin.widget.back') }
-
processAction('save_figure') }>{ LocalizeText('mannequin.widget.save') }
-
-
- } - { viewMode === FurnitureMannequinViewMode.DEFAULT && <> -
-
-
{ mannequinData.name }
+
{ mannequinData.name }
{ LocalizeText('mannequin.widget.weartext') }
processAction('wear') }>{ LocalizeText('mannequin.widget.wear') }
-
- } - { viewMode === FurnitureMannequinViewMode.CLUB && <> -
{ LocalizeText('mannequin.widget.clubnotification') }
- } - { viewMode === FurnitureMannequinViewMode.INCOMPATIBLE_GENDER && <> -
{ LocalizeText('mannequin.widget.wronggender') }
- } + } + { viewMode === FurnitureMannequinViewMode.EDIT && + <> + processAction('set_name', event.target.value) } onKeyDown={ event => handleKeyDown(event) } /> +
+
processAction('load_figure') }>{ LocalizeText('mannequin.widget.style') }
+
processAction('wear') }>{ LocalizeText('mannequin.widget.wear') }
+
+ } + { viewMode === FurnitureMannequinViewMode.SAVE && + <> +
+
{ mannequinData.name }
+
{ LocalizeText('mannequin.widget.savetext') }
+
+
+
processAction('back') }>{ LocalizeText('mannequin.widget.back') }
+
processAction('save_figure') }>{ LocalizeText('mannequin.widget.save') }
+
+ } + { viewMode === FurnitureMannequinViewMode.CLUB && +
{ LocalizeText('mannequin.widget.clubnotification') }
} + { viewMode === FurnitureMannequinViewMode.INCOMPATIBLE_GENDER && +
{ LocalizeText('mannequin.widget.wronggender') }
}
From a907b85514041b0f5881420962e7ef6ca1c1b2fa Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 6 Jul 2021 22:25:36 -0400 Subject: [PATCH 25/72] Trading --- src/assets/styles/scrollbars.scss | 26 +-- src/layout/card/NitroCardView.scss | 1 + src/layout/card/grid/NitroCardGridView.scss | 26 +++ src/layout/card/grid/NitroCardGridView.tsx | 15 ++ .../card/grid/NitroCardGridView.types.ts | 4 + .../card/grid/item/NitroCardGridItemView.scss | 47 ++++ .../card/grid/item/NitroCardGridItemView.tsx | 24 ++ .../grid/item/NitroCardGridItemView.types.ts | 10 + src/views/inventory/InventoryView.tsx | 61 ++--- src/views/inventory/InventoryView.types.ts | 8 +- .../reducers/InventoryFurnitureReducer.tsx | 1 - src/views/inventory/views/InventoryViews.scss | 2 - .../views/badge/InventoryBadgeView.scss | 6 +- .../InventoryActiveBadgeResultsView.scss | 2 - .../InventoryActiveBadgeResultsView.tsx | 5 +- .../badge/item/InventoryBadgeItemView.tsx | 9 +- .../results/InventoryBadgeResultsView.scss | 9 - .../results/InventoryBadgeResultsView.tsx | 17 +- .../inventory/views/bot/InventoryBotView.scss | 2 - .../views/bot/item/InventoryBotItemView.scss | 25 --- .../views/bot/item/InventoryBotItemView.tsx | 9 +- .../bot/results/InventoryBotResultsView.scss | 5 - .../bot/results/InventoryBotResultsView.tsx | 13 +- .../furniture/InventoryFurnitureView.scss | 4 - .../furniture/InventoryFurnitureView.tsx | 117 +--------- .../item/InventoryFurnitureItemView.scss | 25 --- .../item/InventoryFurnitureItemView.tsx | 17 +- .../InventoryFurnitureResultsView.scss | 2 - .../results/InventoryFurnitureResultsView.tsx | 17 +- .../InventoryFurnitureResultsView.types.ts | 1 + .../search/InventoryFurnitureSearchView.scss | 0 .../search/InventoryFurnitureSearchView.tsx | 2 +- .../inventory/views/pet/InventoryPetView.scss | 2 - .../views/pet/item/InventoryPetItemView.scss | 17 -- .../views/pet/item/InventoryPetItemView.tsx | 9 +- .../pet/results/InventoryPetResultsView.scss | 5 - .../pet/results/InventoryPetResultsView.tsx | 13 +- .../views/trade/InventoryTradeView.tsx | 211 ++++++++++++++++-- .../views/trade/InventoryTradeView.types.ts | 1 - .../trade/item/InventoryTradeItemView.tsx | 37 --- .../item/InventoryTradeItemView.types.ts | 6 - 41 files changed, 426 insertions(+), 387 deletions(-) create mode 100644 src/layout/card/grid/NitroCardGridView.scss create mode 100644 src/layout/card/grid/NitroCardGridView.tsx create mode 100644 src/layout/card/grid/NitroCardGridView.types.ts create mode 100644 src/layout/card/grid/item/NitroCardGridItemView.scss create mode 100644 src/layout/card/grid/item/NitroCardGridItemView.tsx create mode 100644 src/layout/card/grid/item/NitroCardGridItemView.types.ts delete mode 100644 src/views/inventory/views/badge/active-results/InventoryActiveBadgeResultsView.scss delete mode 100644 src/views/inventory/views/badge/results/InventoryBadgeResultsView.scss delete mode 100644 src/views/inventory/views/bot/InventoryBotView.scss delete mode 100644 src/views/inventory/views/bot/item/InventoryBotItemView.scss delete mode 100644 src/views/inventory/views/bot/results/InventoryBotResultsView.scss delete mode 100644 src/views/inventory/views/furniture/item/InventoryFurnitureItemView.scss delete mode 100644 src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.scss delete mode 100644 src/views/inventory/views/furniture/search/InventoryFurnitureSearchView.scss delete mode 100644 src/views/inventory/views/pet/InventoryPetView.scss delete mode 100644 src/views/inventory/views/pet/item/InventoryPetItemView.scss delete mode 100644 src/views/inventory/views/pet/results/InventoryPetResultsView.scss delete mode 100644 src/views/inventory/views/trade/item/InventoryTradeItemView.tsx delete mode 100644 src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts diff --git a/src/assets/styles/scrollbars.scss b/src/assets/styles/scrollbars.scss index e9eee6a5..a011c8fa 100644 --- a/src/assets/styles/scrollbars.scss +++ b/src/assets/styles/scrollbars.scss @@ -1,25 +1,21 @@ ::-webkit-scrollbar { - width: 7px; - height: 5px; + width: 0.5rem; } ::-webkit-scrollbar-track { - border-radius: $border-radius; - background: rgba($black,.1); - box-shadow:inset 0 0 1px 1px rgba($black,.1); - padding-top:3px; + background-clip: padding-box; + border-right: 0.25rem solid rgba($black, .1); } ::-webkit-scrollbar-thumb { - border-radius: $border-radius; - background: rgba($primary,.4); - width: 4px; -} + background-clip: padding-box; + border-right: 0.25rem solid rgba($primary, .4); -::-webkit-scrollbar-thumb:hover { - background: rgba($primary,.8); -} + &:hover { + border-right: 0.25rem solid rgba($primary, .8); + } -::-webkit-scrollbar-thumb:active { - background: $secondary; + &:active { + border-right: 0.25rem solid $secondary; + } } diff --git a/src/layout/card/NitroCardView.scss b/src/layout/card/NitroCardView.scss index de37a762..44285071 100644 --- a/src/layout/card/NitroCardView.scss +++ b/src/layout/card/NitroCardView.scss @@ -6,6 +6,7 @@ $nitro-card-tabs-height: 33px; @import './accordion/NitroCardAccordionView'; @import './content/NitroCardContentView'; + @import './grid/NitroCardGridView'; @import './header/NitroCardHeaderView'; @import './tabs/NitroCardTabsView'; } diff --git a/src/layout/card/grid/NitroCardGridView.scss b/src/layout/card/grid/NitroCardGridView.scss new file mode 100644 index 00000000..44a1ee42 --- /dev/null +++ b/src/layout/card/grid/NitroCardGridView.scss @@ -0,0 +1,26 @@ +.nitro-card-grid { + + .row-cols-3 { + + .col { + padding-right: 0.25rem; + + &:nth-child(3n+3) { + padding-right: 0; + } + } + } + + .row-cols-5 { + + .col { + padding-right: 0.25rem; + + &:nth-child(5n+5) { + padding-right: 0; + } + } + } + + @import './item/NitroCardGridItemView.scss'; +} diff --git a/src/layout/card/grid/NitroCardGridView.tsx b/src/layout/card/grid/NitroCardGridView.tsx new file mode 100644 index 00000000..25b9fe47 --- /dev/null +++ b/src/layout/card/grid/NitroCardGridView.tsx @@ -0,0 +1,15 @@ +import { FC } from 'react'; +import { NitroCardGridViewProps } from './NitroCardGridView.types'; + +export const NitroCardGridView: FC = props => +{ + const { columns = 5, children = null } = props; + + return ( +
+
+ { children } +
+
+ ); +} diff --git a/src/layout/card/grid/NitroCardGridView.types.ts b/src/layout/card/grid/NitroCardGridView.types.ts new file mode 100644 index 00000000..b24763d1 --- /dev/null +++ b/src/layout/card/grid/NitroCardGridView.types.ts @@ -0,0 +1,4 @@ +export interface NitroCardGridViewProps +{ + columns?: number; +} diff --git a/src/layout/card/grid/item/NitroCardGridItemView.scss b/src/layout/card/grid/item/NitroCardGridItemView.scss new file mode 100644 index 00000000..988d0535 --- /dev/null +++ b/src/layout/card/grid/item/NitroCardGridItemView.scss @@ -0,0 +1,47 @@ +.grid-item-container { + height: 48px; + max-height: 48px; + + .grid-item { + width: 100%; + height: 100%; + border-color: $grid-border-color !important; + background-color: $grid-bg-color !important; + background-position: center; + background-repeat: no-repeat; + overflow: hidden; + + &.active { + border-color: $grid-active-border-color !important; + background-color: $grid-active-bg-color !important; + } + + .badge { + top: 2px; + right: 2px; + font-size: 8px; + } + + .avatar-image { + width: 100% !important; + height: 100% !important; + background-position: center; + background-repeat: no-repeat; + background-position-y: -32px !important; + } + + .trade-button { + position: absolute; + bottom: 2px; + right: 2px; + font-size: 5px; + padding: 3px; + min-height: unset; + + &.left { + right: unset; + left: 2px; + } + } + } +} diff --git a/src/layout/card/grid/item/NitroCardGridItemView.tsx b/src/layout/card/grid/item/NitroCardGridItemView.tsx new file mode 100644 index 00000000..904c4fea --- /dev/null +++ b/src/layout/card/grid/item/NitroCardGridItemView.tsx @@ -0,0 +1,24 @@ +import { FC } from 'react'; +import { LimitedEditionStyledNumberView } from '../../../../views/shared/limited-edition/styled-number/LimitedEditionStyledNumberView'; +import { NitroCardGridItemViewProps } from './NitroCardGridItemView.types'; + +export const NitroCardGridItemView: FC = props => +{ + const { itemActive = false, itemCount = 1, itemUnique = false, itemUniqueNumber = 0, itemImage = null, className = '', style = {}, children = null, ...rest } = props; + + const imageUrl = `url(${ itemImage })`; + + return ( +
+
+ { (itemCount > 1) && + { itemCount } } + { itemUnique && +
+ +
} + { children } +
+
+ ); +} diff --git a/src/layout/card/grid/item/NitroCardGridItemView.types.ts b/src/layout/card/grid/item/NitroCardGridItemView.types.ts new file mode 100644 index 00000000..20bda705 --- /dev/null +++ b/src/layout/card/grid/item/NitroCardGridItemView.types.ts @@ -0,0 +1,10 @@ +import { DetailsHTMLAttributes } from 'react'; + +export interface NitroCardGridItemViewProps extends DetailsHTMLAttributes +{ + itemImage?: string; + itemActive?: boolean; + itemCount?: number; + itemUnique?: boolean; + itemUniqueNumber?: number; +} diff --git a/src/views/inventory/InventoryView.tsx b/src/views/inventory/InventoryView.tsx index 04f65231..a0905bc4 100644 --- a/src/views/inventory/InventoryView.tsx +++ b/src/views/inventory/InventoryView.tsx @@ -103,18 +103,23 @@ export const InventoryView: FC = props => } }, []); + useEffect(() => + { + if(!furnitureState.tradeData) return; + + setIsVisible(true); + }, [ furnitureState.tradeData ]); + useEffect(() => { if(!isVisible) { if(furnitureState.tradeData) { - setIsVisible(true); - - if(currentTab !== InventoryTabs.FURNITURE) setCurrentTab(InventoryTabs.FURNITURE); + // cancel the trade } } - }, [ furnitureState.tradeData, isVisible, currentTab ]); + }, [ furnitureState.tradeData, isVisible ]); return ( @@ -122,27 +127,33 @@ export const InventoryView: FC = props => { isVisible && setIsVisible(false) } /> - - { tabs.map((name, index) => - { - return ( - setCurrentTab(name) }> - { LocalizeText(name) } - - ); - }) } - - - { (currentTab === InventoryTabs.FURNITURE ) && - } - { (currentTab === InventoryTabs.BOTS ) && - } - { (currentTab === InventoryTabs.PETS ) && - } - { (currentTab === InventoryTabs.BADGES ) && - } - { furnitureState.tradeData && } - + { !furnitureState.tradeData && + <> + + { tabs.map((name, index) => + { + return ( + setCurrentTab(name) }> + { LocalizeText(name) } + + ); + }) } + + + { (currentTab === InventoryTabs.FURNITURE ) && + } + { (currentTab === InventoryTabs.BOTS ) && + } + { (currentTab === InventoryTabs.PETS ) && + } + { (currentTab === InventoryTabs.BADGES ) && + } + + } + { furnitureState.tradeData && + + + } } ); diff --git a/src/views/inventory/InventoryView.types.ts b/src/views/inventory/InventoryView.types.ts index ea815348..ee6e9307 100644 --- a/src/views/inventory/InventoryView.types.ts +++ b/src/views/inventory/InventoryView.types.ts @@ -3,8 +3,8 @@ export interface InventoryViewProps export class InventoryTabs { - public static readonly FURNITURE: string = 'inventory.furni'; - public static readonly BOTS: string = 'inventory.bots'; - public static readonly PETS: string = 'inventory.furni.tab.pets'; - public static readonly BADGES: string = 'inventory.badges'; + public static readonly FURNITURE: string = 'inventory.furni'; + public static readonly BOTS: string = 'inventory.bots'; + public static readonly PETS: string = 'inventory.furni.tab.pets'; + public static readonly BADGES: string = 'inventory.badges'; } diff --git a/src/views/inventory/reducers/InventoryFurnitureReducer.tsx b/src/views/inventory/reducers/InventoryFurnitureReducer.tsx index 51b380c6..cb4dbb1e 100644 --- a/src/views/inventory/reducers/InventoryFurnitureReducer.tsx +++ b/src/views/inventory/reducers/InventoryFurnitureReducer.tsx @@ -261,7 +261,6 @@ export const InventoryFurnitureReducer: Reducer + { badges && (badges.length > 0) && badges.map(code => { return }) } -
+ ); } diff --git a/src/views/inventory/views/badge/item/InventoryBadgeItemView.tsx b/src/views/inventory/views/badge/item/InventoryBadgeItemView.tsx index 1b9248b8..fc221a7d 100644 --- a/src/views/inventory/views/badge/item/InventoryBadgeItemView.tsx +++ b/src/views/inventory/views/badge/item/InventoryBadgeItemView.tsx @@ -1,5 +1,6 @@ import { MouseEventType } from 'nitro-renderer'; import { FC, MouseEvent, useCallback } from 'react'; +import { NitroCardGridItemView } from '../../../../../layout/card/grid/item/NitroCardGridItemView'; import { BadgeImageView } from '../../../../shared/badge-image/BadgeImageView'; import { useInventoryContext } from '../../../context/InventoryContext'; import { InventoryBadgeActions } from '../../../reducers/InventoryBadgeReducer'; @@ -24,10 +25,8 @@ export const InventoryBadgeItemView: FC = props => }, [ badge, dispatchBadgeState ]); return ( -
-
- -
-
+ + + ); } diff --git a/src/views/inventory/views/badge/results/InventoryBadgeResultsView.scss b/src/views/inventory/views/badge/results/InventoryBadgeResultsView.scss deleted file mode 100644 index e9a6e5ee..00000000 --- a/src/views/inventory/views/badge/results/InventoryBadgeResultsView.scss +++ /dev/null @@ -1,9 +0,0 @@ -.badge-item-container { - height: 139px; - max-height: 139px; - overflow-y: auto; -} - -.inventory-badge-overflow { - height:calc(100% - 86px) -} diff --git a/src/views/inventory/views/badge/results/InventoryBadgeResultsView.tsx b/src/views/inventory/views/badge/results/InventoryBadgeResultsView.tsx index 66215373..5473e2b0 100644 --- a/src/views/inventory/views/badge/results/InventoryBadgeResultsView.tsx +++ b/src/views/inventory/views/badge/results/InventoryBadgeResultsView.tsx @@ -1,4 +1,5 @@ import { FC } from 'react'; +import { NitroCardGridView } from '../../../../../layout/card/grid/NitroCardGridView'; import { InventoryBadgeItemView } from '../item/InventoryBadgeItemView'; import { InventoryBadgeResultsViewProps } from './InventoryBadgeResultsView.types'; @@ -7,15 +8,13 @@ export const InventoryBadgeResultsView: FC = pro const { badges = [], activeBadges = [] } = props; return ( -
-
+ { badges && (badges.length > 0) && badges.map(code => - { - if(activeBadges.indexOf(code) >= 0) return null; - - return - }) } -
-
+ { + if(activeBadges.indexOf(code) >= 0) return null; + + return + }) } + ); } diff --git a/src/views/inventory/views/bot/InventoryBotView.scss b/src/views/inventory/views/bot/InventoryBotView.scss deleted file mode 100644 index d82c5a47..00000000 --- a/src/views/inventory/views/bot/InventoryBotView.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import './item/InventoryBotItemView'; -@import './results/InventoryBotResultsView'; diff --git a/src/views/inventory/views/bot/item/InventoryBotItemView.scss b/src/views/inventory/views/bot/item/InventoryBotItemView.scss deleted file mode 100644 index 5de8916d..00000000 --- a/src/views/inventory/views/bot/item/InventoryBotItemView.scss +++ /dev/null @@ -1,25 +0,0 @@ -.inventory-bot-item-container { - height: 48px; - max-height: 48px; - - .inventory-bot-item { - width: 100%; - height: 100%; - border-color: $grid-border-color !important; - background-color: $grid-bg-color; - overflow: hidden; - - &.active { - border-color: $grid-active-border-color !important; - background-color: $grid-active-bg-color; - } - - .avatar-image { - width: 100% !important; - height: 100% !important; - background-position: center; - background-repeat: no-repeat; - background-position-y: -32px !important; - } - } -} diff --git a/src/views/inventory/views/bot/item/InventoryBotItemView.tsx b/src/views/inventory/views/bot/item/InventoryBotItemView.tsx index a08151cf..404deaf2 100644 --- a/src/views/inventory/views/bot/item/InventoryBotItemView.tsx +++ b/src/views/inventory/views/bot/item/InventoryBotItemView.tsx @@ -1,5 +1,6 @@ import { MouseEventType } from 'nitro-renderer'; import { FC, MouseEvent, useCallback, useState } from 'react'; +import { NitroCardGridItemView } from '../../../../../layout/card/grid/item/NitroCardGridItemView'; import { AvatarImageView } from '../../../../shared/avatar-image/AvatarImageView'; import { attemptBotPlacement } from '../../../common/BotUtilities'; import { useInventoryContext } from '../../../context/InventoryContext'; @@ -37,10 +38,8 @@ export const InventoryBotItemView: FC = props => }, [ isActive, isMouseDown, botItem, dispatchBotState ]); return ( -
-
- -
-
+ + + ); } diff --git a/src/views/inventory/views/bot/results/InventoryBotResultsView.scss b/src/views/inventory/views/bot/results/InventoryBotResultsView.scss deleted file mode 100644 index 097c92d8..00000000 --- a/src/views/inventory/views/bot/results/InventoryBotResultsView.scss +++ /dev/null @@ -1,5 +0,0 @@ -.bot-item-container { - height: 220px; - max-height: 220px; - overflow-y: auto; -} diff --git a/src/views/inventory/views/bot/results/InventoryBotResultsView.tsx b/src/views/inventory/views/bot/results/InventoryBotResultsView.tsx index 477c7bb4..fc2763ce 100644 --- a/src/views/inventory/views/bot/results/InventoryBotResultsView.tsx +++ b/src/views/inventory/views/bot/results/InventoryBotResultsView.tsx @@ -1,4 +1,5 @@ import { FC } from 'react'; +import { NitroCardGridView } from '../../../../../layout/card/grid/NitroCardGridView'; import { InventoryBotItemView } from '../item/InventoryBotItemView'; import { InventoryBotResultsViewProps } from './InventoryBotResultsView.types'; @@ -7,13 +8,11 @@ export const InventoryBotResultsView: FC = props = const { botItems = [] } = props; return ( -
-
+ { botItems && (botItems.length > 0) && botItems.map(item => - { - return - }) } -
-
+ { + return + }) } + ); } diff --git a/src/views/inventory/views/furniture/InventoryFurnitureView.scss b/src/views/inventory/views/furniture/InventoryFurnitureView.scss index 19515f7a..f56fa741 100644 --- a/src/views/inventory/views/furniture/InventoryFurnitureView.scss +++ b/src/views/inventory/views/furniture/InventoryFurnitureView.scss @@ -3,7 +3,3 @@ top: 5px; right: 15px; } - -@import './item/InventoryFurnitureItemView'; -@import './results/InventoryFurnitureResultsView'; -@import './search/InventoryFurnitureSearchView'; diff --git a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx index 89cb22ac..99f0693e 100644 --- a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx +++ b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx @@ -1,129 +1,26 @@ -import { FurnitureListComposer, IObjectData, RoomObjectVariable, TradingListAddItemComposer, TradingListAddItemsComposer, Vector3d } from 'nitro-renderer'; -import { FC, useCallback, useEffect, useMemo, useState } from 'react'; -import { GetConnection, GetRoomEngine } from '../../../../api'; -import { SendMessageHook } from '../../../../hooks/messages/message-event'; +import { FurnitureListComposer, RoomObjectVariable, Vector3d } from 'nitro-renderer'; +import { FC, useEffect, useState } from 'react'; +import { GetRoomEngine } from '../../../../api'; +import { SendMessageHook } from '../../../../hooks/messages'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { LimitedEditionCompactPlateView } from '../../../shared/limited-edition/compact-plate/LimitedEditionCompactPlateView'; import { RoomPreviewerView } from '../../../shared/room-previewer/RoomPreviewerView'; import { FurniCategory } from '../../common/FurniCategory'; import { attemptItemPlacement } from '../../common/FurnitureUtilities'; import { GroupItem } from '../../common/GroupItem'; -import { IFurnitureItem } from '../../common/IFurnitureItem'; -import { TradeState } from '../../common/TradeState'; -import { _Str_16998 } from '../../common/TradingUtilities'; import { useInventoryContext } from '../../context/InventoryContext'; import { InventoryFurnitureActions } from '../../reducers/InventoryFurnitureReducer'; import { InventoryFurnitureViewProps } from './InventoryFurnitureView.types'; import { InventoryFurnitureResultsView } from './results/InventoryFurnitureResultsView'; import { InventoryFurnitureSearchView } from './search/InventoryFurnitureSearchView'; -const MAX_ITEMS_TO_TRADE: number = 3; - export const InventoryFurnitureView: FC = props => { const { roomSession = null, roomPreviewer = null } = props; const { furnitureState = null, dispatchFurnitureState = null } = useInventoryContext(); - const { needsFurniUpdate = false, groupItem = null, groupItems = [], tradeData = null } = furnitureState; + const { needsFurniUpdate = false, groupItem = null, groupItems = [] } = furnitureState; const [ filteredGroupItems, setFilteredGroupItems ] = useState(groupItems); - const isTrading = useMemo(() => - { - if(!tradeData) return false; - - return (tradeData.state >= TradeState.TRADING_STATE_RUNNING); - }, [ tradeData ]); - - const canTradeItem = useCallback((isWallItem: boolean, spriteId: number, category: number, groupable: boolean, stuffData: IObjectData) => - { - if(!tradeData || !tradeData.ownUser || tradeData.ownUser.accepts || !tradeData.ownUser.items) return false; - - if(tradeData.ownUser.items.length < MAX_ITEMS_TO_TRADE) return true; - - if(!groupable) return false; - - let type = spriteId.toString(); - - if(category === FurniCategory._Str_5186) - { - type = ((type + 'poster') + stuffData.getLegacyString()); - } - else - { - if(category === FurniCategory._Str_12454) - { - type = _Str_16998(spriteId, stuffData); - } - else - { - type = (((isWallItem) ? 'I' : 'S') + type); - } - } - - return !!tradeData.ownUser.items.getValue(type); - }, [ tradeData ]); - - const attemptItemOffer = useCallback((count: number) => - { - if(!tradeData || !groupItem || !isTrading) return; - - const tradeItems = groupItem.getTradeItems(count); - - if(!tradeItems || !tradeItems.length) return; - - let coreItem: IFurnitureItem = null; - const itemIds: number[] = []; - - for(const item of tradeItems) - { - itemIds.push(item.id); - - if(!coreItem) coreItem = item; - } - - const tradedIds: number[] = []; - - if(isTrading) - { - const ownItemCount = tradeData.ownUser.items.length; - - if((ownItemCount + itemIds.length) <= 1500) - { - if(!coreItem.isGroupable && (itemIds.length)) - { - GetConnection().send(new TradingListAddItemComposer(itemIds.pop())); - } - else - { - const tradeIds: number[] = []; - - for(const itemId of itemIds) - { - if(canTradeItem(coreItem.isWallItem, coreItem.type, coreItem.category, coreItem.isGroupable, coreItem.stuffData)) - { - tradedIds.push(itemId); - } - } - - if(tradedIds.length) - { - if(tradedIds.length === 1) - { - GetConnection().send(new TradingListAddItemComposer(tradedIds.pop())); - } - else - { - GetConnection().send(new TradingListAddItemsComposer(...tradedIds)); - } - } - } - } - else - { - //this._notificationService.alert('${trading.items.too_many_items.desc}', '${trading.items.too_many_items.title}'); - } - } - }, [ canTradeItem, groupItem, isTrading, tradeData ]); - useEffect(() => { if(needsFurniUpdate) @@ -233,10 +130,8 @@ export const InventoryFurnitureView: FC = props => { groupItem &&

{ groupItem.name }

- { !!roomSession && !isTrading && + { !!roomSession && } - { isTrading && - }
}
diff --git a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.scss b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.scss deleted file mode 100644 index 824e17ce..00000000 --- a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.scss +++ /dev/null @@ -1,25 +0,0 @@ -.inventory-furniture-item-container { - height: 48px; - max-height: 48px; - - .inventory-furniture-item { - width: 100%; - height: 100%; - border-color: $grid-border-color !important; - background-color: $grid-bg-color !important; - background-position: center; - background-repeat: no-repeat; - overflow: hidden; - - &.active { - border-color: $grid-active-border-color !important; - background-color: $grid-active-bg-color !important; - } - - .badge { - top: 2px; - right: 2px; - font-size: 8px; - } - } -} diff --git a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx index 5079f367..657ea66c 100644 --- a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx +++ b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx @@ -1,6 +1,6 @@ import { MouseEventType } from 'nitro-renderer'; import { FC, MouseEvent, useCallback, useState } from 'react'; -import { LimitedEditionStyledNumberView } from '../../../../shared/limited-edition/styled-number/LimitedEditionStyledNumberView'; +import { NitroCardGridItemView } from '../../../../../layout/card/grid/item/NitroCardGridItemView'; import { attemptItemPlacement } from '../../../common/FurnitureUtilities'; import { useInventoryContext } from '../../../context/InventoryContext'; import { InventoryFurnitureActions } from '../../../reducers/InventoryFurnitureReducer'; @@ -37,18 +37,7 @@ export const InventoryFurnitureItemView: FC = p } }, [ isActive, isMouseDown, groupItem, dispatchFurnitureState ]); - const imageUrl = `url(${ groupItem.iconUrl })`; + const count = groupItem.getUnlockedCount(); - return ( -
-
- {groupItem.getUnlockedCount() > 1 && - {groupItem.getUnlockedCount()} } - { groupItem.stuffData.isUnique && -
- -
} -
-
- ); + return ; } diff --git a/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.scss b/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.scss deleted file mode 100644 index 2d4f3402..00000000 --- a/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.scss +++ /dev/null @@ -1,2 +0,0 @@ -.furni-item-container { -} diff --git a/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx b/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx index 9df3889c..0464eb55 100644 --- a/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx +++ b/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.tsx @@ -1,19 +1,18 @@ import { FC } from 'react'; +import { NitroCardGridView } from '../../../../../layout/card/grid/NitroCardGridView'; import { InventoryFurnitureItemView } from '../item/InventoryFurnitureItemView'; import { InventoryFurnitureResultsViewProps } from './InventoryFurnitureResultsView.types'; export const InventoryFurnitureResultsView: FC = props => { - const { groupItems = [] } = props; + const { groupItems = [], columns = 5 } = props; return ( -
-
- { groupItems && (groupItems.length > 0) && groupItems.map((item, index) => - { - return - }) } -
-
+ + { groupItems && (groupItems.length > 0) && groupItems.map((item, index) => + { + return + }) } + ); } diff --git a/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.types.ts b/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.types.ts index a0bc56bd..9ee28fe5 100644 --- a/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.types.ts +++ b/src/views/inventory/views/furniture/results/InventoryFurnitureResultsView.types.ts @@ -3,4 +3,5 @@ import { GroupItem } from '../../../common/GroupItem'; export interface InventoryFurnitureResultsViewProps { groupItems: GroupItem[]; + columns?: number; } diff --git a/src/views/inventory/views/furniture/search/InventoryFurnitureSearchView.scss b/src/views/inventory/views/furniture/search/InventoryFurnitureSearchView.scss deleted file mode 100644 index e69de29b..00000000 diff --git a/src/views/inventory/views/furniture/search/InventoryFurnitureSearchView.tsx b/src/views/inventory/views/furniture/search/InventoryFurnitureSearchView.tsx index e8d4f05c..841999b2 100644 --- a/src/views/inventory/views/furniture/search/InventoryFurnitureSearchView.tsx +++ b/src/views/inventory/views/furniture/search/InventoryFurnitureSearchView.tsx @@ -15,7 +15,7 @@ export const InventoryFurnitureSearchView: FC { const comparison = searchValue.toLocaleLowerCase(); - filteredGroupItems = filteredGroupItems.filter(item => + filteredGroupItems = groupItems.filter(item => { if(comparison && comparison.length) { diff --git a/src/views/inventory/views/pet/InventoryPetView.scss b/src/views/inventory/views/pet/InventoryPetView.scss deleted file mode 100644 index 7afd161a..00000000 --- a/src/views/inventory/views/pet/InventoryPetView.scss +++ /dev/null @@ -1,2 +0,0 @@ -@import './item/InventoryPetItemView'; -@import './results/InventoryPetResultsView'; diff --git a/src/views/inventory/views/pet/item/InventoryPetItemView.scss b/src/views/inventory/views/pet/item/InventoryPetItemView.scss deleted file mode 100644 index 17156c99..00000000 --- a/src/views/inventory/views/pet/item/InventoryPetItemView.scss +++ /dev/null @@ -1,17 +0,0 @@ -.inventory-pet-item-container { - height: 48px; - max-height: 48px; - - .inventory-pet-item { - width: 100%; - height: 100%; - border-color: $grid-border-color !important; - background-color: $grid-bg-color; - overflow: hidden; - - &.active { - border-color: $grid-active-border-color!important; - background-color: $grid-active-bg-color; - } - } -} diff --git a/src/views/inventory/views/pet/item/InventoryPetItemView.tsx b/src/views/inventory/views/pet/item/InventoryPetItemView.tsx index cd99c6bc..d9a56dda 100644 --- a/src/views/inventory/views/pet/item/InventoryPetItemView.tsx +++ b/src/views/inventory/views/pet/item/InventoryPetItemView.tsx @@ -1,5 +1,6 @@ import { MouseEventType } from 'nitro-renderer'; import { FC, MouseEvent, useCallback, useState } from 'react'; +import { NitroCardGridItemView } from '../../../../../layout/card/grid/item/NitroCardGridItemView'; import { PetImageView } from '../../../../shared/pet-image/PetImageView'; import { attemptPetPlacement } from '../../../common/PetUtilities'; import { useInventoryContext } from '../../../context/InventoryContext'; @@ -37,10 +38,8 @@ export const InventoryPetItemView: FC = props => }, [ isActive, isMouseDown, petItem, dispatchPetState ]); return ( -
-
- -
-
+ + + ); } diff --git a/src/views/inventory/views/pet/results/InventoryPetResultsView.scss b/src/views/inventory/views/pet/results/InventoryPetResultsView.scss deleted file mode 100644 index f5a48826..00000000 --- a/src/views/inventory/views/pet/results/InventoryPetResultsView.scss +++ /dev/null @@ -1,5 +0,0 @@ -.pet-item-container { - height: 220px; - max-height: 220px; - overflow-y: auto; -} diff --git a/src/views/inventory/views/pet/results/InventoryPetResultsView.tsx b/src/views/inventory/views/pet/results/InventoryPetResultsView.tsx index 21e99114..fb7fae4f 100644 --- a/src/views/inventory/views/pet/results/InventoryPetResultsView.tsx +++ b/src/views/inventory/views/pet/results/InventoryPetResultsView.tsx @@ -1,4 +1,5 @@ import { FC } from 'react'; +import { NitroCardGridView } from '../../../../../layout/card/grid/NitroCardGridView'; import { InventoryPetItemView } from '../item/InventoryPetItemView'; import { InventoryPetResultsViewProps } from './InventoryPetResultsView.types'; @@ -7,13 +8,11 @@ export const InventoryPetResultsView: FC = props = const { petItems = [] } = props; return ( -
-
+ { petItems && (petItems.length > 0) && petItems.map(item => - { - return - }) } -
-
+ { + return + }) } + ); } diff --git a/src/views/inventory/views/trade/InventoryTradeView.tsx b/src/views/inventory/views/trade/InventoryTradeView.tsx index 88fe8f7f..212ca779 100644 --- a/src/views/inventory/views/trade/InventoryTradeView.tsx +++ b/src/views/inventory/views/trade/InventoryTradeView.tsx @@ -1,36 +1,203 @@ -import { FC } from 'react'; +import { FurnitureListComposer, IObjectData, TradingListAddItemComposer, TradingListAddItemsComposer, TradingListItemRemoveComposer } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { SendMessageHook } from '../../../../hooks/messages'; +import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView'; +import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; import { LocalizeText } from '../../../../utils/LocalizeText'; +import { FurniCategory } from '../../common/FurniCategory'; +import { GroupItem } from '../../common/GroupItem'; +import { IFurnitureItem } from '../../common/IFurnitureItem'; +import { _Str_16998 } from '../../common/TradingUtilities'; import { useInventoryContext } from '../../context/InventoryContext'; +import { InventoryFurnitureActions } from '../../reducers/InventoryFurnitureReducer'; +import { InventoryFurnitureSearchView } from '../furniture/search/InventoryFurnitureSearchView'; import { InventoryTradeViewProps } from './InventoryTradeView.types'; -import { InventoryTradeItemView } from './item/InventoryTradeItemView'; -const MAX_ITEMS_COUNT: number = 9; +const MAX_ITEMS_TO_TRADE: number = 9; export const InventoryTradeView: FC = props => { - const { isInFurnitureView = false } = props; - const { furnitureState = null } = useInventoryContext(); - const { tradeData = null } = furnitureState; + const { furnitureState = null, dispatchFurnitureState = null } = useInventoryContext(); + const { needsFurniUpdate = false, groupItems = [], tradeData = null } = furnitureState; + const [ groupItem, setGroupItem ] = useState(null); + const [ selectedGroupItem, setSelectedGroupItem ] = useState(null); + const [ filteredGroupItems, setFilteredGroupItems ] = useState(null); + + const close = useCallback(() => + { + + }, []); + + const canTradeItem = useCallback((isWallItem: boolean, spriteId: number, category: number, groupable: boolean, stuffData: IObjectData) => + { + if(!tradeData || !tradeData.ownUser || tradeData.ownUser.accepts || !tradeData.ownUser.items) return false; + + if(tradeData.ownUser.items.length < MAX_ITEMS_TO_TRADE) return true; + + if(!groupable) return false; + + let type = spriteId.toString(); + + if(category === FurniCategory._Str_5186) + { + type = ((type + 'poster') + stuffData.getLegacyString()); + } + else + { + if(category === FurniCategory._Str_12454) + { + type = _Str_16998(spriteId, stuffData); + } + else + { + type = (((isWallItem) ? 'I' : 'S') + type); + } + } + + return !!tradeData.ownUser.items.getValue(type); + }, [ tradeData ]); + + const attemptItemOffer = useCallback((count: number) => + { + if(!tradeData || !groupItem) return; + + const tradeItems = groupItem.getTradeItems(count); + + if(!tradeItems || !tradeItems.length) return; + + let coreItem: IFurnitureItem = null; + const itemIds: number[] = []; + + for(const item of tradeItems) + { + itemIds.push(item.id); + + if(!coreItem) coreItem = item; + } + + const ownItemCount = tradeData.ownUser.items.length; + + if((ownItemCount + itemIds.length) <= 1500) + { + if(!coreItem.isGroupable && (itemIds.length)) + { + SendMessageHook(new TradingListAddItemComposer(itemIds.pop())); + } + else + { + const tradeIds: number[] = []; + + for(const itemId of itemIds) + { + if(canTradeItem(coreItem.isWallItem, coreItem.type, coreItem.category, coreItem.isGroupable, coreItem.stuffData)) + { + tradeIds.push(itemId); + } + } + + if(tradeIds.length) + { + if(tradeIds.length === 1) + { + SendMessageHook(new TradingListAddItemComposer(tradeIds.pop())); + } + else + { + SendMessageHook(new TradingListAddItemsComposer(...tradeIds)); + } + } + } + } + else + { + //this._notificationService.alert('${trading.items.too_many_items.desc}', '${trading.items.too_many_items.title}'); + } + }, [ groupItem, tradeData, canTradeItem ]); + + const removeItem = useCallback((group: GroupItem) => + { + const item = group.getLastItem(); + + if(!item) return; + + SendMessageHook(new TradingListItemRemoveComposer(item.id)); + }, []); + + useEffect(() => + { + if(needsFurniUpdate) + { + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_NEEDS_UPDATE, + payload: { + flag: false + } + }); + + SendMessageHook(new FurnitureListComposer()); + } + else + { + setFilteredGroupItems(groupItems); + } + + }, [ needsFurniUpdate, groupItems, dispatchFurnitureState ]); return ( -
-
-
{ LocalizeText('inventory.trading.you') }
-
- { Array.from(Array(MAX_ITEMS_COUNT), (e, i) => - { - return ; - }) } -
+
+
+ + + { filteredGroupItems && (filteredGroupItems.length > 0) && filteredGroupItems.map((item, index) => + { + const count = item.getUnlockedCount(); + + return ( + (count && setGroupItem(item)) }> + { ((count > 0) && (groupItem === item)) && + } + + ); + }) } +
-
+
+
{ LocalizeText('inventory.trading.you') }
+ + { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => + { + const item = (tradeData.ownUser.items.getWithIndex(i) || null); + + if(!item) return ; + + return ( + setSelectedGroupItem(item) }> + { (item === selectedGroupItem) && + } + + ); + }) } + +
+
{ tradeData.otherUser.userName }
-
- { Array.from(Array(MAX_ITEMS_COUNT), (e, i) => - { - return ; - }) } -
+ + { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => + { + const item = (tradeData.otherUser.items.getWithIndex(i) || null); + + if(!item) return ; + + return setSelectedGroupItem(item) } />; + }) } + +
+
+ plz
); diff --git a/src/views/inventory/views/trade/InventoryTradeView.types.ts b/src/views/inventory/views/trade/InventoryTradeView.types.ts index aa863e89..ee344ff2 100644 --- a/src/views/inventory/views/trade/InventoryTradeView.types.ts +++ b/src/views/inventory/views/trade/InventoryTradeView.types.ts @@ -1,4 +1,3 @@ export interface InventoryTradeViewProps { - isInFurnitureView: boolean; } diff --git a/src/views/inventory/views/trade/item/InventoryTradeItemView.tsx b/src/views/inventory/views/trade/item/InventoryTradeItemView.tsx deleted file mode 100644 index 75627b04..00000000 --- a/src/views/inventory/views/trade/item/InventoryTradeItemView.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import { FC, useCallback } from 'react'; -import { LimitedEditionStyledNumberView } from '../../../../shared/limited-edition/styled-number/LimitedEditionStyledNumberView'; -import { InventoryTradeItemViewProps } from './InventoryTradeItemView.types'; - -export const InventoryTradeItemView: FC = props => -{ - const { groupItem = null } = props; - - const onClick = useCallback(() => - { - - }, []); - - if(!groupItem) - { - return ( -
-
-
- ); - } - - const imageUrl = `url(${ groupItem.iconUrl })`; - - return ( -
-
- { groupItem.getUnlockedCount() > 1 && - { groupItem.getUnlockedCount() } } - { groupItem.stuffData.isUnique && -
- -
} -
-
- ); -} diff --git a/src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts b/src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts deleted file mode 100644 index 29740d21..00000000 --- a/src/views/inventory/views/trade/item/InventoryTradeItemView.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { GroupItem } from '../../../common/GroupItem'; - -export interface InventoryTradeItemViewProps -{ - groupItem: GroupItem; -} From c9b7fcd841cfa4d853c27f0aa1846514ab6671e9 Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 6 Jul 2021 22:36:10 -0400 Subject: [PATCH 26/72] Fix badges --- src/views/inventory/views/badge/item/InventoryBadgeItemView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/inventory/views/badge/item/InventoryBadgeItemView.tsx b/src/views/inventory/views/badge/item/InventoryBadgeItemView.tsx index fc221a7d..61b15095 100644 --- a/src/views/inventory/views/badge/item/InventoryBadgeItemView.tsx +++ b/src/views/inventory/views/badge/item/InventoryBadgeItemView.tsx @@ -25,7 +25,7 @@ export const InventoryBadgeItemView: FC = props => }, [ badge, dispatchBadgeState ]); return ( - + ); From eac77940911d1b71b756c30ae4830bedde67d934 Mon Sep 17 00:00:00 2001 From: Layne Date: Tue, 6 Jul 2021 22:39:28 -0400 Subject: [PATCH 27/72] bills busted fixes :tm: --- .../views/badge/InventoryBadgeView.scss | 2 +- .../views/trade/InventoryTradeView.tsx | 64 ++++++++++--------- 2 files changed, 34 insertions(+), 32 deletions(-) diff --git a/src/views/inventory/views/badge/InventoryBadgeView.scss b/src/views/inventory/views/badge/InventoryBadgeView.scss index 7285ce2f..fc975ace 100644 --- a/src/views/inventory/views/badge/InventoryBadgeView.scss +++ b/src/views/inventory/views/badge/InventoryBadgeView.scss @@ -7,7 +7,7 @@ } .inventory-badge-overflow { - height: calc(100% - 86px); + height: calc(100% - 91px); } @import './item/InventoryBadgeItemView'; diff --git a/src/views/inventory/views/trade/InventoryTradeView.tsx b/src/views/inventory/views/trade/InventoryTradeView.tsx index 212ca779..b95716ab 100644 --- a/src/views/inventory/views/trade/InventoryTradeView.tsx +++ b/src/views/inventory/views/trade/InventoryTradeView.tsx @@ -163,41 +163,43 @@ export const InventoryTradeView: FC = props => }) }
-
-
{ LocalizeText('inventory.trading.you') }
- - { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => - { - const item = (tradeData.ownUser.items.getWithIndex(i) || null); +
+
+
{ LocalizeText('inventory.trading.you') }
+ + { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => + { + const item = (tradeData.ownUser.items.getWithIndex(i) || null); - if(!item) return ; + if(!item) return ; - return ( - setSelectedGroupItem(item) }> - { (item === selectedGroupItem) && - } - - ); - }) } - -
-
-
{ tradeData.otherUser.userName }
- - { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => - { - const item = (tradeData.otherUser.items.getWithIndex(i) || null); + return ( + setSelectedGroupItem(item) }> + { (item === selectedGroupItem) && + } + + ); + }) } + +
+
+
{ tradeData.otherUser.userName }
+ + { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => + { + const item = (tradeData.otherUser.items.getWithIndex(i) || null); - if(!item) return ; + if(!item) return ; - return setSelectedGroupItem(item) } />; - }) } - -
-
- plz + return setSelectedGroupItem(item) } />; + }) } + +
+
+ plz +
); From f6194e7f137fe25184df49c8771adc1d2d55dd99 Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 7 Jul 2021 03:56:11 -0400 Subject: [PATCH 28/72] Add friend name bubbles --- .../friend-list/FriendEnteredRoomEvent.ts | 11 ++ src/events/friend-list/index.ts | 1 + src/views/friend-list/FriendListView.tsx | 32 +++++- .../room/events/RoomWidgetObjectNameEvent.ts | 4 +- .../handlers/RoomWidgetInfostandHandler.ts | 2 +- .../avatar-info/AvatarInfoWidgetView.tsx | 104 ++++++++++++------ 6 files changed, 112 insertions(+), 42 deletions(-) create mode 100644 src/events/friend-list/FriendEnteredRoomEvent.ts diff --git a/src/events/friend-list/FriendEnteredRoomEvent.ts b/src/events/friend-list/FriendEnteredRoomEvent.ts new file mode 100644 index 00000000..5a7755eb --- /dev/null +++ b/src/events/friend-list/FriendEnteredRoomEvent.ts @@ -0,0 +1,11 @@ +import { RoomWidgetObjectNameEvent } from '../../views/room/events'; + +export class FriendEnteredRoomEvent extends RoomWidgetObjectNameEvent +{ + public static ENTERED: string = 'FERE_ENTERED'; + + constructor(roomIndex: number, category: number, id: number, name: string, userType: number) + { + super(FriendEnteredRoomEvent.ENTERED, roomIndex, category, id, name, userType); + } +} diff --git a/src/events/friend-list/index.ts b/src/events/friend-list/index.ts index 413293c4..4789fde9 100644 --- a/src/events/friend-list/index.ts +++ b/src/events/friend-list/index.ts @@ -1 +1,2 @@ +export * from './FriendEnteredRoomEvent'; export * from './FriendListEvent'; diff --git a/src/views/friend-list/FriendListView.tsx b/src/views/friend-list/FriendListView.tsx index defd406c..a620c0ea 100644 --- a/src/views/friend-list/FriendListView.tsx +++ b/src/views/friend-list/FriendListView.tsx @@ -1,8 +1,10 @@ -import { MessengerInitComposer } from 'nitro-renderer'; +import { MessengerInitComposer, RoomEngineObjectEvent, RoomObjectCategory } from 'nitro-renderer'; import React, { FC, useCallback, useEffect, useReducer, useState } from 'react'; import { createPortal } from 'react-dom'; -import { FriendListEvent } from '../../events'; -import { useUiEvent } from '../../hooks/events/ui/ui-event'; +import { GetRoomSession } from '../../api'; +import { FriendEnteredRoomEvent, FriendListEvent } from '../../events'; +import { useRoomEngineEvent } from '../../hooks/events'; +import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event'; import { SendMessageHook } from '../../hooks/messages/message-event'; import { NitroCardAccordionItemView, NitroCardAccordionView, NitroCardHeaderView, NitroCardView } from '../../layout'; import { LocalizeText } from '../../utils/LocalizeText'; @@ -48,6 +50,30 @@ export const FriendListView: FC = props => SendMessageHook(new MessengerInitComposer()); }, []); + const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) => + { + const roomSession = GetRoomSession(); + + if(!roomSession) return; + + if(event.category !== RoomObjectCategory.UNIT) return; + + const userData = roomSession.userDataManager.getUserDataByIndex(event.objectId); + + if(!userData) return; + + const friend = friendListState.friends.find(friend => + { + return (friend.id === userData.webID); + }); + + if(!friend) return; + + dispatchUiEvent(new FriendEnteredRoomEvent(userData.roomIndex, RoomObjectCategory.UNIT, userData.webID, userData.name, userData.type)); + }, [ friendListState.friends ]); + + useRoomEngineEvent(RoomEngineObjectEvent.ADDED, onRoomEngineObjectEvent); + return ( diff --git a/src/views/room/events/RoomWidgetObjectNameEvent.ts b/src/views/room/events/RoomWidgetObjectNameEvent.ts index 2a3773e4..87fbe42f 100644 --- a/src/views/room/events/RoomWidgetObjectNameEvent.ts +++ b/src/views/room/events/RoomWidgetObjectNameEvent.ts @@ -10,9 +10,9 @@ export class RoomWidgetObjectNameEvent extends RoomWidgetUpdateEvent private _name: string; private _userType: number; - constructor(roomIndex: number, category: number, id: number, name: string, userType: number) + constructor(type: string, roomIndex: number, category: number, id: number, name: string, userType: number) { - super(RoomWidgetObjectNameEvent.TYPE); + super(type); this._roomIndex = roomIndex; this._category = category; diff --git a/src/views/room/handlers/RoomWidgetInfostandHandler.ts b/src/views/room/handlers/RoomWidgetInfostandHandler.ts index 9ad903bf..287c980c 100644 --- a/src/views/room/handlers/RoomWidgetInfostandHandler.ts +++ b/src/views/room/handlers/RoomWidgetInfostandHandler.ts @@ -286,7 +286,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler } } - if(name) this.container.eventDispatcher.dispatchEvent(new RoomWidgetObjectNameEvent(message.id, message.category, id, name, userType)); + if(name) this.container.eventDispatcher.dispatchEvent(new RoomWidgetObjectNameEvent(RoomWidgetObjectNameEvent.TYPE, message.id, message.category, id, name, userType)); return null; } diff --git a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx index 7d06c1e3..34626ff8 100644 --- a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx +++ b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx @@ -1,6 +1,8 @@ import { RoomEnterEffect, RoomObjectCategory } from 'nitro-renderer'; import { FC, useCallback, useMemo, useState } from 'react'; import { GetRoomSession, GetSessionDataManager } from '../../../../api'; +import { FriendEnteredRoomEvent } from '../../../../events'; +import { useUiEvent } from '../../../../hooks/events'; import { CreateEventDispatcherHook } from '../../../../hooks/events/event-dispatcher.base'; import { useRoomContext } from '../../context/RoomContext'; import { RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRentableBotChatEvent } from '../../events'; @@ -19,12 +21,35 @@ export const AvatarInfoWidgetView: FC = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); const [ name, setName ] = useState(null); + const [ nameBubbles, setNameBubbles ] = useState([]); const [ infoStandEvent, setInfoStandEvent ] = useState(null); const [ isGameMode, setGameMode ] = useState(false); const [ isDancing, setIsDancing ] = useState(false); const [ isDecorating, setIsDecorating ] = useState(GetRoomSession().isDecorating); const [ rentableBotChatEvent, setRentableBotChatEvent ] = useState(null); + const removeNameBubble = useCallback((index: number) => + { + setNameBubbles(prevValue => + { + const newValue = [ ...prevValue ]; + + newValue.splice(index, 1); + + return newValue; + }); + }, []); + + const clearInfoStandEvent = useCallback(() => + { + setInfoStandEvent(null); + }, []); + + const clearName = useCallback(() => + { + setName(null); + }, []); + const onRoomWidgetRoomEngineUpdateEvent = useCallback((event: RoomWidgetRoomEngineUpdateEvent) => { switch(event.type) @@ -50,6 +75,16 @@ export const AvatarInfoWidgetView: FC = props => if(event.id === name.id) setName(null); } + if(event.category === RoomObjectCategory.UNIT) + { + const nameBubbleIndex = nameBubbles.findIndex(bubble => + { + return (bubble.roomIndex === event.id); + }); + + if(nameBubbleIndex > -1) removeNameBubble(nameBubbleIndex); + } + if(infoStandEvent) { if(infoStandEvent instanceof RoomWidgetUpdateInfostandFurniEvent) @@ -67,7 +102,7 @@ export const AvatarInfoWidgetView: FC = props => if(infoStandEvent.roomIndex === event.id) setInfoStandEvent(null); } } - }, [ name, infoStandEvent ]); + }, [ name, infoStandEvent, nameBubbles, removeNameBubble ]); CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_REMOVED, eventDispatcher, onRoomObjectRemoved); CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomObjectRemoved); @@ -104,8 +139,6 @@ export const AvatarInfoWidgetView: FC = props => { if(!infoStandEvent) return; - console.log('tru') - setInfoStandEvent(null); }, [ infoStandEvent ]); @@ -142,26 +175,6 @@ export const AvatarInfoWidgetView: FC = props => CreateEventDispatcherHook(RoomWidgetUpdateDanceStatusEvent.UPDATE_DANCE, eventDispatcher, onRoomWidgetUpdateDanceStatusEvent); - const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => - { - switch(event.type) - { - case RoomWidgetRoomObjectUpdateEvent.USER_ADDED: { - // bubble if friend - - return; - } - case RoomWidgetRoomObjectUpdateEvent.OBJECT_SELECTED: { - // set if waiting for pet - - return; - } - } - }, []); - - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_ADDED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_SELECTED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent); - const onRoomWidgetUpdateRentableBotChatEvent = useCallback((event: RoomWidgetUpdateRentableBotChatEvent) => { setRentableBotChatEvent(event); @@ -169,6 +182,16 @@ export const AvatarInfoWidgetView: FC = props => CreateEventDispatcherHook(RoomWidgetUpdateRentableBotChatEvent.UPDATE_CHAT, eventDispatcher, onRoomWidgetUpdateRentableBotChatEvent); + const onFriendEnteredRoomEvent = useCallback((event: FriendEnteredRoomEvent) => + { + setNameBubbles(prevValue => + { + return [ ...prevValue, event ]; + }) + }, []); + + useUiEvent(FriendEnteredRoomEvent.ENTERED, onFriendEnteredRoomEvent); + const decorateView = useMemo(() => { GetRoomSession().isDecorating = isDecorating; @@ -182,23 +205,23 @@ export const AvatarInfoWidgetView: FC = props => return ; }, [ isDecorating ]); - const clearInfoStandEvent = useCallback(() => - { - setInfoStandEvent(null); - }, []); - - const clearName = useCallback(() => - { - setName(null); - }, []); - const currentView = useMemo(() => { if(isGameMode) return null; if(decorateView) return decorateView; - if(name) return ; + if(name) + { + const nameBubbleIndex = nameBubbles.findIndex(bubble => + { + return (bubble.roomIndex === name.roomIndex); + }); + + if(nameBubbleIndex > -1) removeNameBubble(nameBubbleIndex); + + return ; + } if(infoStandEvent) { @@ -210,7 +233,12 @@ export const AvatarInfoWidgetView: FC = props => if(event.isSpectatorMode) return null; - // if existing name bubble remove it + const nameBubbleIndex = nameBubbles.findIndex(bubble => + { + return (bubble.roomIndex === event.roomIndex); + }); + + if(nameBubbleIndex > -1) removeNameBubble(nameBubbleIndex); if(event.isOwnUser) { @@ -241,11 +269,15 @@ export const AvatarInfoWidgetView: FC = props => } return null; - }, [ isGameMode, decorateView, name, isDancing, infoStandEvent, clearName, clearInfoStandEvent ]); + }, [ isGameMode, decorateView, name, nameBubbles, isDancing, infoStandEvent, clearName, clearInfoStandEvent, removeNameBubble ]); return ( <> { currentView } + { (nameBubbles.length > 0) && nameBubbles.map((name, index) => + { + return removeNameBubble(index) } />; + }) } { rentableBotChatEvent && } ) From a9eff4f0ae64ab0f8e0897e4b6fe396b6a37d6a8 Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 7 Jul 2021 05:05:14 -0400 Subject: [PATCH 29/72] Fix index issue on friend bubbles --- src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx index 34626ff8..1514df9e 100644 --- a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx +++ b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx @@ -276,7 +276,7 @@ export const AvatarInfoWidgetView: FC = props => { currentView } { (nameBubbles.length > 0) && nameBubbles.map((name, index) => { - return removeNameBubble(index) } />; + return removeNameBubble(index) } />; }) } { rentableBotChatEvent && } From 4cdd89c25b97e30e2bdd0f31dc36cc3adbea968f Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 7 Jul 2021 05:05:27 -0400 Subject: [PATCH 30/72] Trading works --- .../inventory/InventoryMessageHandler.tsx | 118 ++++++++++------ src/views/inventory/InventoryView.tsx | 55 +++++--- .../furniture/InventoryFurnitureView.tsx | 8 +- .../views/trade/InventoryTradeView.tsx | 128 +++++++++++++++--- .../views/trade/InventoryTradeView.types.ts | 1 + 5 files changed, 223 insertions(+), 87 deletions(-) diff --git a/src/views/inventory/InventoryMessageHandler.tsx b/src/views/inventory/InventoryMessageHandler.tsx index d28f0edf..e00fb7f4 100644 --- a/src/views/inventory/InventoryMessageHandler.tsx +++ b/src/views/inventory/InventoryMessageHandler.tsx @@ -1,4 +1,4 @@ -import { AdvancedMap, BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory, TradingAcceptEvent, TradingCloseEvent, TradingCompletedEvent, TradingConfirmationEvent, TradingListItemEvent, TradingOpenEvent } from 'nitro-renderer'; +import { AdvancedMap, BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory, TradingAcceptEvent, TradingCloseEvent, TradingCompletedEvent, TradingConfirmationEvent, TradingListItemEvent, TradingNotOpenEvent, TradingOpenEvent, TradingOpenFailedEvent, TradingOtherNotAllowedEvent, TradingYouAreNotAllowedEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; import { GetRoomSession, GetSessionDataManager } from '../../api'; import { CreateMessageHook } from '../../hooks/messages/message-event'; @@ -176,6 +176,59 @@ export const InventoryMessageHandler: FC = props = }); }, [ dispatchFurnitureState ]); + const onTradingCloseEvent = useCallback((event: TradingCloseEvent) => + { + const parser = event.getParser(); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.CLOSE_TRADE, + payload: {} + }); + }, [ dispatchFurnitureState ]); + + const onTradingCompletedEvent = useCallback((event: TradingCompletedEvent) => + { + const parser = event.getParser(); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.CLOSE_TRADE, + payload: {} + }); + }, [ dispatchFurnitureState ]); + + const onTradingConfirmationEvent = useCallback((event: TradingConfirmationEvent) => + { + const parser = event.getParser(); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_TRADE_STATE, + payload: { + tradeState: TradeState.TRADING_STATE_COUNTDOWN + } + }); + }, [ dispatchFurnitureState ]); + + const onTradingListItemEvent = useCallback((event: TradingListItemEvent) => + { + const parser = event.getParser(); + + console.log(parser); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.UPDATE_TRADE, + payload: { + tradeParser: event.getParser() + } + }); + }, [ dispatchFurnitureState ]); + + const onTradingNotOpenEvent = useCallback((event: TradingNotOpenEvent) => + { + const parser = event.getParser(); + + console.log(parser); + }, []); + const onTradingOpenEvent = useCallback((event: TradingOpenEvent) => { const parser = event.getParser(); @@ -220,53 +273,26 @@ export const InventoryMessageHandler: FC = props = }); }, [ dispatchFurnitureState ]); - const onTradingCloseEvent = useCallback((event: TradingCloseEvent) => - { - const parser = event.getParser(); - - dispatchFurnitureState({ - type: InventoryFurnitureActions.CLOSE_TRADE, - payload: {} - }); - }, [ dispatchFurnitureState ]); - - const onTradingCompletedEvent = useCallback((event: TradingCompletedEvent) => - { - const parser = event.getParser(); - - dispatchFurnitureState({ - type: InventoryFurnitureActions.SET_TRADE_STATE, - payload: { - tradeState: TradeState.TRADING_STATE_COMPLETED - } - }); - }, [ dispatchFurnitureState ]); - - const onTradingConfirmationEvent = useCallback((event: TradingConfirmationEvent) => - { - const parser = event.getParser(); - - dispatchFurnitureState({ - type: InventoryFurnitureActions.SET_TRADE_STATE, - payload: { - tradeState: TradeState.TRADING_STATE_CONFIRMED - } - }); - }, [ dispatchFurnitureState ]); - - const onTradingListItemEvent = useCallback((event: TradingListItemEvent) => + const onTradingOpenFailedEvent = useCallback((event: TradingOpenFailedEvent) => { const parser = event.getParser(); console.log(parser); + }, []); - dispatchFurnitureState({ - type: InventoryFurnitureActions.UPDATE_TRADE, - payload: { - tradeParser: event.getParser() - } - }); - }, [ dispatchFurnitureState ]); + const onTradingOtherNotAllowedEvent = useCallback((event: TradingOtherNotAllowedEvent) => + { + const parser = event.getParser(); + + console.log(parser); + }, []); + + const onTradingYouAreNotAllowedEvent = useCallback((event: TradingYouAreNotAllowedEvent) => + { + const parser = event.getParser(); + + console.log(parser); + }, []); CreateMessageHook(FurnitureListAddOrUpdateEvent, onFurnitureListAddOrUpdateEvent); CreateMessageHook(FurnitureListEvent, onFurnitureListEvent); @@ -281,11 +307,15 @@ export const InventoryMessageHandler: FC = props = CreateMessageHook(PetAddedToInventoryEvent, onPetAddedToInventoryEvent); CreateMessageHook(BadgesEvent, onBadgesEvent); CreateMessageHook(TradingAcceptEvent, onTradingAcceptEvent); - CreateMessageHook(TradingOpenEvent, onTradingOpenEvent); CreateMessageHook(TradingCloseEvent, onTradingCloseEvent); CreateMessageHook(TradingCompletedEvent, onTradingCompletedEvent); CreateMessageHook(TradingConfirmationEvent, onTradingConfirmationEvent); CreateMessageHook(TradingListItemEvent, onTradingListItemEvent); + CreateMessageHook(TradingNotOpenEvent, onTradingNotOpenEvent); + CreateMessageHook(TradingOpenEvent, onTradingOpenEvent); + CreateMessageHook(TradingOpenFailedEvent, onTradingOpenFailedEvent); + CreateMessageHook(TradingOtherNotAllowedEvent, onTradingOtherNotAllowedEvent); + CreateMessageHook(TradingYouAreNotAllowedEvent, onTradingYouAreNotAllowedEvent); return null; } diff --git a/src/views/inventory/InventoryView.tsx b/src/views/inventory/InventoryView.tsx index a0905bc4..8896d6b6 100644 --- a/src/views/inventory/InventoryView.tsx +++ b/src/views/inventory/InventoryView.tsx @@ -1,13 +1,15 @@ -import { IRoomSession, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent, TradingOpenComposer } from 'nitro-renderer'; +import { IRoomSession, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent, TradingCancelComposer, TradingCloseComposer, TradingOpenComposer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; import { GetConnection, GetRoomEngine } from '../../api'; import { InventoryEvent, InventoryTradeRequestEvent } from '../../events'; import { useRoomEngineEvent } from '../../hooks/events/nitro/room/room-engine-event'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; import { useUiEvent } from '../../hooks/events/ui/ui-event'; +import { SendMessageHook } from '../../hooks/messages'; import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout'; import { LocalizeText } from '../../utils/LocalizeText'; import { isObjectMoverRequested, setObjectMoverRequested } from './common/InventoryUtilities'; +import { TradeState } from './common/TradeState'; import { InventoryContextProvider } from './context/InventoryContext'; import { InventoryMessageHandler } from './InventoryMessageHandler'; import { InventoryTabs, InventoryViewProps } from './InventoryView.types'; @@ -34,18 +36,47 @@ export const InventoryView: FC = props => const [ petState, dispatchPetState ] = useReducer(InventoryPetReducer, initialInventoryPet); const [ badgeState, dispatchBadgeState ] = useReducer(InventoryBadgeReducer, initialInventoryBadge); + const close = useCallback(() => + { + if(furnitureState.tradeData) + { + switch(furnitureState.tradeData.state) + { + case TradeState.TRADING_STATE_RUNNING: + SendMessageHook(new TradingCloseComposer()); + return; + case TradeState.TRADING_STATE_CONFIRMING: + SendMessageHook(new TradingCancelComposer()); + return; + } + } + + setIsVisible(false); + }, [ furnitureState.tradeData ]); + const onInventoryEvent = useCallback((event: InventoryEvent) => { switch(event.type) { case InventoryEvent.SHOW_INVENTORY: + if(isVisible) return; + setIsVisible(true); return; case InventoryEvent.HIDE_INVENTORY: - setIsVisible(false); + if(!isVisible) return; + + close(); return; case InventoryEvent.TOGGLE_INVENTORY: - setIsVisible(value => !value); + if(!isVisible) + { + setIsVisible(true); + } + else + { + close(); + } return; case InventoryTradeRequestEvent.REQUEST_TRADE: { const tradeEvent = (event as InventoryTradeRequestEvent); @@ -53,7 +84,7 @@ export const InventoryView: FC = props => GetConnection().send(new TradingOpenComposer(tradeEvent.objectId)); } } - }, []); + }, [ isVisible, close ]); useUiEvent(InventoryEvent.SHOW_INVENTORY, onInventoryEvent); useUiEvent(InventoryEvent.HIDE_INVENTORY, onInventoryEvent); @@ -103,21 +134,11 @@ export const InventoryView: FC = props => } }, []); - useEffect(() => - { - if(!furnitureState.tradeData) return; - - setIsVisible(true); - }, [ furnitureState.tradeData ]); - useEffect(() => { if(!isVisible) { - if(furnitureState.tradeData) - { - // cancel the trade - } + if(furnitureState.tradeData) setIsVisible(true); } }, [ furnitureState.tradeData, isVisible ]); @@ -126,7 +147,7 @@ export const InventoryView: FC = props => { isVisible && - setIsVisible(false) } /> + { !furnitureState.tradeData && <> @@ -152,7 +173,7 @@ export const InventoryView: FC = props => } { furnitureState.tradeData && - + } } diff --git a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx index 99f0693e..be45bc0b 100644 --- a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx +++ b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx @@ -1,6 +1,6 @@ import { FurnitureListComposer, RoomObjectVariable, Vector3d } from 'nitro-renderer'; import { FC, useEffect, useState } from 'react'; -import { GetRoomEngine } from '../../../../api'; +import { GetRoomEngine, GetSessionDataManager } from '../../../../api'; import { SendMessageHook } from '../../../../hooks/messages'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { LimitedEditionCompactPlateView } from '../../../shared/limited-edition/compact-plate/LimitedEditionCompactPlateView'; @@ -80,9 +80,9 @@ export const InventoryFurnitureView: FC = props => if(furnitureItem.category === FurniCategory._Str_3432) { - // insert a window if the type is landscape - //_local_19 = this._model.controller._Str_18225("ads_twi_windw", ProductTypeEnum.WALL); - //this._roomPreviewer._Str_12087(_local_19.id, new Vector3d(90, 0, 0), _local_19._Str_4558); + const data = GetSessionDataManager().getWallItemDataByName('noob_window_double'); + + if(data) roomPreviewer.addWallItemIntoRoom(data.id, new Vector3d(90, 0, 0), data.customParams); } } else diff --git a/src/views/inventory/views/trade/InventoryTradeView.tsx b/src/views/inventory/views/trade/InventoryTradeView.tsx index b95716ab..d7c6ad83 100644 --- a/src/views/inventory/views/trade/InventoryTradeView.tsx +++ b/src/views/inventory/views/trade/InventoryTradeView.tsx @@ -1,5 +1,5 @@ -import { FurnitureListComposer, IObjectData, TradingListAddItemComposer, TradingListAddItemsComposer, TradingListItemRemoveComposer } from 'nitro-renderer'; -import { FC, useCallback, useEffect, useState } from 'react'; +import { FurnitureListComposer, IObjectData, TradingAcceptComposer, TradingConfirmationComposer, TradingListAddItemComposer, TradingListAddItemsComposer, TradingListItemRemoveComposer, TradingUnacceptComposer } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { SendMessageHook } from '../../../../hooks/messages'; import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView'; import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; @@ -7,6 +7,7 @@ import { LocalizeText } from '../../../../utils/LocalizeText'; import { FurniCategory } from '../../common/FurniCategory'; import { GroupItem } from '../../common/GroupItem'; import { IFurnitureItem } from '../../common/IFurnitureItem'; +import { TradeState } from '../../common/TradeState'; import { _Str_16998 } from '../../common/TradingUtilities'; import { useInventoryContext } from '../../context/InventoryContext'; import { InventoryFurnitureActions } from '../../reducers/InventoryFurnitureReducer'; @@ -17,16 +18,14 @@ const MAX_ITEMS_TO_TRADE: number = 9; export const InventoryTradeView: FC = props => { + const { cancelTrade = null } = props; + const [ groupItem, setGroupItem ] = useState(null); + const [ ownGroupItem, setOwnGroupItem ] = useState(null); + const [ otherGroupItem, setOtherGroupItem ] = useState(null); + const [ filteredGroupItems, setFilteredGroupItems ] = useState(null); + const [ countdownTick, setCountdownTick ] = useState(3); const { furnitureState = null, dispatchFurnitureState = null } = useInventoryContext(); const { needsFurniUpdate = false, groupItems = [], tradeData = null } = furnitureState; - const [ groupItem, setGroupItem ] = useState(null); - const [ selectedGroupItem, setSelectedGroupItem ] = useState(null); - const [ filteredGroupItems, setFilteredGroupItems ] = useState(null); - - const close = useCallback(() => - { - - }, []); const canTradeItem = useCallback((isWallItem: boolean, spriteId: number, category: number, groupable: boolean, stuffData: IObjectData) => { @@ -136,13 +135,94 @@ export const InventoryTradeView: FC = props => SendMessageHook(new FurnitureListComposer()); } - else - { - setFilteredGroupItems(groupItems); - } }, [ needsFurniUpdate, groupItems, dispatchFurnitureState ]); + const progressTrade = useCallback(() => + { + switch(tradeData.state) + { + case TradeState.TRADING_STATE_RUNNING: + if(!tradeData.otherUser.itemCount && !tradeData.ownUser.accepts) + { + //this._notificationService.alert('${inventory.trading.warning.other_not_offering}'); + } + + if(tradeData.ownUser.accepts) + { + SendMessageHook(new TradingUnacceptComposer()); + } + else + { + SendMessageHook(new TradingAcceptComposer()); + } + return; + case TradeState.TRADING_STATE_CONFIRMING: + SendMessageHook(new TradingConfirmationComposer()); + + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_TRADE_STATE, + payload: { + tradeState: TradeState.TRADING_STATE_CONFIRMED + } + }); + return; + } + }, [ tradeData, dispatchFurnitureState ]); + + const getTradeButton = useMemo(() => + { + if(!tradeData) return null; + + switch(tradeData.state) + { + case TradeState.TRADING_STATE_READY: + return ; + case TradeState.TRADING_STATE_RUNNING: + return ; + case TradeState.TRADING_STATE_COUNTDOWN: + return ; + case TradeState.TRADING_STATE_CONFIRMING: + return ; + case TradeState.TRADING_STATE_CONFIRMED: + return ; + } + }, [ tradeData, countdownTick, progressTrade ]); + + useEffect(() => + { + if(!tradeData || (tradeData.state !== TradeState.TRADING_STATE_COUNTDOWN)) return; + + setCountdownTick(3); + + const interval = setInterval(() => + { + setCountdownTick(prevValue => + { + const newValue = (prevValue - 1); + + if(newValue === -1) + { + dispatchFurnitureState({ + type: InventoryFurnitureActions.SET_TRADE_STATE, + payload: { + tradeState: TradeState.TRADING_STATE_CONFIRMING + } + }); + + clearInterval(interval); + } + + return newValue; + }); + }, 1000); + + return () => + { + clearInterval(interval); + } + }, [ tradeData, dispatchFurnitureState ]); + return (
@@ -162,10 +242,11 @@ export const InventoryTradeView: FC = props => ); }) } +
{ groupItem ? groupItem.name : LocalizeText('catalog_selectproduct') }
-
+
-
{ LocalizeText('inventory.trading.you') }
+ { LocalizeText('inventory.trading.you') } { LocalizeText('inventory.trading.areoffering') }: { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => { @@ -174,18 +255,19 @@ export const InventoryTradeView: FC = props => if(!item) return ; return ( - setSelectedGroupItem(item) }> - { (item === selectedGroupItem) && + setOwnGroupItem(item) }> + { (ownGroupItem === item) && } ); }) } +
{ ownGroupItem ? ownGroupItem.name : LocalizeText('catalog_selectproduct') }
-
{ tradeData.otherUser.userName }
+ { tradeData.otherUser.userName } { LocalizeText('inventory.trading.isoffering') }: { Array.from(Array(MAX_ITEMS_TO_TRADE), (e, i) => { @@ -193,12 +275,14 @@ export const InventoryTradeView: FC = props => if(!item) return ; - return setSelectedGroupItem(item) } />; + return setOtherGroupItem(item) } />; }) } +
{ otherGroupItem ? otherGroupItem.name : LocalizeText('catalog_selectproduct') }
-
- plz +
+ + { getTradeButton }
diff --git a/src/views/inventory/views/trade/InventoryTradeView.types.ts b/src/views/inventory/views/trade/InventoryTradeView.types.ts index ee344ff2..c71fe143 100644 --- a/src/views/inventory/views/trade/InventoryTradeView.types.ts +++ b/src/views/inventory/views/trade/InventoryTradeView.types.ts @@ -1,3 +1,4 @@ export interface InventoryTradeViewProps { + cancelTrade: () => void; } From 7669d2bc9c9bab6f28acf20e2f98665f8aff60a8 Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 7 Jul 2021 05:05:49 -0400 Subject: [PATCH 31/72] Catalog updates --- .../navigation/item/CatalogNavigationItemView.tsx | 2 +- src/views/catalog/views/page/CatalogPageView.tsx | 8 +++----- .../layout/spaces-new/CatalogLayoutSpacesView.tsx | 14 ++++++-------- 3 files changed, 10 insertions(+), 14 deletions(-) diff --git a/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx b/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx index d1cdea58..4fcabb6b 100644 --- a/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx +++ b/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx @@ -44,7 +44,7 @@ export const CatalogNavigationItemView: FC = pro }, [ page, setActiveChild ]); return ( -
+
{ page.localization }
diff --git a/src/views/catalog/views/page/CatalogPageView.tsx b/src/views/catalog/views/page/CatalogPageView.tsx index 3b127509..f87b48fa 100644 --- a/src/views/catalog/views/page/CatalogPageView.tsx +++ b/src/views/catalog/views/page/CatalogPageView.tsx @@ -87,12 +87,10 @@ export const CatalogPageView: FC = props => return; } - // const windowData = Nitro.instance.sessionDataManager.getWallItemDataByName('ads_twi_windw'); + const windowData = GetSessionDataManager().getWallItemDataByName('noob_window_double'); + + if(windowData) roomPreviewer.addWallItemIntoRoom(windowData.id, new Vector3d(90, 0, 0), windowData.customParams); - // if(windowData) - // { - // this._roomPreviewer.addWallItemIntoRoom(windowData.id, new Vector3d(90), windowData.customParams) - // } return; } } diff --git a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx b/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx index 5b56f6a3..54ca82e5 100644 --- a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx +++ b/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx @@ -70,14 +70,12 @@ export const CatalogLayoutSpacesView: FC = props = return (
-
-
-
- { groupNames.map((name, index) => - { - return - })} -
+
+
+ { groupNames.map((name, index) => + { + return + })}
From 1966d14396358e8ffb30574723fa5cc020d900ee Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 8 Jul 2021 01:46:59 -0400 Subject: [PATCH 32/72] Notification center updates --- .../NotificationCenterAlertEvent.ts | 34 +++++ src/events/notification-center/index.ts | 1 + .../NotificationCenterMessageHandler.tsx | 66 ++++----- .../NotificationCenterView.scss | 21 +-- .../NotificationCenterView.tsx | 125 ++++-------------- .../NotificationCenterAlertBase.tsx | 18 +++ .../NotificationCenterAlertBase.types.ts | 5 + .../BroadcastMessageView.tsx | 28 ---- .../BroadcastMessageView.types.ts | 7 - ...NotificationCenterBroadcastMessageView.tsx | 30 +++++ ...icationCenterBroadcastMessageView.types.ts | 7 + .../views/motd/MOTDView.tsx | 31 ----- .../views/motd/MOTDView.types.ts | 7 - .../views/motd/NotificationCenterMotdView.tsx | 10 ++ .../motd/NotificationCenterMotdView.types.ts | 7 + 15 files changed, 178 insertions(+), 219 deletions(-) create mode 100644 src/events/notification-center/NotificationCenterAlertEvent.ts create mode 100644 src/views/notification-center/views/alert-base/NotificationCenterAlertBase.tsx create mode 100644 src/views/notification-center/views/alert-base/NotificationCenterAlertBase.types.ts delete mode 100644 src/views/notification-center/views/broadcast-message/BroadcastMessageView.tsx delete mode 100644 src/views/notification-center/views/broadcast-message/BroadcastMessageView.types.ts create mode 100644 src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.tsx create mode 100644 src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.types.ts delete mode 100644 src/views/notification-center/views/motd/MOTDView.tsx delete mode 100644 src/views/notification-center/views/motd/MOTDView.types.ts create mode 100644 src/views/notification-center/views/motd/NotificationCenterMotdView.tsx create mode 100644 src/views/notification-center/views/motd/NotificationCenterMotdView.types.ts diff --git a/src/events/notification-center/NotificationCenterAlertEvent.ts b/src/events/notification-center/NotificationCenterAlertEvent.ts new file mode 100644 index 00000000..74266659 --- /dev/null +++ b/src/events/notification-center/NotificationCenterAlertEvent.ts @@ -0,0 +1,34 @@ +import { NitroEvent } from 'nitro-renderer'; + +export class NotificationCenterAlertEvent extends NitroEvent +{ + public static HOTEL_ALERT: string = 'NCAE_HOTEL_ALERT'; + + private _message: string[]; + private _clickUrl: string; + private _headerText: string; + + constructor(type: string, message: string[], clickUrl = null, headerText = null) + { + super(type); + + this._message = message; + this._clickUrl = clickUrl; + this._headerText = headerText; + } + + public get message(): string[] + { + return this._message; + } + + public get clickUrl(): string + { + return this._clickUrl; + } + + public get headerText(): string + { + return this._headerText; + } +} diff --git a/src/events/notification-center/index.ts b/src/events/notification-center/index.ts index 2a5b66e3..37a4117b 100644 --- a/src/events/notification-center/index.ts +++ b/src/events/notification-center/index.ts @@ -1,2 +1,3 @@ export * from './NotificationCenterAddNotificationEvent'; +export * from './NotificationCenterAlertEvent'; export * from './NotificationCenterEvent'; diff --git a/src/views/notification-center/NotificationCenterMessageHandler.tsx b/src/views/notification-center/NotificationCenterMessageHandler.tsx index d25038d5..b6a845c2 100644 --- a/src/views/notification-center/NotificationCenterMessageHandler.tsx +++ b/src/views/notification-center/NotificationCenterMessageHandler.tsx @@ -1,14 +1,13 @@ import { HabboBroadcastMessageEvent, HotelWillShutdownEvent, ModeratorMessageEvent, MOTDNotificationEvent, NotificationDialogMessageEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; +import { NotificationCenterAlertEvent } from '../../events'; +import { dispatchUiEvent } from '../../hooks/events'; import { CreateMessageHook } from '../../hooks/messages'; import { useNotificationCenterContext } from './context/NotificationCenterContext'; import { INotificationCenterMessageHandlerProps } from './NotificationCenterMessageHandler.types'; import { NotificationCenterActions } from './reducers/NotificationCenterReducer'; -import { BroadcastMessageNotification } from './utils/BroadcastMessageNotification'; import { DialogMessageNotification } from './utils/DialogMessageNotification'; import { HotelWillShutdownNotification } from './utils/HotelWillShutdownNotification'; -import { ModeratorMessageNotification } from './utils/ModeratorMessageNotification'; -import { MOTDNotification } from './utils/MOTDNotification'; export const NotificationCenterMessageHandler: FC = props => { @@ -18,10 +17,31 @@ export const NotificationCenterMessageHandler: FC + { + const parser = event.getParser(); + + dispatchUiEvent(new NotificationCenterAlertEvent(NotificationCenterAlertEvent.HOTEL_ALERT, [ parser.message ], parser.link)); + }, []); + + const onMOTDNotificationEvent = useCallback((event: MOTDNotificationEvent) => + { + const parser = event.getParser(); + + dispatchUiEvent(new NotificationCenterAlertEvent(NotificationCenterAlertEvent.HOTEL_ALERT, parser.messages)); + }, []); + + const onHotelWillShutdownEvent = useCallback((event: HotelWillShutdownEvent) => + { + const parser = event.getParser(); + dispatchNotificationCenterState({ type: NotificationCenterActions.ADD_NOTIFICATION, payload: { - notification: new BroadcastMessageNotification(parser.message) + notification: new HotelWillShutdownNotification(parser.minutes) } }); }, [ dispatchNotificationCenterState ]); @@ -38,47 +58,11 @@ export const NotificationCenterMessageHandler: FC - { - const parser = event.getParser(); - - dispatchNotificationCenterState({ - type: NotificationCenterActions.ADD_NOTIFICATION, - payload: { - notification: new ModeratorMessageNotification(parser.message, parser.link) - } - }); - }, [ dispatchNotificationCenterState ]); - - const onMOTDNotificationEvent = useCallback((event: MOTDNotificationEvent) => - { - const parser = event.getParser(); - - dispatchNotificationCenterState({ - type: NotificationCenterActions.ADD_NOTIFICATION, - payload: { - notification: new MOTDNotification(parser.messages) - } - }); - }, [ dispatchNotificationCenterState ]); - - const onHotelWillShutdownEvent = useCallback((event: HotelWillShutdownEvent) => - { - const parser = event.getParser(); - - dispatchNotificationCenterState({ - type: NotificationCenterActions.ADD_NOTIFICATION, - payload: { - notification: new HotelWillShutdownNotification(parser.minutes) - } - }); - }, [ dispatchNotificationCenterState ]); - CreateMessageHook(HabboBroadcastMessageEvent, onHabboBroadcastMessageEvent); - CreateMessageHook(NotificationDialogMessageEvent, onNotificationDialogMessageEvent); CreateMessageHook(ModeratorMessageEvent, onModeratorMessageEvent); CreateMessageHook(MOTDNotificationEvent, onMOTDNotificationEvent); CreateMessageHook(HotelWillShutdownEvent, onHotelWillShutdownEvent); + CreateMessageHook(NotificationDialogMessageEvent, onNotificationDialogMessageEvent); return null; } diff --git a/src/views/notification-center/NotificationCenterView.scss b/src/views/notification-center/NotificationCenterView.scss index 834846f6..bf7e1d8e 100644 --- a/src/views/notification-center/NotificationCenterView.scss +++ b/src/views/notification-center/NotificationCenterView.scss @@ -1,3 +1,15 @@ +.nitro-alert { + width: 350px; + + .content-area { + min-height: 125px; + height: 125px; + max-height: 430px; + resize: vertical; + overflow: auto; + } +} + .nitro-notification-center-container { position: absolute; top: 0; @@ -13,12 +25,3 @@ pointer-events: all; } } - -.nitro-notification { - width: 350px; - - .content-area { - max-height: 200px; - overflow-y: auto; - } -} diff --git a/src/views/notification-center/NotificationCenterView.tsx b/src/views/notification-center/NotificationCenterView.tsx index de872df3..bbaa5022 100644 --- a/src/views/notification-center/NotificationCenterView.tsx +++ b/src/views/notification-center/NotificationCenterView.tsx @@ -1,116 +1,49 @@ -import { FC, useCallback, useReducer, useState } from 'react'; -import { NotificationCenterAddNotificationEvent, NotificationCenterEvent } from '../../events'; +import { FC, useCallback, useState } from 'react'; +import { NotificationCenterAlertEvent } from '../../events'; import { useUiEvent } from '../../hooks/events'; -import { TransitionAnimation } from '../../layout/transitions/TransitionAnimation'; -import { TransitionAnimationTypes } from '../../layout/transitions/TransitionAnimation.types'; -import { NotificationCenterContextProvider } from './context/NotificationCenterContext'; import { NotificationCenterMessageHandler } from './NotificationCenterMessageHandler'; import { NotificationCenterViewProps } from './NotificationCenterView.types'; -import { initialNotificationCenter, NotificationCenterActions, NotificationCenterReducer } from './reducers/NotificationCenterReducer'; -import { BroadcastMessageNotification } from './utils/BroadcastMessageNotification'; -import { HotelWillShutdownNotification } from './utils/HotelWillShutdownNotification'; -import { ModeratorMessageNotification } from './utils/ModeratorMessageNotification'; -import { MOTDNotification } from './utils/MOTDNotification'; -import { NitroNotification } from './utils/Notification'; -import { BroadcastMessageView } from './views/broadcast-message/BroadcastMessageView'; -import { HotelWillShutdownView } from './views/hotel-will-shutdown/HotelWillShutdownView'; -import { ModeratorMessageView } from './views/moderator-message/ModeratorMessageView'; -import { MOTDView } from './views/motd/MOTDView'; +import { NotificationCenterBroadcastMessageView } from './views/broadcast-message/NotificationCenterBroadcastMessageView'; export const NotificationCenterView: FC = props => { - const [ isVisible, setIsVisible ] = useState(false); + const [ alerts, setAlerts ] = useState([]); - const [ notificationCenterState, dispatchNotificationCenterState ] = useReducer(NotificationCenterReducer, initialNotificationCenter); - const { notifications = null } = notificationCenterState; - - const onNotificationCenterEvent = useCallback((event: NotificationCenterEvent) => + const onNotificationCenterAlertEvent = useCallback((event: NotificationCenterAlertEvent) => { - switch(event.type) - { - case NotificationCenterEvent.SHOW_NOTIFICATION_CENTER: - setIsVisible(true); - return; - case NotificationCenterEvent.HIDE_NOTIFICATION_CENTER: - setIsVisible(false); - return; - case NotificationCenterEvent.TOGGLE_NOTIFICATION_CENTER: - setIsVisible(value => !value); - return; - case NotificationCenterEvent.ADD_NOTIFICATION: { - const castedEvent = (event as NotificationCenterAddNotificationEvent); - - dispatchNotificationCenterState({ - type: NotificationCenterActions.ADD_NOTIFICATION, - payload: { - notification: castedEvent.notification - } - }); - return; - } - } + setAlerts(prevValue => + { + return [ ...prevValue, event ]; + }); }, []); - useUiEvent(NotificationCenterEvent.SHOW_NOTIFICATION_CENTER, onNotificationCenterEvent); - useUiEvent(NotificationCenterEvent.HIDE_NOTIFICATION_CENTER, onNotificationCenterEvent); - useUiEvent(NotificationCenterEvent.TOGGLE_NOTIFICATION_CENTER, onNotificationCenterEvent); - useUiEvent(NotificationCenterEvent.ADD_NOTIFICATION, onNotificationCenterEvent); + useUiEvent(NotificationCenterAlertEvent.HOTEL_ALERT, onNotificationCenterAlertEvent); - const handleButtonClick = useCallback((action: string, value: number) => + const closeAlert = useCallback((alert: NotificationCenterAlertEvent) => { - if(!action) return; - - switch(action) - { - case 'dismiss_notification': - dispatchNotificationCenterState({ - type: NotificationCenterActions.DISMISS_NOTIFICATION, - payload: { - id: value - } - }); - return; - case 'remove_notification': - dispatchNotificationCenterState({ - type: NotificationCenterActions.REMOVE_NOTIFICATION, - payload: { - id: value - } - }); - return; - } - }, [ dispatchNotificationCenterState ]); - - const mapNotifications = useCallback((notifications: NitroNotification[], inTray: boolean) => - { - if(!notifications) return null; - - return notifications.map(notification => + setAlerts(prevValue => { - if(!inTray && notification.dismissed) return null; + const newAlerts = [ ...prevValue ]; + const index = newAlerts.findIndex(value => (alert === value)); - if(notification instanceof BroadcastMessageNotification) - return handleButtonClick(action, notification.id) } /> - if(notification instanceof MOTDNotification) - return handleButtonClick(action, notification.id) } /> - if(notification instanceof ModeratorMessageNotification) - return handleButtonClick(action, notification.id) } /> - if(notification instanceof HotelWillShutdownNotification) - return handleButtonClick(action, notification.id) } /> - else - return null; + if(index >= 0) newAlerts.splice(index, 1); + + return newAlerts; }); - }, [ handleButtonClick ]); + }, []); return ( - + <> - -
- { mapNotifications(notifications, true) } -
-
- { mapNotifications(notifications, false) } -
+ { (alerts.length > 0) && alerts.map((alert, index) => + { + switch(alert.type) + { + case NotificationCenterAlertEvent.HOTEL_ALERT: + default: + return closeAlert(alert) } />; + } + })} + ); } diff --git a/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.tsx b/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.tsx new file mode 100644 index 00000000..58cc5d93 --- /dev/null +++ b/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.tsx @@ -0,0 +1,18 @@ +import { FC } from 'react'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; +import { LocalizeText } from '../../../../utils/LocalizeText'; +import { NotificationCenterAlertBaseProps } from './NotificationCenterAlertBase.types'; + +export const NotificationCenterAlertBase: FC = props => +{ + const { headerText = LocalizeText('mod.alert.title'), onClose = null, children = null } = props; + + return ( + + + + { children } + + + ); +} diff --git a/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.types.ts b/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.types.ts new file mode 100644 index 00000000..e7c08d27 --- /dev/null +++ b/src/views/notification-center/views/alert-base/NotificationCenterAlertBase.types.ts @@ -0,0 +1,5 @@ +export interface NotificationCenterAlertBaseProps +{ + headerText?: string; + onClose: () => void; +} diff --git a/src/views/notification-center/views/broadcast-message/BroadcastMessageView.tsx b/src/views/notification-center/views/broadcast-message/BroadcastMessageView.tsx deleted file mode 100644 index 5b7cd157..00000000 --- a/src/views/notification-center/views/broadcast-message/BroadcastMessageView.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { FC } from 'react'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; -import { LocalizeText } from '../../../../utils/LocalizeText'; -import { NotificationTrayItemView } from '../tray-item/NotificationTrayItemView'; -import { BroadcastMessageViewProps } from './BroadcastMessageView.types'; - -export const BroadcastMessageView: FC = props => -{ - const { notification = null, inTray = null, onButtonClick = null } = props; - - if(!notification) return null; - - const content =
; - - if(inTray) - return ( - onButtonClick('remove_notification') } /> - ); - - return ( - - onButtonClick('dismiss_notification') } /> - - { content } - - - ); -}; diff --git a/src/views/notification-center/views/broadcast-message/BroadcastMessageView.types.ts b/src/views/notification-center/views/broadcast-message/BroadcastMessageView.types.ts deleted file mode 100644 index fcda3f80..00000000 --- a/src/views/notification-center/views/broadcast-message/BroadcastMessageView.types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { NotificationViewProps } from '../../NotificationCenterView.types'; -import { BroadcastMessageNotification } from './../../utils/BroadcastMessageNotification'; - -export class BroadcastMessageViewProps extends NotificationViewProps -{ - notification: BroadcastMessageNotification; -} diff --git a/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.tsx b/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.tsx new file mode 100644 index 00000000..e30208f4 --- /dev/null +++ b/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.tsx @@ -0,0 +1,30 @@ +import { FC, useMemo } from 'react'; +import { LocalizeText } from '../../../../utils/LocalizeText'; +import { NotificationCenterAlertBase } from '../alert-base/NotificationCenterAlertBase'; +import { NotificationCenterBroadcastMessageViewProps } from './NotificationCenterBroadcastMessageView.types'; + +export const NotificationCenterBroadcastMessageView: FC = props => +{ + const { notification = null, onClose = null } = props; + + const message = useMemo(() => + { + let finalMessage = ''; + + notification.message.forEach(message => + { + finalMessage += message.replace(/\r\n|\r|\n/g, '
'); + }); + + return finalMessage; + }, [ notification ]); + + return ( + +
+
+ +
+ + ); +}; diff --git a/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.types.ts b/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.types.ts new file mode 100644 index 00000000..bd89dd38 --- /dev/null +++ b/src/views/notification-center/views/broadcast-message/NotificationCenterBroadcastMessageView.types.ts @@ -0,0 +1,7 @@ +import { NotificationCenterAlertEvent } from '../../../../events'; + +export class NotificationCenterBroadcastMessageViewProps +{ + notification: NotificationCenterAlertEvent; + onClose: () => void; +} diff --git a/src/views/notification-center/views/motd/MOTDView.tsx b/src/views/notification-center/views/motd/MOTDView.tsx deleted file mode 100644 index c63af9ff..00000000 --- a/src/views/notification-center/views/motd/MOTDView.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { FC } from 'react'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; -import { LocalizeText } from '../../../../utils/LocalizeText'; -import { NotificationTrayItemView } from '../tray-item/NotificationTrayItemView'; -import { MOTDViewProps } from './MOTDView.types'; - -export const MOTDView: FC = props => -{ - const { notification = null, inTray = null, onButtonClick = null } = props; - - if(!notification) return null; - - const content = notification.messages.map((message, index) => - { - return
- }); - - if(inTray) - return ( - onButtonClick('remove_notification') } /> - ); - - return ( - - onButtonClick('dismiss_notification') } /> - - { content } - - - ); -}; diff --git a/src/views/notification-center/views/motd/MOTDView.types.ts b/src/views/notification-center/views/motd/MOTDView.types.ts deleted file mode 100644 index 8175abf7..00000000 --- a/src/views/notification-center/views/motd/MOTDView.types.ts +++ /dev/null @@ -1,7 +0,0 @@ -import { NotificationViewProps } from '../../NotificationCenterView.types'; -import { MOTDNotification } from './../../utils/MOTDNotification'; - -export class MOTDViewProps extends NotificationViewProps -{ - notification: MOTDNotification; -} diff --git a/src/views/notification-center/views/motd/NotificationCenterMotdView.tsx b/src/views/notification-center/views/motd/NotificationCenterMotdView.tsx new file mode 100644 index 00000000..1039f298 --- /dev/null +++ b/src/views/notification-center/views/motd/NotificationCenterMotdView.tsx @@ -0,0 +1,10 @@ +import { FC } from 'react'; +import { NotificationCenterBroadcastMessageView } from '../broadcast-message/NotificationCenterBroadcastMessageView'; +import { NotificationCenterMotdViewProps } from './NotificationCenterMotdView.types'; + +export const NotificationCenterMotdView: FC = props => +{ + const { notification = null, onClose = null } = props; + + return ; +} diff --git a/src/views/notification-center/views/motd/NotificationCenterMotdView.types.ts b/src/views/notification-center/views/motd/NotificationCenterMotdView.types.ts new file mode 100644 index 00000000..921e8634 --- /dev/null +++ b/src/views/notification-center/views/motd/NotificationCenterMotdView.types.ts @@ -0,0 +1,7 @@ +import { NotificationCenterAlertEvent } from '../../../../events'; + +export interface NotificationCenterMotdViewProps +{ + notification: NotificationCenterAlertEvent; + onClose: () => void; +} From 3fc5fdd68e48f61aed0687425297fdca4aef8eea Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 8 Jul 2021 01:47:27 -0400 Subject: [PATCH 33/72] Trade update --- src/views/inventory/views/trade/InventoryTradeView.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/views/inventory/views/trade/InventoryTradeView.tsx b/src/views/inventory/views/trade/InventoryTradeView.tsx index d7c6ad83..38d725ec 100644 --- a/src/views/inventory/views/trade/InventoryTradeView.tsx +++ b/src/views/inventory/views/trade/InventoryTradeView.tsx @@ -244,7 +244,7 @@ export const InventoryTradeView: FC = props =>
{ groupItem ? groupItem.name : LocalizeText('catalog_selectproduct') }
-
+
{ LocalizeText('inventory.trading.you') } { LocalizeText('inventory.trading.areoffering') }: From 5fc3a95d2f49675cc60d841cd79e0411c6786c68 Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 8 Jul 2021 02:05:44 -0400 Subject: [PATCH 34/72] Update widgets --- .../handlers/RoomWidgetChatInputHandler.ts | 5 +- .../avatar-info/utils/PetSupplementEnum.ts | 5 + .../avatar/AvatarInfoWidgetAvatarView.tsx | 2 - .../own-pet/AvatarInfoWidgetOwnPetView.tsx | 234 +++++++++++++++++- .../AvatarInfoWidgetRentableBotView.tsx | 23 +- .../widgets/context-menu/ContextMenuView.tsx | 2 +- .../InfoStandWidgetRentableBotView.tsx | 4 +- 7 files changed, 252 insertions(+), 23 deletions(-) create mode 100644 src/views/room/widgets/avatar-info/utils/PetSupplementEnum.ts diff --git a/src/views/room/handlers/RoomWidgetChatInputHandler.ts b/src/views/room/handlers/RoomWidgetChatInputHandler.ts index 20f054e6..18b0b2b9 100644 --- a/src/views/room/handlers/RoomWidgetChatInputHandler.ts +++ b/src/views/room/handlers/RoomWidgetChatInputHandler.ts @@ -1,5 +1,6 @@ import { AvatarExpressionEnum, HabboClubLevelEnum, NitroEvent, RoomControllerLevel, RoomSessionChatEvent, RoomSettingsComposer, RoomZoomEvent } from 'nitro-renderer'; -import { GetConnection, GetRoomEngine, GetSessionDataManager } from '../../../api'; +import { GetRoomEngine, GetSessionDataManager } from '../../../api'; +import { SendMessageHook } from '../../../hooks/messages'; import { RoomWidgetFloodControlEvent, RoomWidgetUpdateEvent } from '../events'; import { RoomWidgetChatMessage, RoomWidgetChatSelectAvatarMessage, RoomWidgetChatTypingMessage, RoomWidgetMessage, RoomWidgetRequestWidgetMessage } from '../messages'; import { RoomWidgetHandler } from './RoomWidgetHandler'; @@ -148,7 +149,7 @@ export class RoomWidgetChatInputHandler extends RoomWidgetHandler case ':settings': if(this.container.roomSession.isRoomOwner || GetSessionDataManager().isModerator) { - GetConnection().send(new RoomSettingsComposer(this.container.roomSession.roomId)); + SendMessageHook(new RoomSettingsComposer(this.container.roomSession.roomId)); } return null; diff --git a/src/views/room/widgets/avatar-info/utils/PetSupplementEnum.ts b/src/views/room/widgets/avatar-info/utils/PetSupplementEnum.ts new file mode 100644 index 00000000..eb236875 --- /dev/null +++ b/src/views/room/widgets/avatar-info/utils/PetSupplementEnum.ts @@ -0,0 +1,5 @@ +export class PetSupplementEnum +{ + public static WATER: number = 0; + public static LIGHT: number = 1; +} diff --git a/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.tsx b/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.tsx index d2f3bff6..9f6d5415 100644 --- a/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.tsx +++ b/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.tsx @@ -103,8 +103,6 @@ export const AvatarInfoWidgetAvatarView: FC = p return newRespectsLeft; }); - //userData.respectLeft--; - messageType = RoomWidgetUserActionMessage.RESPECT_USER; if(newRespectsLeft > 0) hideMenu = false; diff --git a/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx b/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx index b95e6c30..bcc54ac7 100644 --- a/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx +++ b/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx @@ -1,9 +1,235 @@ -import { FC } from 'react'; +import { PetType, RoomObjectCategory, RoomObjectVariable } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { GetOwnRoomObject } from '../../../../../../api'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { useRoomContext } from '../../../../context/RoomContext'; +import { RoomWidgetMessage, RoomWidgetUserActionMessage } from '../../../../messages'; +import { ContextMenuView } from '../../../context-menu/ContextMenuView'; +import { ContextMenuHeaderView } from '../../../context-menu/views/header/ContextMenuHeaderView'; +import { ContextMenuListItemView } from '../../../context-menu/views/list-item/ContextMenuListItemView'; import { AvatarInfoWidgetOwnPetViewProps } from './AvatarInfoWidgetOwnPetView.types'; +const _Str_2906: number = 0; +const _Str_5818: number = 1; +const _Str_5938: number = 2; +const _Str_10946: number = 3; + export const AvatarInfoWidgetOwnPetView: FC = props => { - const { petData = null } = props; - - return null; + const { petData = null, close = null } = props; + const [ mode, setMode ] = useState(_Str_2906); + const [ respectsLeft, setRespectsLeft ] = useState(0); + const { roomSession = null, widgetHandler = null } = useRoomContext(); + + useEffect(() => + { + setMode(prevValue => + { + if(petData.petType === PetType.MONSTERPLANT) return _Str_10946; + else if(petData.saddle && !petData.rider) return _Str_5818; + else if(petData.rider) return _Str_5938; + + return _Str_2906; + }); + + setRespectsLeft(petData.respectsPetLeft); + }, [ petData ]) + + const processAction = useCallback((name: string) => + { + let messageType: string = null; + let message: RoomWidgetMessage = null; + let hideMenu = true; + + if(name) + { + switch(name) + { + case 'respect': + let newRespectsLeft = 0; + + setRespectsLeft(prevValue => + { + newRespectsLeft = (prevValue - 1); + + return newRespectsLeft; + }); + + messageType = RoomWidgetUserActionMessage.RESPECT_PET; + + if(newRespectsLeft > 0) hideMenu = false; + break; + case 'treat': + messageType = RoomWidgetUserActionMessage.TREAT_PET; + break; + case 'pass_handitem': + messageType = RoomWidgetUserActionMessage.GIVE_CARRY_ITEM_TO_PET; + break; + case 'train': + //this.widget._Str_23877(); + break; + case 'pick_up': + messageType = RoomWidgetUserActionMessage.PICKUP_PET; + //this.widget._Str_25401(); + break; + case 'mount': + messageType = RoomWidgetUserActionMessage.MOUNT_PET; + break; + case 'toggle_riding_permission': + messageType = RoomWidgetUserActionMessage.TOGGLE_PET_RIDING_PERMISSION; + // update riding checkbox + break; + case 'toggle_breeding_permission': + messageType = RoomWidgetUserActionMessage.TOGGLE_PET_BREEDING_PERMISSION + // update breeding checkbox; + break; + case 'dismount': + messageType = RoomWidgetUserActionMessage.DISMOUNT_PET; + break; + case 'saddle_off': + messageType = RoomWidgetUserActionMessage.SADDLE_OFF; + break; + case 'breed': + if(mode === _Str_2906) + { + // _local_7 = RoomWidgetPetCommandMessage._Str_16282; + // _local_8 = ("pet.command." + _local_7); + // _local_9 = _Str_2268.catalog.localization.getLocalization(_local_8); + // _local_4 = new RoomWidgetPetCommandMessage(RoomWidgetPetCommandMessage.RWPCM_PET_COMMAND, this._Str_594.id, ((this._Str_594.name + " ") + _local_9)); + } + + else if(mode === _Str_10946) + { + messageType = RoomWidgetUserActionMessage.REQUEST_BREED_PET; + } + break; + case 'harvest': + messageType = RoomWidgetUserActionMessage.HARVEST_PET; + break; + case 'revive': + messageType = RoomWidgetUserActionMessage.REVIVE_PET; + break; + case 'compost': + messageType = RoomWidgetUserActionMessage.COMPOST_PLANT; + break; + case 'buy_saddle': + //this.openCatalogPage(this._Str_11220); + break; + } + + if(messageType) message = new RoomWidgetUserActionMessage(messageType, petData.id); + + if(message) widgetHandler.processWidgetMessage(message); + } + + if(hideMenu) close(); + }, [ widgetHandler, petData, mode, close ]); + + const canGiveHandItem = useMemo(() => + { + let flag = false; + + const roomObject = GetOwnRoomObject(); + + if(roomObject) + { + const carryId = roomObject.model.getValue(RoomObjectVariable.FIGURE_CARRY_OBJECT); + + if((carryId > 0) && (carryId < 999999)) flag = true; + } + + return flag; + }, []); + + return ( + + + { petData.name } + + { (mode === _Str_2906) && + <> + { (respectsLeft > 0) && + processAction('respect') }> + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + } + processAction('train') }> + { LocalizeText('infostand.button.train') } + + processAction('pick_up') }> + { LocalizeText('infostand.button.pickup') } + + { (petData.petType === PetType.HORSE) && + processAction('buy_saddle') }> + { LocalizeText('infostand.button.buy_saddle') } + } + { ([ PetType.BEAR, PetType.TERRIER, PetType.CAT, PetType.DOG, PetType.PIG].indexOf(petData.petType) > -1) && + processAction('breed') }> + { LocalizeText('infostand.button.breed') } + } + } + { (mode === _Str_5818) && + <> + processAction('mount') }> + { LocalizeText('infostand.button.mount') } + + processAction('toggle_riding_permission') }> + { LocalizeText('infostand.button.toggle_riding_permission') } + + { (respectsLeft > 0) && + processAction('respect') }> + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + } + processAction('train') }> + { LocalizeText('infostand.button.train') } + + processAction('pick_up') }> + { LocalizeText('infostand.button.pickup') } + + processAction('saddle_off') }> + { LocalizeText('infostand.button.saddle_off') } + + } + { (mode === _Str_5938) && + <> + processAction('dismount') }> + { LocalizeText('infostand.button.dismount') } + + { (respectsLeft > 0) && + processAction('respect') }> + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + } + } + { (mode === _Str_10946) && + <> + processAction('pick_up') }> + { LocalizeText('infostand.button.pickup') } + + { petData.dead && + processAction('revive') }> + { LocalizeText('infostand.button.revive') } + } + { roomSession.isRoomOwner && + processAction('compost') }> + { LocalizeText('infostand.button.compost') } + } + { !petData.dead && ((petData.energy / petData.maximumEnergy) < 0.98) && + processAction('treat') }> + { LocalizeText('infostand.button.treat') } + } + { !petData.dead && (petData.level === petData.maximumLevel) && petData.breedable && + <> + processAction('toggle_breeding_permission') }> + { LocalizeText('infostand.button.toggle_breeding_permission') } + + processAction('breed') }> + { LocalizeText('infostand.button.breed') } + + } + } + { canGiveHandItem && + processAction('pass_hand_item') }> + { LocalizeText('infostand.button.pass_hand_item') } + } + + ); } diff --git a/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx index 13caa8df..ed82968a 100644 --- a/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx +++ b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx @@ -1,7 +1,6 @@ import { BotCommandConfigurationEvent, BotRemoveComposer, BotSkillSaveComposer, Nitro, RequestBotCommandConfigurationComposer, RoomObjectCategory } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; -import { GetConnection } from '../../../../../../api'; -import { CreateMessageHook } from '../../../../../../hooks/messages'; +import { CreateMessageHook, SendMessageHook } from '../../../../../../hooks/messages'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { useRoomContext } from '../../../../context/RoomContext'; import { RoomWidgetUpdateRentableBotChatEvent } from '../../../../events'; @@ -73,7 +72,7 @@ export const AvatarInfoWidgetRentableBotView: FC { - GetConnection().send(new RequestBotCommandConfigurationComposer(rentableBotData.webID, skillType)); + SendMessageHook(new RequestBotCommandConfigurationComposer(rentableBotData.webID, skillType)); }, [ rentableBotData ]); const processAction = useCallback((name: string) => @@ -86,45 +85,45 @@ export const AvatarInfoWidgetRentableBotView: FC = props => if(!bounds || !elementRef.current) return; let left = Math.round((bounds.left + (bounds.width / 2)) - (elementRef.current.offsetWidth / 2)); - let top = Math.round((bounds.top - elementRef.current.offsetHeight) + 20); + let top = Math.round((bounds.top - elementRef.current.offsetHeight)); const maxLeft = ((Nitro.instance.width - elementRef.current.offsetWidth) - SPACE_AROUND_EDGES); const maxTop = ((Nitro.instance.height - elementRef.current.offsetHeight) - SPACE_AROUND_EDGES); diff --git a/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx b/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx index a25fc8d3..c4d79504 100644 --- a/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx +++ b/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx @@ -1,6 +1,6 @@ import { BotRemoveComposer } from 'nitro-renderer'; import { FC, useCallback, useMemo } from 'react'; -import { GetConnection } from '../../../../../../api'; +import { SendMessageHook } from '../../../../../../hooks/messages'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { AvatarImageView } from '../../../../../shared/avatar-image/AvatarImageView'; import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView'; @@ -23,7 +23,7 @@ export const InfoStandWidgetRentableBotView: FC { - GetConnection().send(new BotRemoveComposer(rentableBotData.webID)); + SendMessageHook(new BotRemoveComposer(rentableBotData.webID)); }, [ rentableBotData ]); if(!rentableBotData) return; From 32c4037e9863034afe32abeb6feb0a3e36972f51 Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 8 Jul 2021 02:05:55 -0400 Subject: [PATCH 35/72] Update infostand handler --- .../handlers/RoomWidgetInfostandHandler.ts | 41 ++++++++++--------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/views/room/handlers/RoomWidgetInfostandHandler.ts b/src/views/room/handlers/RoomWidgetInfostandHandler.ts index 287c980c..1ec12c3a 100644 --- a/src/views/room/handlers/RoomWidgetInfostandHandler.ts +++ b/src/views/room/handlers/RoomWidgetInfostandHandler.ts @@ -1,10 +1,13 @@ -import { IFurnitureData, Nitro, NitroEvent, ObjectDataFactory, PetFigureData, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer'; -import { GetConnection, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; +import { IFurnitureData, Nitro, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer'; +import { GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../events'; +import { FriendListSendFriendRequestEvent } from '../../../events/friend-list/FriendListSendFriendRequestEvent'; import { dispatchUiEvent } from '../../../hooks/events'; +import { SendMessageHook } from '../../../hooks/messages'; import { LocalizeText } from '../../../utils/LocalizeText'; import { RoomWidgetObjectNameEvent, RoomWidgetUpdateChatInputContentEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events'; import { RoomWidgetChangeMottoMessage, RoomWidgetFurniActionMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages'; +import { PetSupplementEnum } from '../widgets/avatar-info/utils/PetSupplementEnum'; import { RoomWidgetHandler } from './RoomWidgetHandler'; export class RoomWidgetInfostandHandler extends RoomWidgetHandler @@ -73,7 +76,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler case RoomWidgetRoomObjectMessage.GET_OBJECT_INFO: return this.processObjectInfoMessage((message as RoomWidgetRoomObjectMessage)); case RoomWidgetUserActionMessage.SEND_FRIEND_REQUEST: - //this._container.friendService.sendFriendRequest(userId, userData.name); + dispatchUiEvent(new FriendListSendFriendRequestEvent(userId)); break; case RoomWidgetUserActionMessage.RESPECT_USER: GetSessionDataManager().giveRespect(userId); @@ -119,41 +122,41 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler // case RoomWidgetUserActionMessage.RWUAM_OPEN_HOME_PAGE: // this._container.sessionDataManager._Str_21275((message as RoomWidgetUserActionMessage).userId, _local_3.name); // break; - // case RoomWidgetUserActionMessage.RWUAM_PICKUP_PET: - // this._container.roomSession._Str_13781(_local_2); - // break; - // case RoomWidgetUserActionMessage.RWUAM_MOUNT_PET: - // this._container.roomSession._Str_21066(_local_2); - // break; + case RoomWidgetUserActionMessage.PICKUP_PET: + this.container.roomSession.pickupPet(userId); + break; + case RoomWidgetUserActionMessage.MOUNT_PET: + this.container.roomSession.mountPet(userId); + break; // case RoomWidgetUserActionMessage.RWUAM_TOGGLE_PET_RIDING_PERMISSION: // this._container.roomSession._Str_21025(_local_2); // break; // case RoomWidgetUserActionMessage.RWUAM_TOGGLE_PET_BREEDING_PERMISSION: // this._container.roomSession._Str_21562(_local_2); // break; - // case RoomWidgetUserActionMessage.RWUAM_DISMOUNT_PET: - // this._container.roomSession._Str_19075(_local_2); - // break; + case RoomWidgetUserActionMessage.DISMOUNT_PET: + this.container.roomSession.dismountPet(userId); + break; // case RoomWidgetUserActionMessage.RWUAM_SADDLE_OFF: // this._container.roomSession._Str_21635(_local_2); // break; case RoomWidgetUserActionMessage.PASS_CARRY_ITEM: - GetConnection().send(new RoomUnitGiveHandItemComposer(userId)); + SendMessageHook(new RoomUnitGiveHandItemComposer(userId)); break; case RoomWidgetUserActionMessage.GIVE_CARRY_ITEM_TO_PET: - GetConnection().send(new RoomUnitGiveHandItemPetComposer(userId)); + SendMessageHook(new RoomUnitGiveHandItemPetComposer(userId)); break; case RoomWidgetUserActionMessage.GIVE_WATER_TO_PET: - //this._container.connection.send(new _Str_7251(_local_2, PetSupplementEnum._Str_9473)); + SendMessageHook(new PetSupplementComposer(userId, PetSupplementEnum.WATER)); break; case RoomWidgetUserActionMessage.GIVE_LIGHT_TO_PET: - //this._container.connection.send(new _Str_7251(_local_2, PetSupplementEnum._Str_8421)); + SendMessageHook(new PetSupplementComposer(userId, PetSupplementEnum.LIGHT)); break; case RoomWidgetUserActionMessage.TREAT_PET: - //this._container.connection.send(new _Str_8184(_local_2)); + SendMessageHook(new PetRespectComposer(userId)); break; case RoomWidgetUserActionMessage.DROP_CARRY_ITEM: - GetConnection().send(new RoomUnitDropHandItemComposer()); + SendMessageHook(new RoomUnitDropHandItemComposer()); break; case RoomWidgetUserActionMessage.REQUEST_PET_UPDATE: this.container.roomSession.userDataManager.requestPetInfo(userId); @@ -221,7 +224,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler GetRoomEngine().processRoomObjectWallOperation(objectId, category, RoomObjectOperationType.OBJECT_SAVE_STUFF_DATA, mapData); - if(GetSessionDataManager().hasSecurity(SecurityLevel.MODERATOR)) GetConnection().send(new RoomAdsUpdateComposer(objectId, mapData)); + if(GetSessionDataManager().hasSecurity(SecurityLevel.MODERATOR)) SendMessageHook(new RoomAdsUpdateComposer(objectId, mapData)); return; } From c7fe32411ff904456c6eede7e61f53e3e63860d7 Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 8 Jul 2021 04:25:42 -0400 Subject: [PATCH 36/72] Start furni context menus --- .../furniture/FurnitureWidgetsView.tsx | 2 + .../context-menu/FurnitureContextMenuView.tsx | 100 ++++++++++++++++++ 2 files changed, 102 insertions(+) create mode 100644 src/views/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx diff --git a/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx b/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx index 8c688a13..ce58b376 100644 --- a/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx +++ b/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx @@ -1,5 +1,6 @@ import { FC } from 'react'; import { FurnitureBackgroundColorView } from './background-color/FurnitureBackgroundColorView'; +import { FurnitureContextMenuView } from './context-menu/FurnitureContextMenuView'; import { FurnitureDimmerView } from './dimmer/FurnitureDimmerView'; import { FurnitureEngravingLockView } from './engraving-lock/FurnitureEngravingLockView'; import { FurnitureExchangeCreditView } from './exchange-credit/FurnitureExchangeCreditView'; @@ -16,6 +17,7 @@ export const FurnitureWidgetsView: FC = props => return (
+ diff --git a/src/views/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx b/src/views/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx new file mode 100644 index 00000000..9409b00d --- /dev/null +++ b/src/views/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx @@ -0,0 +1,100 @@ +import { ContextMenuEnum, IRoomObject, RoomEngineObjectEvent, RoomEngineTriggerWidgetEvent, RoomObjectCategory } from 'nitro-renderer'; +import { FC, useCallback, useState } from 'react'; +import { GetRoomEngine, IsOwnerOfFurniture } from '../../../../../api'; +import { useRoomEngineEvent } from '../../../../../hooks/events'; +import { LocalizeText } from '../../../../../utils/LocalizeText'; +import { useRoomContext } from '../../../context/RoomContext'; +import { ContextMenuView } from '../../context-menu/ContextMenuView'; +import { ContextMenuHeaderView } from '../../context-menu/views/header/ContextMenuHeaderView'; +import { ContextMenuListItemView } from '../../context-menu/views/list-item/ContextMenuListItemView'; + +const MONSTERPLANT_SEED_CONFIRMATION: string = 'MONSTERPLANT_SEED_CONFIRMATION'; + +export const FurnitureContextMenuView: FC<{}> = props => +{ + const { roomSession = null, eventDispatcher = null, widgetHandler = null } = useRoomContext(); + const [ roomObject, setRoomObject ] = useState(null); + const [ contextMenu, setContextMenu ] = useState(null); + + const close = useCallback(() => + { + setRoomObject(null); + setContextMenu(null); + }, []); + + const onRoomEngineTriggerWidgetEvent = useCallback((event: RoomEngineTriggerWidgetEvent) => + { + const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, event.objectId, event.category); + + if(!roomObject) return; + + switch(event.type) + { + case RoomEngineTriggerWidgetEvent.OPEN_FURNI_CONTEXT_MENU: + switch(event.contextMenu) + { + case ContextMenuEnum.FRIEND_FURNITURE: + return; + case ContextMenuEnum.MONSTERPLANT_SEED: + if(IsOwnerOfFurniture(roomObject)) + { + setRoomObject(roomObject); + setContextMenu(ContextMenuEnum.MONSTERPLANT_SEED); + } + return; + case ContextMenuEnum.MYSTERY_BOX: + return; + case ContextMenuEnum.RANDOM_TELEPORT: + return; + case ContextMenuEnum.PURCHASABLE_CLOTHING: + return; + } + + return; + case RoomEngineTriggerWidgetEvent.CLOSE_FURNI_CONTEXT_MENU: + close(); + return; + } + }, [ roomSession, close ]); + + useRoomEngineEvent(RoomEngineTriggerWidgetEvent.OPEN_FURNI_CONTEXT_MENU, onRoomEngineTriggerWidgetEvent); + useRoomEngineEvent(RoomEngineTriggerWidgetEvent.CLOSE_FURNI_CONTEXT_MENU, onRoomEngineTriggerWidgetEvent); + + const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) => + { + if(!roomObject || (event.objectId !== roomObject.id)) return; + + close(); + }, [ roomObject, close ]); + + useRoomEngineEvent(RoomEngineObjectEvent.REMOVED, onRoomEngineObjectEvent); + + const processAction = useCallback((name: string) => + { + if(name) + { + switch(name) + { + case 'use_monsterplant_seed': + setContextMenu(MONSTERPLANT_SEED_CONFIRMATION); + break; + } + } + }, [ ]); + + if(!roomObject || !contextMenu) return null; + + return ( + + { (contextMenu === ContextMenuEnum.MONSTERPLANT_SEED) && + <> + + { LocalizeText('furni.mnstr_seed.name') } + + processAction('use_monsterplant_seed') }> + { LocalizeText('widget.monsterplant_seed.button.use') } + + } + + ) +} From 7893de3a34423f6289b3b0ee152be4c6fa65f771 Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 8 Jul 2021 04:25:57 -0400 Subject: [PATCH 37/72] Update friend list --- .../FriendListSendFriendRequestEvent.ts | 20 +++++++++++++++++++ src/views/friend-list/FriendListView.tsx | 9 +++++++-- .../friend-bar-item/FriendBarItemView.tsx | 4 ++-- 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 src/events/friend-list/FriendListSendFriendRequestEvent.ts diff --git a/src/events/friend-list/FriendListSendFriendRequestEvent.ts b/src/events/friend-list/FriendListSendFriendRequestEvent.ts new file mode 100644 index 00000000..02d7c006 --- /dev/null +++ b/src/events/friend-list/FriendListSendFriendRequestEvent.ts @@ -0,0 +1,20 @@ +import { FriendListEvent } from './FriendListEvent'; + +export class FriendListSendFriendRequestEvent extends FriendListEvent +{ + public static SEND_FRIEND_REQUEST: string = 'FLSFRE_SEND_FRIEND_REQUEST'; + + private _userId: number; + + constructor(userId: number) + { + super(FriendListSendFriendRequestEvent.SEND_FRIEND_REQUEST); + + this._userId = userId; + } + + public get userId(): number + { + return this._userId; + } +} diff --git a/src/views/friend-list/FriendListView.tsx b/src/views/friend-list/FriendListView.tsx index a620c0ea..15c447d2 100644 --- a/src/views/friend-list/FriendListView.tsx +++ b/src/views/friend-list/FriendListView.tsx @@ -1,8 +1,9 @@ -import { MessengerInitComposer, RoomEngineObjectEvent, RoomObjectCategory } from 'nitro-renderer'; +import { MessengerInitComposer, RoomEngineObjectEvent, RoomObjectCategory, RoomObjectUserType } from 'nitro-renderer'; import React, { FC, useCallback, useEffect, useReducer, useState } from 'react'; import { createPortal } from 'react-dom'; import { GetRoomSession } from '../../api'; import { FriendEnteredRoomEvent, FriendListEvent } from '../../events'; +import { FriendListSendFriendRequestEvent } from '../../events/friend-list/FriendListSendFriendRequestEvent'; import { useRoomEngineEvent } from '../../hooks/events'; import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event'; import { SendMessageHook } from '../../hooks/messages/message-event'; @@ -32,11 +33,15 @@ export const FriendListView: FC = props => case FriendListEvent.TOGGLE_FRIEND_LIST: setIsVisible(value => !value); return; + case FriendListSendFriendRequestEvent.SEND_FRIEND_REQUEST: + const requestEvent = (event as FriendListSendFriendRequestEvent); + return; } }, []); useUiEvent(FriendListEvent.SHOW_FRIEND_LIST, onFriendListEvent); useUiEvent(FriendListEvent.TOGGLE_FRIEND_LIST, onFriendListEvent); + useUiEvent(FriendListSendFriendRequestEvent.SEND_FRIEND_REQUEST, onFriendListEvent); useEffect(() => { @@ -60,7 +65,7 @@ export const FriendListView: FC = props => const userData = roomSession.userDataManager.getUserDataByIndex(event.objectId); - if(!userData) return; + if(!userData || (userData.type !== RoomObjectUserType.getTypeNumber(RoomObjectUserType.USER))) return; const friend = friendListState.friends.find(friend => { diff --git a/src/views/friend-list/views/friend-bar-item/FriendBarItemView.tsx b/src/views/friend-list/views/friend-bar-item/FriendBarItemView.tsx index 0cd1049c..45397a82 100644 --- a/src/views/friend-list/views/friend-bar-item/FriendBarItemView.tsx +++ b/src/views/friend-list/views/friend-bar-item/FriendBarItemView.tsx @@ -1,6 +1,6 @@ import { FollowFriendComposer, MouseEventType } from 'nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; -import { GetConnection } from '../../../../api'; +import { SendMessageHook } from '../../../../hooks/messages'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; import { FriendBarItemViewProps } from './FriendBarItemView.types'; @@ -13,7 +13,7 @@ export const FriendBarItemView: FC = props => const followFriend = useCallback(() => { - GetConnection().send(new FollowFriendComposer(friend.id)); + SendMessageHook(new FollowFriendComposer(friend.id)); }, [ friend ]); const onClick = useCallback((event: MouseEvent) => From 2f96c83c440192cd1c007bdd07e14b670e5a7851 Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 8 Jul 2021 04:26:04 -0400 Subject: [PATCH 38/72] Updates --- src/views/inventory/InventoryView.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/views/inventory/InventoryView.tsx b/src/views/inventory/InventoryView.tsx index 8896d6b6..8f7b0a9b 100644 --- a/src/views/inventory/InventoryView.tsx +++ b/src/views/inventory/InventoryView.tsx @@ -1,6 +1,6 @@ import { IRoomSession, RoomEngineObjectEvent, RoomEngineObjectPlacedEvent, RoomPreviewer, RoomSessionEvent, TradingCancelComposer, TradingCloseComposer, TradingOpenComposer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; -import { GetConnection, GetRoomEngine } from '../../api'; +import { GetRoomEngine } from '../../api'; import { InventoryEvent, InventoryTradeRequestEvent } from '../../events'; import { useRoomEngineEvent } from '../../hooks/events/nitro/room/room-engine-event'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; @@ -45,7 +45,7 @@ export const InventoryView: FC = props => case TradeState.TRADING_STATE_RUNNING: SendMessageHook(new TradingCloseComposer()); return; - case TradeState.TRADING_STATE_CONFIRMING: + default: SendMessageHook(new TradingCancelComposer()); return; } @@ -81,7 +81,7 @@ export const InventoryView: FC = props => case InventoryTradeRequestEvent.REQUEST_TRADE: { const tradeEvent = (event as InventoryTradeRequestEvent); - GetConnection().send(new TradingOpenComposer(tradeEvent.objectId)); + SendMessageHook(new TradingOpenComposer(tradeEvent.objectId)); } } }, [ isVisible, close ]); From afa70ff93ecc7582852e607b4cc844d4eea87527 Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 9 Jul 2021 13:29:00 -0400 Subject: [PATCH 39/72] Lots of pet updates --- .../session/GetFurnitureDataForRoomObject.ts | 22 +++ src/api/nitro/session/index.ts | 1 + .../inventory/views/pet/InventoryPetView.tsx | 2 +- .../views/pet/item/InventoryPetItemView.tsx | 4 +- .../RoomWidgetUpdateInfostandPetEvent.ts | 3 +- .../events/RoomWidgetUseProductBubbleEvent.ts | 21 +++ src/views/room/events/UseProductItem.ts | 50 +++++++ src/views/room/events/index.ts | 2 + .../handlers/RoomWidgetAvatarInfoHandler.ts | 96 +++++++++++- .../handlers/RoomWidgetInfostandHandler.ts | 22 +-- .../messages/RoomWidgetUseProductMessage.ts | 28 ++++ src/views/room/messages/index.ts | 1 + src/views/room/widgets/RoomWidgetsView.tsx | 30 ++-- .../avatar-info/AvatarInfoWidgetView.tsx | 81 +++++++++- .../{utils => common}/BotSkillsEnum.ts | 0 .../{utils => common}/PetSupplementEnum.ts | 0 .../own-pet/AvatarInfoWidgetOwnPetView.tsx | 11 +- .../AvatarInfoWidgetRentableBotView.tsx | 2 +- .../AvatarInfoUseProductConfirmView.tsx | 83 +++++++++++ .../AvatarInfoUseProductConfirmView.types.ts | 7 + .../use-product/AvatarInfoUseProductView.tsx | 138 ++++++++++++++++++ .../AvatarInfoUseProductView.types.ts | 9 ++ .../widgets/context-menu/ContextMenuView.tsx | 16 +- .../views/pet/InfoStandWidgetPetView.tsx | 2 +- .../InfoStandWidgetRentableBotView.tsx | 2 +- src/views/wired/WiredView.tsx | 9 +- 26 files changed, 581 insertions(+), 61 deletions(-) create mode 100644 src/api/nitro/session/GetFurnitureDataForRoomObject.ts create mode 100644 src/views/room/events/RoomWidgetUseProductBubbleEvent.ts create mode 100644 src/views/room/events/UseProductItem.ts create mode 100644 src/views/room/messages/RoomWidgetUseProductMessage.ts rename src/views/room/widgets/avatar-info/{utils => common}/BotSkillsEnum.ts (100%) rename src/views/room/widgets/avatar-info/{utils => common}/PetSupplementEnum.ts (100%) create mode 100644 src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx create mode 100644 src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.types.ts create mode 100644 src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx create mode 100644 src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.types.ts diff --git a/src/api/nitro/session/GetFurnitureDataForRoomObject.ts b/src/api/nitro/session/GetFurnitureDataForRoomObject.ts new file mode 100644 index 00000000..e1739f76 --- /dev/null +++ b/src/api/nitro/session/GetFurnitureDataForRoomObject.ts @@ -0,0 +1,22 @@ +import { IFurnitureData, RoomObjectCategory, RoomObjectVariable } from 'nitro-renderer'; +import { GetRoomEngine } from '../room'; +import { GetSessionDataManager } from './GetSessionDataManager'; + +export function GetFurnitureDataForRoomObject(roomId: number, objectId: number, category: number): IFurnitureData +{ + const roomObject = GetRoomEngine().getRoomObject(roomId, objectId, category); + + if(!roomObject) return; + + const typeId = roomObject.model.getValue(RoomObjectVariable.FURNITURE_TYPE_ID); + + switch(category) + { + case RoomObjectCategory.FLOOR: + return GetSessionDataManager().getFloorItemData(typeId); + case RoomObjectCategory.WALL: + return GetSessionDataManager().getWallItemData(typeId); + } + + return null; +} diff --git a/src/api/nitro/session/index.ts b/src/api/nitro/session/index.ts index ff45e484..ff62191c 100644 --- a/src/api/nitro/session/index.ts +++ b/src/api/nitro/session/index.ts @@ -2,6 +2,7 @@ export * from './CanManipulateFurniture'; export * from './GetCanStandUp'; export * from './GetCanUseExpression'; export * from './GetFurnitureDataForProductOffer'; +export * from './GetFurnitureDataForRoomObject'; export * from './GetOwnPosture'; export * from './GetProductDataForLocalization'; export * from './GetRoomSession'; diff --git a/src/views/inventory/views/pet/InventoryPetView.tsx b/src/views/inventory/views/pet/InventoryPetView.tsx index df943500..5723c190 100644 --- a/src/views/inventory/views/pet/InventoryPetView.tsx +++ b/src/views/inventory/views/pet/InventoryPetView.tsx @@ -60,7 +60,7 @@ export const InventoryPetView: FC = props => roomPreviewer.reset(false); roomPreviewer.updateRoomWallsAndFloorVisibility(true, true); roomPreviewer.updateObjectRoom(floorType, wallType, landscapeType); - roomPreviewer.addPetIntoRoom(petData.figureData.figuredata); + roomPreviewer.addPetIntoRoom(petData.figureString); }, [ roomPreviewer, petItem ]); if(!petItems || !petItems.length) diff --git a/src/views/inventory/views/pet/item/InventoryPetItemView.tsx b/src/views/inventory/views/pet/item/InventoryPetItemView.tsx index d9a56dda..0cbc8e8f 100644 --- a/src/views/inventory/views/pet/item/InventoryPetItemView.tsx +++ b/src/views/inventory/views/pet/item/InventoryPetItemView.tsx @@ -36,10 +36,10 @@ export const InventoryPetItemView: FC = props => return; } }, [ isActive, isMouseDown, petItem, dispatchPetState ]); - + return ( - + ); } diff --git a/src/views/room/events/RoomWidgetUpdateInfostandPetEvent.ts b/src/views/room/events/RoomWidgetUpdateInfostandPetEvent.ts index f4404e6d..be193d60 100644 --- a/src/views/room/events/RoomWidgetUpdateInfostandPetEvent.ts +++ b/src/views/room/events/RoomWidgetUpdateInfostandPetEvent.ts @@ -1,4 +1,3 @@ -import { PetFigureData } from 'nitro-renderer'; import { RoomWidgetUpdateInfostandEvent } from './RoomWidgetUpdateInfostandEvent'; export class RoomWidgetUpdateInfostandPetEvent extends RoomWidgetUpdateInfostandEvent @@ -21,7 +20,7 @@ export class RoomWidgetUpdateInfostandPetEvent extends RoomWidgetUpdateInfostand public image: HTMLImageElement = null; public petType: number = 0; public petBreed: number = 0; - public petFigure: PetFigureData = null; + public petFigure: string = ''; public posture: string = 'std'; public isOwner: boolean = false; public ownerId: number = -1; diff --git a/src/views/room/events/RoomWidgetUseProductBubbleEvent.ts b/src/views/room/events/RoomWidgetUseProductBubbleEvent.ts new file mode 100644 index 00000000..54c8ef62 --- /dev/null +++ b/src/views/room/events/RoomWidgetUseProductBubbleEvent.ts @@ -0,0 +1,21 @@ +import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; +import { UseProductItem } from './UseProductItem'; + +export class RoomWidgetUseProductBubbleEvent extends RoomWidgetUpdateEvent +{ + public static USE_PRODUCT_BUBBLES: string = 'RWUPBE_USE_PRODUCT_BUBBLES'; + + private _items: UseProductItem[]; + + constructor(type: string, items: UseProductItem[]) + { + super(type); + + this._items = items; + } + + public get items(): UseProductItem[] + { + return this._items; + } +} diff --git a/src/views/room/events/UseProductItem.ts b/src/views/room/events/UseProductItem.ts new file mode 100644 index 00000000..c886c403 --- /dev/null +++ b/src/views/room/events/UseProductItem.ts @@ -0,0 +1,50 @@ +export class UseProductItem +{ + private _id: number; + private _category: number; + private _name: string; + private _requestRoomObjectId: number; + private _targetRoomObjectId: number; + private _requestInventoryStripId: number; + private _replace: boolean; + + constructor(id: number, category: number, name: string, requestRoomObjectId: number, targetRoomObjectId: number, requestInventoryStripId: number, replace: boolean) + { + this._id = id; + this._category = category; + this._name = name; + this._requestRoomObjectId = requestRoomObjectId; + this._requestInventoryStripId = requestInventoryStripId; + this._replace = replace; + } + + public get id(): number + { + return this._id; + } + + public get category(): number + { + return this._category; + } + + public get name(): string + { + return this._name; + } + + public get requestRoomObjectId(): number + { + return this._requestRoomObjectId; + } + + public get requestInventoryStripId(): number + { + return this._requestInventoryStripId; + } + + public get replace(): boolean + { + return this._replace; + } +} diff --git a/src/views/room/events/index.ts b/src/views/room/events/index.ts index d281c2fc..88858e0f 100644 --- a/src/views/room/events/index.ts +++ b/src/views/room/events/index.ts @@ -14,3 +14,5 @@ export * from './RoomWidgetUpdateInfostandRentableBotEvent'; export * from './RoomWidgetUpdateInfostandUserEvent'; export * from './RoomWidgetUpdateRentableBotChatEvent'; export * from './RoomWidgetUpdateUserDataEvent'; +export * from './RoomWidgetUseProductBubbleEvent'; +export * from './UseProductItem'; diff --git a/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts b/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts index c88ce7d4..5b7f5538 100644 --- a/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts +++ b/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts @@ -1,7 +1,8 @@ -import { NitroEvent, RoomSessionDanceEvent, RoomSessionUserDataUpdateEvent } from 'nitro-renderer'; -import { GetRoomSession, GetSessionDataManager } from '../../../api'; -import { RoomWidgetAvatarInfoEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateUserDataEvent } from '../events'; -import { RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages'; +import { NitroEvent, RoomEngineUseProductEvent, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionDanceEvent, RoomSessionUserDataUpdateEvent } from 'nitro-renderer'; +import { GetRoomEngine, GetRoomSession, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; +import { FurniCategory } from '../../inventory/common/FurniCategory'; +import { RoomWidgetAvatarInfoEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateUserDataEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../events'; +import { RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUseProductMessage, RoomWidgetUserActionMessage } from '../messages'; import { RoomWidgetHandler } from './RoomWidgetHandler'; export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler @@ -24,6 +25,11 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateDanceStatusEvent(isDancing)); return; + case RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY: + return; + case RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM: + this.processUsableRoomObject((event as RoomEngineUseProductEvent).objectId); + return; } } @@ -56,6 +62,12 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler GetRoomSession().sendPostureMessage(postureMessage.posture); break; } + case RoomWidgetUseProductMessage.PET_PRODUCT: { + const productMessage = (message as RoomWidgetUseProductMessage); + + GetRoomSession().usePetProduct(productMessage.objectId, productMessage.petId); + break; + } } return null; @@ -71,11 +83,81 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler if(userData) this.container.eventDispatcher.dispatchEvent(new RoomWidgetAvatarInfoEvent(userId, userName, userData.type, userData.roomIndex, allowNameChange)); } + private processUsableRoomObject(objectId: number): void + { + const roomId = this.container.roomSession.roomId; + const roomObject = GetRoomEngine().getRoomObject(roomId, objectId, RoomObjectCategory.FLOOR); + + if(!roomObject || !IsOwnerOfFurniture(roomObject)) return; + + const ownerId = roomObject.model.getValue(RoomObjectVariable.FURNITURE_OWNER_ID); + const typeId = roomObject.model.getValue(RoomObjectVariable.FURNITURE_TYPE_ID); + const furniData = GetSessionDataManager().getFloorItemData(typeId); + const parts = furniData.customParams.split(' '); + const part = (parts.length ? parseInt(parts[0]) : -1); + + if(part === -1) return; + + this.processUseableProduct(roomId, objectId, part, furniData.specialType, ownerId); + } + + private processUseableProduct(roomId: number, objectId: number, part: number, specialType: number, ownerId: number, arg6 = -1): void + { + const useProductBubbles: UseProductItem[] = []; + const roomObjects = GetRoomEngine().getRoomObjects(roomId, RoomObjectCategory.UNIT); + + for(const roomObject of roomObjects) + { + const userData = this.container.roomSession.userDataManager.getUserDataByIndex(roomObject.id); + + let replace = false; + + if(!userData || (userData.type !== RoomObjectType.PET)) + { + + } + else + { + if(userData.ownerId === ownerId) + { + if(userData.hasSaddle && (specialType === FurniCategory._Str_6096)) replace = true; + + const figureParts = userData.figure.split(' '); + const figurePart = (figureParts.length ? parseInt(figureParts[0]) : -1); + + if(figurePart === part) + { + if(specialType === FurniCategory._Str_6915) + { + if(!userData.canRevive) continue; + } + + if(specialType === FurniCategory._Str_8726) + { + if((userData.petLevel < 7) || userData.canRevive || userData.canBreed) continue; + } + + if(specialType === FurniCategory._Str_9449) + { + if((userData.petLevel >= 7) || userData.canRevive) continue; + } + + useProductBubbles.push(new UseProductItem(userData.roomIndex, RoomObjectCategory.UNIT, userData.name, objectId, roomObject.id, arg6, replace)); + } + } + } + } + + if(useProductBubbles.length) this.container.eventDispatcher.dispatchEvent(new RoomWidgetUseProductBubbleEvent(RoomWidgetUseProductBubbleEvent.USE_PRODUCT_BUBBLES, useProductBubbles)); + } + public get eventTypes(): string[] { return [ RoomSessionUserDataUpdateEvent.USER_DATA_UPDATED, - RoomSessionDanceEvent.RSDE_DANCE + RoomSessionDanceEvent.RSDE_DANCE, + RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY, + RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM ]; } @@ -85,7 +167,9 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler RoomWidgetRoomObjectMessage.GET_OWN_CHARACTER_INFO, RoomWidgetDanceMessage.DANCE, RoomWidgetAvatarExpressionMessage.AVATAR_EXPRESSION, - RoomWidgetChangePostureMessage.CHANGE_POSTURE + RoomWidgetChangePostureMessage.CHANGE_POSTURE, + RoomWidgetUseProductMessage.PET_PRODUCT, + RoomWidgetUseProductMessage.MONSTERPLANT_SEED ]; } } diff --git a/src/views/room/handlers/RoomWidgetInfostandHandler.ts b/src/views/room/handlers/RoomWidgetInfostandHandler.ts index 1ec12c3a..463955e9 100644 --- a/src/views/room/handlers/RoomWidgetInfostandHandler.ts +++ b/src/views/room/handlers/RoomWidgetInfostandHandler.ts @@ -7,7 +7,7 @@ import { SendMessageHook } from '../../../hooks/messages'; import { LocalizeText } from '../../../utils/LocalizeText'; import { RoomWidgetObjectNameEvent, RoomWidgetUpdateChatInputContentEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events'; import { RoomWidgetChangeMottoMessage, RoomWidgetFurniActionMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages'; -import { PetSupplementEnum } from '../widgets/avatar-info/utils/PetSupplementEnum'; +import { PetSupplementEnum } from '../widgets/avatar-info/common/PetSupplementEnum'; import { RoomWidgetHandler } from './RoomWidgetHandler'; export class RoomWidgetInfostandHandler extends RoomWidgetHandler @@ -128,18 +128,18 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler case RoomWidgetUserActionMessage.MOUNT_PET: this.container.roomSession.mountPet(userId); break; - // case RoomWidgetUserActionMessage.RWUAM_TOGGLE_PET_RIDING_PERMISSION: - // this._container.roomSession._Str_21025(_local_2); - // break; - // case RoomWidgetUserActionMessage.RWUAM_TOGGLE_PET_BREEDING_PERMISSION: - // this._container.roomSession._Str_21562(_local_2); - // break; + case RoomWidgetUserActionMessage.TOGGLE_PET_RIDING_PERMISSION: + this.container.roomSession.togglePetRiding(userId); + break; + case RoomWidgetUserActionMessage.TOGGLE_PET_BREEDING_PERMISSION: + this.container.roomSession.togglePetBreeding(userId); + break; case RoomWidgetUserActionMessage.DISMOUNT_PET: this.container.roomSession.dismountPet(userId); break; - // case RoomWidgetUserActionMessage.RWUAM_SADDLE_OFF: - // this._container.roomSession._Str_21635(_local_2); - // break; + case RoomWidgetUserActionMessage.SADDLE_OFF: + this.container.roomSession.removePetSaddle(userId); + break; case RoomWidgetUserActionMessage.PASS_CARRY_ITEM: SendMessageHook(new RoomUnitGiveHandItemComposer(userId)); break; @@ -620,7 +620,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler infostandEvent.rarityLevel = petData.rarityLevel; infostandEvent.petType = figure.typeId; infostandEvent.petBreed = figure.paletteId; - infostandEvent.petFigure = figure; + infostandEvent.petFigure = roomPetData.figure; infostandEvent.posture = posture; infostandEvent.isOwner = isOwner; infostandEvent.roomIndex = roomPetData.roomIndex; diff --git a/src/views/room/messages/RoomWidgetUseProductMessage.ts b/src/views/room/messages/RoomWidgetUseProductMessage.ts new file mode 100644 index 00000000..deef093c --- /dev/null +++ b/src/views/room/messages/RoomWidgetUseProductMessage.ts @@ -0,0 +1,28 @@ +import { RoomWidgetMessage } from './RoomWidgetMessage'; + +export class RoomWidgetUseProductMessage extends RoomWidgetMessage +{ + public static PET_PRODUCT: string = 'RWUPM_PET_PRODUCT'; + public static MONSTERPLANT_SEED: string = 'RWUPM_MONSTERPLANT_SEED'; + + private _objectId: number; + public _petId: number; + + constructor(type: string, objectId: number, petId: number = -1) + { + super(type); + + this._objectId = objectId; + this._petId = petId; + } + + public get objectId(): number + { + return this._objectId; + } + + public get petId(): number + { + return this._petId; + } +} diff --git a/src/views/room/messages/index.ts b/src/views/room/messages/index.ts index b11cc9a7..d3ccbe7d 100644 --- a/src/views/room/messages/index.ts +++ b/src/views/room/messages/index.ts @@ -9,4 +9,5 @@ export * from './RoomWidgetFurniActionMessage'; export * from './RoomWidgetMessage'; export * from './RoomWidgetRequestWidgetMessage'; export * from './RoomWidgetRoomObjectMessage'; +export * from './RoomWidgetUseProductMessage'; export * from './RoomWidgetUserActionMessage'; diff --git a/src/views/room/widgets/RoomWidgetsView.tsx b/src/views/room/widgets/RoomWidgetsView.tsx index e0cd7f19..57523e17 100644 --- a/src/views/room/widgets/RoomWidgetsView.tsx +++ b/src/views/room/widgets/RoomWidgetsView.tsx @@ -1,6 +1,6 @@ -import { RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent } from 'nitro-renderer'; +import { NitroEvent, RoomEngineUseProductEvent, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; -import { useRoomSessionManagerEvent } from '../../../hooks/events'; +import { useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks/events'; import { LocalizeText } from '../../../utils/LocalizeText'; import { useRoomContext } from '../context/RoomContext'; import { AvatarInfoWidgetView } from './avatar-info/AvatarInfoWidgetView'; @@ -15,24 +15,26 @@ export const RoomWidgetsView: FC = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); - const onRoomSessionEvent = useCallback((event: RoomSessionEvent) => + const onNitroEvent = useCallback((event: NitroEvent) => { if(!widgetHandler) return; widgetHandler.processEvent(event); }, [ widgetHandler ]); - useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionChatEvent.FLOOD_EVENT, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionDanceEvent.RSDE_DANCE, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionUserBadgesEvent.RSUBE_BADGES, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionDoorbellEvent.DOORBELL, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_REJECTED, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_ACCEPTED, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionDimmerPresetsEvent.ROOM_DIMMER_PRESETS, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionPresentEvent.RSPE_PRESENT_OPENED, onRoomSessionEvent); - useRoomSessionManagerEvent(RoomSessionPetInfoUpdateEvent.PET_INFO, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionChatEvent.FLOOD_EVENT, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionDanceEvent.RSDE_DANCE, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionUserBadgesEvent.RSUBE_BADGES, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionDoorbellEvent.DOORBELL, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_REJECTED, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_ACCEPTED, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionDimmerPresetsEvent.ROOM_DIMMER_PRESETS, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionPresentEvent.RSPE_PRESENT_OPENED, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionPetInfoUpdateEvent.PET_INFO, onNitroEvent); + useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY, onNitroEvent); + useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM, onNitroEvent); const onRoomErrorEvent = useCallback((event: RoomSessionEvent) => { diff --git a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx index 1514df9e..d691e06e 100644 --- a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx +++ b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx @@ -5,7 +5,7 @@ import { FriendEnteredRoomEvent } from '../../../../events'; import { useUiEvent } from '../../../../hooks/events'; import { CreateEventDispatcherHook } from '../../../../hooks/events/event-dispatcher.base'; import { useRoomContext } from '../../context/RoomContext'; -import { RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRentableBotChatEvent } from '../../events'; +import { RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRentableBotChatEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../../events'; import { RoomWidgetRoomObjectMessage } from '../../messages'; import { AvatarInfoWidgetViewProps } from './AvatarInfoWidgetView.types'; import { AvatarInfoWidgetAvatarView } from './views/avatar/AvatarInfoWidgetAvatarView'; @@ -16,12 +16,16 @@ import { AvatarInfoWidgetOwnPetView } from './views/own-pet/AvatarInfoWidgetOwnP import { AvatarInfoWidgetPetView } from './views/pet/AvatarInfoWidgetPetView'; import { AvatarInfoRentableBotChatView } from './views/rentable-bot-chat/AvatarInfoRentableBotChatView'; import { AvatarInfoWidgetRentableBotView } from './views/rentable-bot/AvatarInfoWidgetRentableBotView'; +import { AvatarInfoUseProductConfirmView } from './views/use-product-confirm/AvatarInfoUseProductConfirmView'; +import { AvatarInfoUseProductView } from './views/use-product/AvatarInfoUseProductView'; export const AvatarInfoWidgetView: FC = props => { - const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); + const { roomSession = null, eventDispatcher = null, widgetHandler = null } = useRoomContext(); const [ name, setName ] = useState(null); const [ nameBubbles, setNameBubbles ] = useState([]); + const [ productBubbles, setProductBubbles ] = useState([]); + const [ confirmingProduct, setConfirmingProduct ] = useState(null); const [ infoStandEvent, setInfoStandEvent ] = useState(null); const [ isGameMode, setGameMode ] = useState(false); const [ isDancing, setIsDancing ] = useState(false); @@ -40,6 +44,19 @@ export const AvatarInfoWidgetView: FC = props => }); }, []); + const removeProductBubble = useCallback((index: number) => + { + setProductBubbles(prevValue => + { + const newValue = [ ...prevValue ]; + const item = newValue.splice(index, 1)[0]; + + if(confirmingProduct === item) setConfirmingProduct(null); + + return newValue; + }); + }, [ confirmingProduct ]); + const clearInfoStandEvent = useCallback(() => { setInfoStandEvent(null); @@ -83,6 +100,31 @@ export const AvatarInfoWidgetView: FC = props => }); if(nameBubbleIndex > -1) removeNameBubble(nameBubbleIndex); + + if(productBubbles.length) + { + setProductBubbles(prevValue => + { + return prevValue.filter(bubble => + { + return (bubble.id !== event.id); + }); + }); + } + } + + else if(event.category === RoomObjectCategory.FLOOR) + { + if(productBubbles.length) + { + setProductBubbles(prevValue => + { + return prevValue.filter(bubble => + { + return (bubble.requestRoomObjectId !== event.id); + }); + }); + } } if(infoStandEvent) @@ -102,7 +144,7 @@ export const AvatarInfoWidgetView: FC = props => if(infoStandEvent.roomIndex === event.id) setInfoStandEvent(null); } } - }, [ name, infoStandEvent, nameBubbles, removeNameBubble ]); + }, [ name, infoStandEvent, nameBubbles, productBubbles, removeNameBubble ]); CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_REMOVED, eventDispatcher, onRoomObjectRemoved); CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomObjectRemoved); @@ -137,10 +179,9 @@ export const AvatarInfoWidgetView: FC = props => const onObjectDeselected = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => { - if(!infoStandEvent) return; - - setInfoStandEvent(null); - }, [ infoStandEvent ]); + if(infoStandEvent) setInfoStandEvent(null); + if(productBubbles.length) setProductBubbles([]); + }, [ infoStandEvent, productBubbles ]); CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, eventDispatcher, onObjectDeselected); @@ -182,6 +223,27 @@ export const AvatarInfoWidgetView: FC = props => CreateEventDispatcherHook(RoomWidgetUpdateRentableBotChatEvent.UPDATE_CHAT, eventDispatcher, onRoomWidgetUpdateRentableBotChatEvent); + const onRoomWidgetUseProductBubbleEvent = useCallback((event: RoomWidgetUseProductBubbleEvent) => + { + setProductBubbles(prevValue => + { + const newBubbles = [ ...prevValue ]; + + for(const item of event.items) + { + const index = newBubbles.findIndex(bubble => (bubble.id === item.id)); + + if(index > -1) newBubbles.splice(index, 1); + + newBubbles.push(item); + } + + return newBubbles; + }); + }, []); + + CreateEventDispatcherHook(RoomWidgetUseProductBubbleEvent.USE_PRODUCT_BUBBLES, eventDispatcher, onRoomWidgetUseProductBubbleEvent); + const onFriendEnteredRoomEvent = useCallback((event: FriendEnteredRoomEvent) => { setNameBubbles(prevValue => @@ -278,7 +340,12 @@ export const AvatarInfoWidgetView: FC = props => { return removeNameBubble(index) } />; }) } + { (productBubbles.length > 0) && productBubbles.map((item, index) => + { + return removeProductBubble(index) } />; + }) } { rentableBotChatEvent && } + { confirmingProduct && setConfirmingProduct(null) } /> } ) } diff --git a/src/views/room/widgets/avatar-info/utils/BotSkillsEnum.ts b/src/views/room/widgets/avatar-info/common/BotSkillsEnum.ts similarity index 100% rename from src/views/room/widgets/avatar-info/utils/BotSkillsEnum.ts rename to src/views/room/widgets/avatar-info/common/BotSkillsEnum.ts diff --git a/src/views/room/widgets/avatar-info/utils/PetSupplementEnum.ts b/src/views/room/widgets/avatar-info/common/PetSupplementEnum.ts similarity index 100% rename from src/views/room/widgets/avatar-info/utils/PetSupplementEnum.ts rename to src/views/room/widgets/avatar-info/common/PetSupplementEnum.ts diff --git a/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx b/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx index bcc54ac7..a5b3a2ff 100644 --- a/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx +++ b/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx @@ -70,18 +70,15 @@ export const AvatarInfoWidgetOwnPetView: FC = p break; case 'pick_up': messageType = RoomWidgetUserActionMessage.PICKUP_PET; - //this.widget._Str_25401(); break; case 'mount': messageType = RoomWidgetUserActionMessage.MOUNT_PET; break; case 'toggle_riding_permission': messageType = RoomWidgetUserActionMessage.TOGGLE_PET_RIDING_PERMISSION; - // update riding checkbox break; case 'toggle_breeding_permission': - messageType = RoomWidgetUserActionMessage.TOGGLE_PET_BREEDING_PERMISSION - // update breeding checkbox; + messageType = RoomWidgetUserActionMessage.TOGGLE_PET_BREEDING_PERMISSION; break; case 'dismount': messageType = RoomWidgetUserActionMessage.DISMOUNT_PET; @@ -162,7 +159,7 @@ export const AvatarInfoWidgetOwnPetView: FC = p processAction('buy_saddle') }> { LocalizeText('infostand.button.buy_saddle') } } - { ([ PetType.BEAR, PetType.TERRIER, PetType.CAT, PetType.DOG, PetType.PIG].indexOf(petData.petType) > -1) && + { ([ PetType.BEAR, PetType.TERRIER, PetType.CAT, PetType.DOG, PetType.PIG ].indexOf(petData.petType) > -1) && processAction('breed') }> { LocalizeText('infostand.button.breed') } } @@ -173,6 +170,7 @@ export const AvatarInfoWidgetOwnPetView: FC = p { LocalizeText('infostand.button.mount') } processAction('toggle_riding_permission') }> + { LocalizeText('infostand.button.toggle_riding_permission') } { (respectsLeft > 0) && @@ -186,7 +184,7 @@ export const AvatarInfoWidgetOwnPetView: FC = p { LocalizeText('infostand.button.pickup') } processAction('saddle_off') }> - { LocalizeText('infostand.button.saddle_off') } + { LocalizeText('infostand.button.saddleoff') } } { (mode === _Str_5938) && @@ -219,6 +217,7 @@ export const AvatarInfoWidgetOwnPetView: FC = p { !petData.dead && (petData.level === petData.maximumLevel) && petData.breedable && <> processAction('toggle_breeding_permission') }> + { LocalizeText('infostand.button.toggle_breeding_permission') } processAction('breed') }> diff --git a/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx index ed82968a..ab5522ba 100644 --- a/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx +++ b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx @@ -7,7 +7,7 @@ import { RoomWidgetUpdateRentableBotChatEvent } from '../../../../events'; import { ContextMenuView } from '../../../context-menu/ContextMenuView'; import { ContextMenuHeaderView } from '../../../context-menu/views/header/ContextMenuHeaderView'; import { ContextMenuListItemView } from '../../../context-menu/views/list-item/ContextMenuListItemView'; -import { BotSkillsEnum } from '../../utils/BotSkillsEnum'; +import { BotSkillsEnum } from '../../common/BotSkillsEnum'; import { AvatarInfoWidgetRentableBotViewProps } from './AvatarInfoWidgetRentableBotView.types'; const MODE_NORMAL = 0; diff --git a/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx new file mode 100644 index 00000000..32ea2d7d --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx @@ -0,0 +1,83 @@ +import { IFurnitureData, RoomObjectCategory, RoomUserData } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { GetFurnitureDataForRoomObject } from '../../../../../../api'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../../layout'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { FurniCategory } from '../../../../../inventory/common/FurniCategory'; +import { useRoomContext } from '../../../../context/RoomContext'; +import { RoomWidgetUseProductMessage } from '../../../../messages'; +import { AvatarInfoUseProductConfirmViewProps } from './AvatarInfoUseProductConfirmView.types'; + +const _Str_5091: number = -1; +const _Str_11906: number = 0; +const _Str_11214: number = 1; +const _Str_11733: number = 2; +const _Str_11369: number = 3; +const _Str_8759: number = 4; +const _Str_8432: number = 5; +const _Str_9653: number = 6; + +export const AvatarInfoUseProductConfirmView: FC = props => +{ + const { item = null, close = null } = props; + const [ mode, setMode ] = useState(_Str_5091); + const [ petData, setPetData ] = useState(null); + const [ furniData, setFurniData ] = useState(null); + const { roomSession = null, widgetHandler = null } = useRoomContext(); + + const useProduct = useCallback(() => + { + widgetHandler.processWidgetMessage(new RoomWidgetUseProductMessage(RoomWidgetUseProductMessage.PET_PRODUCT, item.requestRoomObjectId, petData.webID)); + }, [ widgetHandler, item, petData ]); + + useEffect(() => + { + const userData = roomSession.userDataManager.getUserDataByIndex(item.id); + + setPetData(userData); + + const furniData = GetFurnitureDataForRoomObject(roomSession.roomId, item.requestRoomObjectId, RoomObjectCategory.FLOOR); + + if(!furniData) return; + + setFurniData(furniData); + + let mode = _Str_5091; + + switch(furniData.specialType) + { + case FurniCategory._Str_7696: + mode = _Str_11906; + break; + case FurniCategory._Str_7297: + mode = _Str_11214; + break; + case FurniCategory._Str_7954: + mode = _Str_11733; + break; + case FurniCategory._Str_6096: + mode = _Str_11369; + break; + case FurniCategory._Str_6915: + mode = _Str_8759; + break; + case FurniCategory._Str_8726: + mode = _Str_8432; + break; + case FurniCategory._Str_9449: + mode = _Str_9653; + break; + } + + setMode(mode); + }, [ roomSession, item ]); + + return ( + + + + + + + ) +} diff --git a/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.types.ts b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.types.ts new file mode 100644 index 00000000..8f1c3ad3 --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.types.ts @@ -0,0 +1,7 @@ +import { UseProductItem } from '../../../../events'; + +export interface AvatarInfoUseProductConfirmViewProps +{ + item: UseProductItem; + close: () => void; +} diff --git a/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx new file mode 100644 index 00000000..f2e66720 --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx @@ -0,0 +1,138 @@ +import { RoomObjectCategory } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { GetFurnitureDataForRoomObject } from '../../../../../../api'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { FurniCategory } from '../../../../../inventory/common/FurniCategory'; +import { useRoomContext } from '../../../../context/RoomContext'; +import { ContextMenuView } from '../../../context-menu/ContextMenuView'; +import { ContextMenuHeaderView } from '../../../context-menu/views/header/ContextMenuHeaderView'; +import { ContextMenuListItemView } from '../../../context-menu/views/list-item/ContextMenuListItemView'; +import { AvatarInfoUseProductViewProps } from './AvatarInfoUseProductView.types'; + +const _Str_2906: number = 0; +const _Str_13718: number = 1; +const _Str_14146: number = 2; +const _Str_15667: number = 3; +const _Str_14658: number = 4; +const _Str_14165: number = 5; +const _Str_12577: number = 6; +const _Str_14611: number = 7; + +export const AvatarInfoUseProductView: FC = props => +{ + const { item = null, setConfirmingProduct = null, close = null } = props; + const [ mode, setMode ] = useState(0); + const { roomSession = null } = useRoomContext(); + + useEffect(() => + { + if(!item) return; + + const furniData = GetFurnitureDataForRoomObject(roomSession.roomId, item.requestRoomObjectId, RoomObjectCategory.FLOOR); + + if(!furniData) return; + + let mode = _Str_2906; + + switch(furniData.specialType) + { + case FurniCategory._Str_7696: + mode = _Str_13718; + break; + case FurniCategory._Str_7297: + mode = _Str_14146; + break; + case FurniCategory._Str_7954: + mode = _Str_15667; + break; + case FurniCategory._Str_6096: + mode = _Str_14658; + break; + case FurniCategory._Str_6915: + mode = _Str_14165; + break; + case FurniCategory._Str_8726: + mode = _Str_12577; + break; + case FurniCategory._Str_9449: + mode = _Str_14611; + break; + } + + setMode(mode); + }, [ roomSession, item ]); + + const processAction = useCallback((name: string) => + { + let hideMenu = true; + + if(name) + { + switch(name) + { + case 'use_product': + case 'use_product_shampoo': + case 'use_product_custom_part': + case 'use_product_custom_part_shampoo': + case 'use_product_saddle': + case 'replace_product_saddle': + case 'revive_monsterplant': + case 'rebreed_monsterplant': + case 'fertilize_monsterplant': + setConfirmingProduct(item); + break; + default: + break; + } + } + + if(hideMenu) close(); + }, [ item, setConfirmingProduct, close ]); + + return ( + + + { item.name } + + { (mode === _Str_2906) && + processAction('use_product') }> + { LocalizeText('infostand.button.useproduct') } + } + { (mode === _Str_13718) && + processAction('use_product_shampoo') }> + { LocalizeText('infostand.button.useproduct_shampoo') } + } + { (mode === _Str_14146) && + processAction('use_product_custom_part') }> + { LocalizeText('infostand.button.useproduct_custom_part') } + } + { (mode === _Str_15667) && + processAction('use_product_custom_part_shampoo') }> + { LocalizeText('infostand.button.useproduct_custom_part_shampoo') } + } + { (mode === _Str_14658) && + <> + { item.replace && + processAction('replace_product_saddle') }> + { LocalizeText('infostand.button.replaceproduct_saddle') } + } + { !item.replace && + processAction('use_product_saddle') }> + { LocalizeText('infostand.button.useproduct_saddle') } + } + } + { (mode === _Str_14165) && + processAction('revive_monsterplant') }> + { LocalizeText('infostand.button.revive_monsterplant') } + } + { (mode === _Str_12577) && + processAction('rebreed_monsterplant') }> + { LocalizeText('infostand.button.rebreed_monsterplant') } + } + { (mode === _Str_14611) && + processAction('fertilize_monsterplant') }> + { LocalizeText('infostand.button.fertilize_monsterplant') } + } + + ); +} diff --git a/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.types.ts b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.types.ts new file mode 100644 index 00000000..1407ee5e --- /dev/null +++ b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.types.ts @@ -0,0 +1,9 @@ +import { Dispatch, SetStateAction } from 'react'; +import { UseProductItem } from '../../../../events'; + +export interface AvatarInfoUseProductViewProps +{ + item: UseProductItem; + setConfirmingProduct: Dispatch>; + close: () => void; +} diff --git a/src/views/room/widgets/context-menu/ContextMenuView.tsx b/src/views/room/widgets/context-menu/ContextMenuView.tsx index 3dff75a6..c99f48b4 100644 --- a/src/views/room/widgets/context-menu/ContextMenuView.tsx +++ b/src/views/room/widgets/context-menu/ContextMenuView.tsx @@ -15,6 +15,7 @@ export const ContextMenuView: FC = props => const [ opacity, setOpacity ] = useState(1); const [ isFading, setIsFading ] = useState(false); const [ fadeTime, setFadeTime ] = useState(0); + const [ frozen, setFrozen ] = useState(false); const elementRef = useRef(); const update = useCallback((time: number) => @@ -72,13 +73,20 @@ export const ContextMenuView: FC = props => useEffect(() => { - GetTicker().add(update); + let added = false; + + if(!frozen) + { + added = true; + + GetTicker().add(update); + } return () => { - GetTicker().remove(update); + if(added) GetTicker().remove(update); } - }, [ update ]); + }, [ frozen, update ]); useEffect(() => { @@ -93,7 +101,7 @@ export const ContextMenuView: FC = props => }, [ fades ]); return ( -
+
setFrozen(true) } onMouseLeave={ event => setFrozen(false) }> { children }
); diff --git a/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx b/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx index c37a30ab..c934373b 100644 --- a/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx +++ b/src/views/room/widgets/infostand/views/pet/InfoStandWidgetPetView.tsx @@ -14,7 +14,7 @@ export const InfoStandWidgetPetView: FC = props => { petData.name }
{ LocalizeText('pet.breed.' + petData.petType + '.' + petData.petBreed) } } onCloseClick={ close }>
- +
{ LocalizeText('pet.level', ['level', 'maxlevel'], [petData.level.toString(), petData.maximumLevel.toString()]) }
diff --git a/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx b/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx index c4d79504..ffa24a0a 100644 --- a/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx +++ b/src/views/room/widgets/infostand/views/rentable-bot/InfoStandWidgetRentableBotView.tsx @@ -4,7 +4,7 @@ import { SendMessageHook } from '../../../../../../hooks/messages'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { AvatarImageView } from '../../../../../shared/avatar-image/AvatarImageView'; import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView'; -import { BotSkillsEnum } from '../../../avatar-info/utils/BotSkillsEnum'; +import { BotSkillsEnum } from '../../../avatar-info/common/BotSkillsEnum'; import { InfoStandBaseView } from '../base/InfoStandBaseView'; import { InfoStandWidgetRentableBotViewProps } from './InfoStandWidgetRentableBotView.types'; diff --git a/src/views/wired/WiredView.tsx b/src/views/wired/WiredView.tsx index e438dd67..b9517011 100644 --- a/src/views/wired/WiredView.tsx +++ b/src/views/wired/WiredView.tsx @@ -1,8 +1,8 @@ import { ConditionDefinition, Triggerable, TriggerDefinition, UpdateActionMessageComposer, UpdateConditionMessageComposer, UpdateTriggerMessageComposer, WiredActionDefinition } from 'nitro-renderer'; import { FC, useCallback, useMemo, useState } from 'react'; -import { GetConnection } from '../../api'; import { WiredEvent } from '../../events'; import { useUiEvent } from '../../hooks/events'; +import { SendMessageHook } from '../../hooks/messages'; import { GetWiredLayout } from './common/GetWiredLayout'; import { WiredContextProvider } from './context/WiredContext'; import { WiredMessageHandler } from './WiredMessageHandler'; @@ -27,18 +27,17 @@ export const WiredView: FC = props => if(trigger instanceof WiredActionDefinition) { - GetConnection().send(new UpdateActionMessageComposer(trigger.id, intParams, stringParam, furniIds, actionDelay, trigger.stuffTypeSelectionCode)); + SendMessageHook(new UpdateActionMessageComposer(trigger.id, intParams, stringParam, furniIds, actionDelay, trigger.stuffTypeSelectionCode)); } else if(trigger instanceof TriggerDefinition) { - console.log(intParams, stringParam); - GetConnection().send(new UpdateTriggerMessageComposer(trigger.id, intParams, stringParam, furniIds, trigger.stuffTypeSelectionCode)); + SendMessageHook(new UpdateTriggerMessageComposer(trigger.id, intParams, stringParam, furniIds, trigger.stuffTypeSelectionCode)); } else if(trigger instanceof ConditionDefinition) { - GetConnection().send(new UpdateConditionMessageComposer(trigger.id, intParams, stringParam, furniIds, trigger.stuffTypeSelectionCode)); + SendMessageHook(new UpdateConditionMessageComposer(trigger.id, intParams, stringParam, furniIds, trigger.stuffTypeSelectionCode)); } }, [ trigger, intParams, stringParam, furniIds, actionDelay ]); From 2f1bbf83f95613ffd2226e1d5099225e148cf8a2 Mon Sep 17 00:00:00 2001 From: Bill Date: Sun, 11 Jul 2021 02:37:56 -0400 Subject: [PATCH 40/72] Update avatar info use product --- src/assets/images/modtool/m_icon.png | Bin 0 -> 299 bytes .../avatar-info/monsterplant-preview.png | Bin 0 -> 2048 bytes .../avatar-info/preview-background.png | Bin 0 -> 7756 bytes .../stickie-widget/stickie-christmas.png | Bin 0 -> 1272 bytes src/views/room/widgets/RoomWidgets.scss | 1 + .../avatar-info/AvatarInfoWidgetView.scss | 13 ++ .../avatar-info/AvatarInfoWidgetView.tsx | 35 ++- .../AvatarInfoUseProductConfirmView.tsx | 200 +++++++++++++++++- .../use-product/AvatarInfoUseProductView.tsx | 39 ++-- .../AvatarInfoUseProductView.types.ts | 3 +- 10 files changed, 250 insertions(+), 41 deletions(-) create mode 100644 src/assets/images/modtool/m_icon.png create mode 100644 src/assets/images/room-widgets/avatar-info/monsterplant-preview.png create mode 100644 src/assets/images/room-widgets/avatar-info/preview-background.png create mode 100644 src/assets/images/room-widgets/stickie-widget/stickie-christmas.png create mode 100644 src/views/room/widgets/avatar-info/AvatarInfoWidgetView.scss diff --git a/src/assets/images/modtool/m_icon.png b/src/assets/images/modtool/m_icon.png new file mode 100644 index 0000000000000000000000000000000000000000..1116b4ded8492bfb4d0ff477b8281f9cea5c0e0f GIT binary patch literal 299 zcmeAS@N?(olHy`uVBq!ia0vp^(m*W7!3-o{9iMsyNHG=%xjQkeJ16rJ$YDu$^mSxl z*x1kgCy^D%R}An8aeephosyE$|NsAIp820P^UTaMXVPZQ1WFnkrvU+w@wWcKIUvPd z666;QR0ahMUjB@qfWn*w9+AaBSz!=nWSBKa0w`GH>Eak-;lKB?wNQfskAtH?&w;=E zIdvK{5}y7zHt~U&i9{549f!8llJGA{e1+aOw{Rb0*|w%_GN)egtFjw;k4tmR81B6= zkd!@WE!iXZDvS5mqnY0pUi4-=&Sa~7xX$R$F=^Sf+0tjOt-T=G-xa01O>5h}-TCEp eKi6+5V{-q(nRP&T@d}_j7(8A5T-G@yGywpMymChX literal 0 HcmV?d00001 diff --git a/src/assets/images/room-widgets/avatar-info/monsterplant-preview.png b/src/assets/images/room-widgets/avatar-info/monsterplant-preview.png new file mode 100644 index 0000000000000000000000000000000000000000..8d3d771ef46781f618464db09215eff640b7aa74 GIT binary patch literal 2048 zcmbW2`9Bj39LJX{rqSVyJn@v9BoT6@FgbD#Ifh}vMrh8+7$L*s%n?bvupvid_Atwa z4G{^`9GiF?QPP1td;W#z^Ll+g@7L#-&+Gf!_wgM&OAzoZ5C8yxz*aXMxpd>&S&)~T zmmdQXxi}W-Xn6yGAC+C>7QP@eTQdNl6)Sw;%g^oYcWj(*ap?z#XXWMQWyDq$roMa< z(%wyY-d2jvfOvT8IRt~T3AXtKLH8h+y4&l5y=@!uk3$hwmvwaBknn?qrz7viQ(`lbUS3_Byx3Qo&>#0u6g`CC#*h)Sp>celS&k$m&_c*>Ckl zfK`AhQUcD}pk!x>qV$;B0yGVwF_~+M3({@P3O-t=9c@oemxa-KaDP?SG8hb4388cO zhrsw&PDlS=0Aj{^9d}14+{!%?01%=4=VLTvJq!R4cmlp@=ImzKF%62J za68Gr5X=*N-ZUE5h|daBnZ;mL-)lzyJUR*)D>Vcoj1i{$8)m@Nl@TqJRfFuXl}6{z zYbPFsAP2DlG&x*KbopAGN*K|wNV3lv)`JwpuUim7IrUckJCO5E=f#A1?u9 zL5iE^*gOX6^q;YDsZ?UrUjp>h0R2CP;N^S6JbEufnh*H``j&UxUKy8$_krm7r{%Ew zu(b%Z_Cj9vcn;VNK}IMJLq(QFq)8k&vOqJMRU%tJy z^@^3*ro6}}mDyK80_W4&jtNp*YJD4Db*?d*K1kRrv`M=q5cTBKjB zs1m2CQPW+6iWp+;jE^V6!7AU2vUc=6TdtjJQK`^e^kaIO&!Z?dY;E$CY9o~FRIWJq z4}H&l{8n$foa~icmLjtBg4~JL?g-3B;)1!ENQBElX2tbnbe2j!RO9%mfX=1RjI{EL z4yP@XI^AU_D%}qwMWdB>r+un@9S|o7SY?$;vGC zO-=dc6fr@Z|Nfbk2=ANqK(|Fb?~JTr=}DDiu$*NvL@g-tiM46kC|j%;5#T#p`p*Mi>Ri;{gH`enzT z?&8LIROQ#5v5?REs=nlV3F~w6{-XI@v=+=p+Se8{VI(CDeQ%CHkp;}D(^UoI0sU9d z$D2G-5J6;q#?$nqtaUz4gWox$(Z`Z=;CEi(LQa314!wx|?qL?}jZHre#6t%q^COho z**vZdI-#?cCl`g(sCpOt)%=b%VyLBA1N}qyx zz}tt{ReGgiiK$#FF523-2h5zhz~)co_PAu18rl7FK$07yXs@iV(Cv9 zR%TDA%aEu-n!FpHc~iiRK#F7QvVu=@~e z8z`n|8HWZ&_~7{G`MYP>7hYdaX6`E^zE`x=_?{^mu|^Fz;`HJKowM<)@=qaoX@X=ik96b8*ISBu$L@Xy&^-ITY zgUqCzRGz)^Oq?)q>Xp3AL&30N-n-<4{a+(W^ElB;r}wJ*bXU^e+1pC55}_k^V!zsw zzV#apmO!!rab$(7G5z-PbDO9hZNkSVG=HrC8v*5jh-BG;+3ht4;A__}%h*409~@TJ zn2GxhhIRZ{W6#2aAIoAfL3NQ8n0$-gE+J$A!a;j-;CZk3ae13=g2>Osm-gOdJS+f9 z@zD04mN#MUvcY3i?MXy41~Y--F)+>Fru$XqMmFJk<$t9mDZSz90zWiyN90(L?(U+ zoN>PCz!%y`3;3fOx+_s%pvCrE&`~cSPZ$|ZS-)=+ogQHdZ2Tg!AW5HM+ZdBfi6(Vu z>_hJ2-o8YVNnBajf_g2TQ}20{ogE_2R_tLRtLH+pWKtCDrhIm+_n^$#?cXbbpD_eE ztA|W#P&3<_vp;5AVhfm;N7bp$psRJ`8T!=2s4n%cHC^B0cbrep+4&kwyC1Nh(wn>U zDQR<{#sr>C1M<}U%S8x)@!(iel3XF~RP84}q`=}C7^A>P$^Y~D>I(ZjkeYv)SIYkH zhS0L%RFqMxjOO0N?XgOwA@c6#4}~sNZ}H$E(d>5;v{G|(rkNA|LzI~lwlva4VRF9} N0DQ~tCjJIAWP@ literal 0 HcmV?d00001 diff --git a/src/assets/images/room-widgets/avatar-info/preview-background.png b/src/assets/images/room-widgets/avatar-info/preview-background.png new file mode 100644 index 0000000000000000000000000000000000000000..dea4f08dd49c0ddbc562e6eb17c854411d830cab GIT binary patch literal 7756 zcmV-S9<$+zP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D9pOntK~#8N?R`m> zBuA1R5>-uJsMq~^$JZwS>LT25(HpLKkb1xodfRIriH)TEK}1CdGk1@O911VLxu|^k zB089=n}=s$$WK2t{PN2$pH2T^@#)iaOA|hS-f!=&{!3t8!>j9k1;79P`#v}h`3L@7 z*dE*;hy3S79`+}Y-+udz2mS+pPW<}ouRr~4{sVtI(yUa z-PpfWQMvuDb(_4zKmW`BG#j{lqQ9?0#sNHM_y&tFv6mKA*TBZ!Tl~m-!TxBr=c75! zG3;%)I=k=mqZ>z(c8&EQzckkQ?&m}@?c3u!JLvn3dD|v`gk9sc^?W;gCkK7K5sx=A z`*!8cykxO*j?69$~Nh)(8F-5Bhu~Z$IFyX?0y%jqdS<*R2toaDlz% z@qvFCe1(JFZx(pl0cYMdJq+sycDkNHuU{`03?nw-fIWYG;Ct;y;0qu0dBLw8aORwE zVLt?1kI_0`+BN!IxbP|?Hetb@yFc)c!xud0eWCkJA-KAsmP=ZpH~NTP+>Dc-Q?ngK z+l*WX*RqvO!Gb;azQcZ8_k|96pLoBKtHnWgZlY~dCuC9B@i3un;=N^`Ceh|#!nC%j ze;z(3Xdpo88QFfa17Kx=SC*Sc22W^7wka+8}$oNT{dt$+)^%!4+q zSP4al8h4UMeqh$>mI{YHlXM#ML!Rh;;CXSUiLI6MCKSNK=)|oIv<(-s&b5(CtJ)W= z`p=`<;8aILXe(AZY_YX4JzJUE^Cyk>(Bgf}$3TyFV4uSGZJd^1tz54G53|cGDUh32 zlPJq8wCPX@eGi-Ji30V{+pU8aJrtQx9h?Geq58%RyUo<}h}%8Kdsr2KMom zy3A3TbsA{3&>A~3zu6V41LXvL8WUW$ZXQI;R(gvMtw8r4=uJO{HHi5nGS#CQKFoNwVw5qaY05b zt}{aHF1+B8GpByCRvXRGfx*(PxH#yG>RX)pjLEgk1O=yCCU?L|r86r(4v|sC(qMke zBc?t-&G8X-YgM~my{0Z~dTLyaF2t_Wn&9MnD`y^1JxMkTTJ0$vxR76cqUT|*CKH?t zS2sXVFuWCz@=1sW@7SN~>5w6&=9<*R+hMv+2QVKpEDFx1m5eL2(MP$eNxigaOJigg znh0CObgh*$4`dIa^GCR^#T{M(>$zF0%9Nn`af8B=R{X3#J5Lto=DcLKQ` zsQa1!GWiL;|1H)+$6Nm{=r##1mPA@DK5rzUc-&l=V_X>z4T`yS9sXZz;60YWDRd46JHLpW}dW6BlrP+(-#*s(TIO zjjGM+8zXJnNN=o0LX3LFdKzFpO!WOJ4iLtE8vAJ3KiUvHPUh6NG+d0a1{q`G6h~XN z4CFEfNLvgn;fk7~fc5Vo7V#tWt_r!?#!Xz&dyqF@`I|8H+174wo9MXI)S9ow*Kuux^Y|eWfGj8_ZYU3ua@EEaKt- zVtJzHlt2Z2xX)Nxb`Nn!x7HMKOOCvaA$hcwV<1;?H3Lg14ADbe0(bB#QMRqbYV<7DPx;V14392#?=RP!KxP%V~MpF7Js^-;e(cQD2ba5JimaeO%JyQ$x(2HJ-<*E8;#^ zXE|qGoMBu!hc5wZy2gF>NsP$?rjs^B!7Bhq5Z1~`DWO3$>UIqqmO6NDk`KZ;Ud}`B zmU{K=Irkepbo;F98a%Z0VDdv(ogkJubHlw`u4zQ$T|VIc7beJE+P-0%#;53%1CLFu zrwp%X&?0Z1RvU>pIAUt$HFoAxABWlx(R?*NPb2<0J_({7aq-ZtRXwtc&o#>gvJ5j% zKTy%4Z&=g*LUx7Ni5sln>{bH~dVOo8#pc2T$k}(p0Wi~Uo*KNhHJ)mCjl;&~cRt<> zK7^B@p5`}4sPH<-KF{FYM-y)G&ZUQzhBhG{Eo;n;s;peoHeBhq2OXWz?}2F(!K1-w z)@O^RysW-~Vqbl6OOd132J6B>*v#_@OHYoU$E{}LG>m;Ry%B=AkF|)XO?hjJkERU$ zM^0*wiR?o^P|>2F@l4I#LErX&VsI~#t;bcVW=&TDwklb+k|+p8`-(C!LsHSyTbKB<74#>9D5&lUw+2uptv@p zQtm}bxvY^#36jX}e$>X3xEwGz4vjH2)oih~{?uk%xnP;Q^tD#>!B}Hl#{Lro>W4vJ zwS%=9jct9x8VgZ<0tUeAg$t7x$L8dvak?@tsJR4H(iKvZ#|6H6=IkfEts`UkFleQx z;V@9$HWXFK?WJFMB>OkIbT@vUj_Z7gWw!*^a9k$Feddo9Ck8kC>)!QJx$&fS!p5Bkx^ z_66p}EVJfK&;vbA4jo7>TI9oWZ24&2Z_YQK2ZWe4iuop3OmBv;_-LFo#?dE#VPn1L zBPf$@&sBt;9+Z$K>O8$Ln6V12me@L+ffc=u7+g1DtdlS3S@EeiMJeN^bvV*2s0O~* zP<36eX?YlU8uHz!`;vy&i1{N1I+XI^SdlgMN-&34QZ#buNBRmQf3EaMPvLyf&-dTq z8)aKJy&&bhX|z*msjhL7<1M^-*3pkV4>4<$A;$Lu>!{(=I>v!sKd-5UgO)iu*Awu5 znwebYDBiWj_-PR4Ple~~F)-Q@WASf6?;E@}Ds{)i?yD@dwwblbi1iwIdd0}}1LgrX zvpnlV6n9;6`6yx2jCCW=@tI54auflu6oz^Sj`0xZn#+U!63`Nsg+!4|@hL9`pwwSGH}IylzWeH4QD!&1OAc=_wPcA=8BzlKaxE z>0r7Z4oICbd?rA_F)jmYL~(hAEV3m1A^MoTPt(WR66ZfMee6Md0n@yRt3?A5YLmq? zFPhxG<-7LQ|Bx(-Ro+C0|^&O8Z zuJNWPdb*MKAcm>2=+K1HhG)JDD_Xx{4Hb%v0~Y4k9-0_A^|glRYekJ|fV7YE1p2x@ z8Xx=7{SYtQ$jwd98`5}EdTjC}+-~G{*u-4F9UH?%Bknbh(@O5%4%e9jZhoWr1rGY9 zrCs1K#)EhJM{L#fMreE*A%fGvsJ!WW$&+~0@ofWtwI_OA-kbL!!2$MBrbFoT!5d}9 zE4AN0-uVA8`GM~ZpYfT^kL~Nv?oWUF+uuI_{qKKwDE#Mt{O@SvUA;U7{1@59*dkwX za`pkYCNVq=?<;Y6|8Chi>H4kKq^&V)6h|YD_iSs{$Q%MrD<9XWZF50m4jNVRjEZOekN?M5eLw&7FaP6zQBTAf zf8-ObNz=U#>mbhzI%=kBZ^neKHJ)1ubPiN}8V{h}a~E|F@u1%uhyAJ_-Fnx)f~7wC z??Z%88n}bQ#!r0_?1L@9@vh@!H)-_-xPi*EZuR$guIe$q>Or4SHxe7sH!yLK0x1kX z*NqO+TV3%1X!_V=(D-cZ3S%&IqT*;$8{`ZQ*zutL5pKFaIB4{oOI3xL&^6~Z-u*=P3FgU`soRF0HdmXPh^U8^O)>K$_A46X!1{>h)@2FD z?x#w`Ob!n)PvSYmM{7i|<~wqffxYH!xE|*VeRMyw@Nv7tORLx$tJoY`kg9EQQ>mvX zWfZ1j5Sujh1FW&JUima26!bS|Y@eT0`Hg$d&sw)!^K3x&ZC0PA@Q-nS(976A{Si%% z0rIYQuCV*rqTxDq8$vL?Qju4Gb82A`_YKI6>OS*>Gny_TJZiFT@=nu7943e}L<6oW z2%~NFiIyGdBlhH~Fuon*_Mjj1T(Oj2^&Xp)z}D#J3_FGO&C*6X!3+vmBrf93LM=Sv z%(+iKNqow7<2-&68PmHj<57niKCQ^nT<asm~;xx!jHO2 zQyY3>Q}&VpzVWW{zJoqYJW1nDj6J5}hLJaDY>2!zSC)0$=;ZKdUDti}O}<#x;3};@ zozTGSi>DqfYhljwMJhhL=+I#C>K_o@N{^=Nt3ALw4mwBojcyofRUQi==0~4waC}tC z@{YB^t}l*5ab0@XX5SjeUb!64;~;iFXt}Rd<$#X0mY;xP{9SwHa05|R1pX^#1TVqYs`70 zQ=hyK%K6Wq|0@g!_FobEXwI2F#FVUOI&V->txvvf0H3bdL{@53(|69AgBOpFQ`X^Q zHSCZ4SawXVIc1|S*O7UwA$SDVQ)?bNBIfy0L*6t*y%ydXxzu``E_G{}n*gmw-0=1< zV>RhDRIx4~m~ZrGdPNg`azmOwYR%UnAy12#`P4PG4lv&!s;|SYaWV%@aWvG*b8N>^ zqxr&jj())=b6?f8n0=uPelq3L?ty=u>iVD`_iu<|)@%A66Uliqr8hHKWit{YQc{YGtExPiE^R)9A{uL=mb=&hZ-55=(#NC&|KiEG5x zZj7}abB#4l&NXWCshvG$#@w1$ec&M}Mvnff6+rdn}fdZNO<8waE7^%5fjPt zX4#+}Ha3DS2}gr>?eMwr(qwrE;?cGmc-wmQT-55YQqM8Wt>?IkSsnD?TaBPN8Q~fU zR?QVJSu~55>%21MLCo`Gj5?@E*w~nG0P0kvoHsr7QLl}c`4CD| zpJ48zgQ^2;x@_%xm?N&NQBD?(bB@6a(9AN&`b6@f%;>eR;q70>61j3BIK#H!DF)1a zquiii{rAY*@0QE|fe%r}>8a%b#5Fi{#ifOx4!Fg6XjuoZ9}6uu4yvLg%hp{n9#^Jfn5l7(p zxftnnFN)I-9?mtSKyo+IQFD$98mu8}fHgPpj*sqr&`Du%aRXi~qm2inlzjNC(I$GM znafRY2g2MqK;?QoTYkhx1ubh+<5hL$H9p=`$f*tT;}>>owW`WYNt1aBaGHH0D8*GXR%1 z@gSrt4;#9?;*O?hz=j_0Jv-j{Wo#LIT1fB~il*ipa{bKXN*;da^0>ew7&#wC9(rn} z-x+>M;*WcnerYmt)G&^J1VrGR=j}Rp_y`ok7YD%kDxQ%rYoa|5tnoeGbkL8c82Mlf zdXJ&Wq4j3e%|ryAIs4?w`5>&LRypa&m&Pk}81o0~SH#h{zjKUZDn*VVm@_#zT7I0H zLyu7zp=8XMJ)w>Ktle9-fac$E{r5*djitZGn^Xq6DIr+bst;~5t9nkla!bsE0v0|c>ejcyz8UU7|abr+_j7&AX5x?6N4~VYpO}*fOAG`xyHM`jLkzICaRkQ z%;*-qYqem+aUrHAW81WC!<*Kv@;JPcJ?yKRS%b62IILpSd)ydbdCX-WRvK#tmk!Oj zvJqDe?JXfU%y8CNh883`^mCMUDPg}ckJR)+i ztXXr?88B9Wrs*&RfuR!Uvtejk_E>+$`=01!qJ7%KLfmJxVRl_Dkxtx-;+i{i&S&mW z^Sr@@x2J+x)QEzfJw+$ZB~<)qHJ zFgo!X6LA{R^P{HQ^pV~yKl00X!AHJ*>`#4sF-OgL_6r)O7CM8#Pzm;_s9|VZ_E>+9 z5BV9*4ZOvk-}@jAvrAH8vJylx)FCz_n3?SAI@JNreS%E4LlHe1)$nQ9!GRG7@;D8^Hc8eR3N z06y8Qv9{Z>59~4Sf7iW^_rUZ|Z_YVcG@BMLuVF}eA!qB_S{DUX2i`7y_=5F*ccyDn zwE$ZYUy4#|LO{VR67Y=~?Je*P9qnFiXKW)(Nw|RbBRb9ybU5_Q4+?HqdH7ZR4No&U$SWKD}&tc;gTc z^^5U>?{<4dx5?V2A!XC0S|SUMm@1dZxa|8HKKzMJaN{51cxyx+!j9|{)~Le$dMo-E zbzwbiz9pE!+JjE)eU6ov{a?p}gU$uL&G;LtgMMv0t`8ho`Y$0R^zWC)du08Sql{y6 zP+Mxl@)PNhvYm4)xDNOy>=}HqCpu9Z_Y|&|p5xq)mHoRl`idPz*pAoM_89l$ybWLc zpcAhh(DVpxw*GSCR5L8cx*v15dptbc8Y&uE*UonR{p5i?fv|H{@+jpu+heGPn*g9dWrUq^22 z*V&+Z+^wbOc6;qj^vE9Ln;mrG?FSC5H~iLdp25e=^}hRkJHGirCvpSczX|;yKGNQY zZ*{so@u2_p-~Qd~S+u`{3I9Pr82^sQ$?*3{uJ#xGeV1WB zZ}!(=e}VlI?Js5jZP;JC{rBR34Sr|6cC#8^^X2?pOJCcvZr%^>>v+FoKcbP<-hB+N z&hFDMzx?v~x8Htq_yd1N{QB#!f1Z!-A9wp1uWar~d%_ zQqd4&o9(%dyBzRJ-$!G;3fx1E+3%Px#1ZP1_K>z@;j|==^1poj56;Mo6MF0Q*lJ1y&%z|mLX&XlbNq0;D002oVBm4jW z00(qZPE-H?|NsC002)gJMgRZ+32;bRa{vGi!vFvd!vV){sAK>D1X)Q$K~#8N?bp$A z+aM5y;iPW!{*PRC_eg+*6vumZV`lg-A|cSsXNueOW8yyNY{~Om^8A)Oza`Ia$@5$C z{FXewCC_ha`JXvk^8A)Oza`Ia$@5$C{FXewCC_ik^IP)#g5?if1B#VD9&z*~A2+SM zz~__;JdVEPgA5)edKykg|gHerHT&}li_F~uuFK7vnoTJ}3k5Q~-9TYJtdY0m?G)r~pl zr^-W2(h86R+lM(~5%Te-vr9TH0rWI^3Dcw!<(Ora^$nFUPl_&w@>H3?3Q}x2oL%-1 z3uw{hyIltDjZPB_J1xziegbA0a*O@%f7m(iN0L6_755G829hnHMV13O3`b%-ECOyZk-khxSM1N7Q0K{bK-xD z)@jkI4tIlWC82?KzuIY7^c_Z)HL;QS=K z`Fa#NFh7X!`yxXwklJ&f1Ft%wpO$`flfC(RoIP(F!jBKj7%#tE&N<)LY&YeiZ#tr% zmT?un)4g%z-_xzSR_|OT?K!H8_0CnUT)_3t7yBF9k8ZLz9dYEl)`ridD?O1vW|jf?OD;DcSg`?CqChe?w1QPTQ-m$Jz7iE>_4Roq9d?X*ss7I8>hL zj3eSVbjWWP?3D-l+!f`VD{Tl@BJP^(Enlo}sQr94d(9VT&$Z$K?7p%JZ@41LZSPGt zYMaJlZ&dj=+g|4E(^2Be1va)5$tXyE-g}v$Mm{Y{u6J$Q3@fI5lkGy7rR{-T8S&(s zaJ#l}U7+#oEO|9c5bmQkmYpPrrj<5-$sD*GI#Uj3sUJ!5Wb5tZ5aQCw%RrY|?y|ho z$wg$kOSzhHWyF%3N-j2%l&Kx>vA`8i4$(l~j&N@mS4_FuFXXr_=}3M!Y^U+lU4+;5hgTQ%BMnN!Hkyt|D#iM(@{%BYj~v#%B-KUTa|?r{HY%8}PU1=oI8 z>gT_YuOzvdUG7FM@I1NOUF8bTl)D4f;1kLLpHIHQr<3pS+2j>InY@9|C2!$#$y@kb i@)lm?69u#M_4OZ#A^v;!G(p?|0000 = props => }); }, [ confirmingProduct ]); + const clearProductBubbles = useCallback(() => + { + setProductBubbles([]); + }, []); + const clearInfoStandEvent = useCallback(() => { setInfoStandEvent(null); @@ -67,6 +72,12 @@ export const AvatarInfoWidgetView: FC = props => setName(null); }, []); + const updateConfirmingProduct = useCallback((product: UseProductItem) => + { + setConfirmingProduct(product); + setProductBubbles([]); + }, []); + const onRoomWidgetRoomEngineUpdateEvent = useCallback((event: RoomWidgetRoomEngineUpdateEvent) => { switch(event.type) @@ -131,20 +142,20 @@ export const AvatarInfoWidgetView: FC = props => { if(infoStandEvent instanceof RoomWidgetUpdateInfostandFurniEvent) { - if(infoStandEvent.id === event.id) setInfoStandEvent(null); + if(infoStandEvent.id === event.id) clearInfoStandEvent(); } else if((infoStandEvent instanceof RoomWidgetUpdateInfostandUserEvent) || (infoStandEvent instanceof RoomWidgetUpdateInfostandRentableBotEvent)) { - if(infoStandEvent.roomIndex === event.id) setInfoStandEvent(null); + if(infoStandEvent.roomIndex === event.id) clearInfoStandEvent(); } else if(infoStandEvent instanceof RoomWidgetUpdateInfostandPetEvent) { - if(infoStandEvent.roomIndex === event.id) setInfoStandEvent(null); + if(infoStandEvent.roomIndex === event.id) clearInfoStandEvent(); } } - }, [ name, infoStandEvent, nameBubbles, productBubbles, removeNameBubble ]); + }, [ name, infoStandEvent, nameBubbles, productBubbles, removeNameBubble, clearInfoStandEvent ]); CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_REMOVED, eventDispatcher, onRoomObjectRemoved); CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomObjectRemoved); @@ -179,9 +190,9 @@ export const AvatarInfoWidgetView: FC = props => const onObjectDeselected = useCallback((event: RoomWidgetRoomObjectUpdateEvent) => { - if(infoStandEvent) setInfoStandEvent(null); + if(infoStandEvent) clearInfoStandEvent(); if(productBubbles.length) setProductBubbles([]); - }, [ infoStandEvent, productBubbles ]); + }, [ infoStandEvent, productBubbles, clearInfoStandEvent ]); CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, eventDispatcher, onObjectDeselected); @@ -190,7 +201,8 @@ export const AvatarInfoWidgetView: FC = props => if(event.category !== RoomObjectCategory.UNIT) return; setName(event); - }, []); + clearProductBubbles(); + }, [ clearProductBubbles ]); CreateEventDispatcherHook(RoomWidgetObjectNameEvent.TYPE, eventDispatcher, onRoomWidgetObjectNameEvent); @@ -198,9 +210,11 @@ export const AvatarInfoWidgetView: FC = props => { if(name) setName(null); - if(event.type === RoomWidgetUpdateInfostandFurniEvent.FURNI) setInfoStandEvent(null); + if(event.type === RoomWidgetUpdateInfostandFurniEvent.FURNI) clearInfoStandEvent(); else setInfoStandEvent(event); - }, [ name ]); + + clearProductBubbles(); + }, [ name, clearInfoStandEvent, clearProductBubbles ]); CreateEventDispatcherHook(RoomWidgetUpdateInfostandFurniEvent.FURNI, eventDispatcher, onRoomWidgetUpdateInfostandEvent); CreateEventDispatcherHook(RoomWidgetUpdateInfostandUserEvent.OWN_USER, eventDispatcher, onRoomWidgetUpdateInfostandEvent); @@ -225,6 +239,7 @@ export const AvatarInfoWidgetView: FC = props => const onRoomWidgetUseProductBubbleEvent = useCallback((event: RoomWidgetUseProductBubbleEvent) => { + setConfirmingProduct(null); setProductBubbles(prevValue => { const newBubbles = [ ...prevValue ]; @@ -342,7 +357,7 @@ export const AvatarInfoWidgetView: FC = props => }) } { (productBubbles.length > 0) && productBubbles.map((item, index) => { - return removeProductBubble(index) } />; + return removeProductBubble(index) } />; }) } { rentableBotChatEvent && } { confirmingProduct && setConfirmingProduct(null) } /> } diff --git a/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx index 32ea2d7d..8a7b2bf9 100644 --- a/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx +++ b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx @@ -1,9 +1,10 @@ -import { IFurnitureData, RoomObjectCategory, RoomUserData } from 'nitro-renderer'; -import { FC, useCallback, useEffect, useState } from 'react'; -import { GetFurnitureDataForRoomObject } from '../../../../../../api'; +import { IFurnitureData, PetCustomPart, PetFigureData, RoomObjectCategory, RoomObjectVariable, RoomUserData } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { GetFurnitureDataForRoomObject, GetRoomEngine } from '../../../../../../api'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../../layout'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { FurniCategory } from '../../../../../inventory/common/FurniCategory'; +import { PetImageView } from '../../../../../shared/pet-image/PetImageView'; import { useRoomContext } from '../../../../context/RoomContext'; import { RoomWidgetUseProductMessage } from '../../../../messages'; import { AvatarInfoUseProductConfirmViewProps } from './AvatarInfoUseProductConfirmView.types'; @@ -28,7 +29,145 @@ export const AvatarInfoUseProductConfirmView: FC { widgetHandler.processWidgetMessage(new RoomWidgetUseProductMessage(RoomWidgetUseProductMessage.PET_PRODUCT, item.requestRoomObjectId, petData.webID)); - }, [ widgetHandler, item, petData ]); + + close(); + }, [ widgetHandler, item, petData, close ]); + + const getPetImage = useMemo(() => + { + if(!petData || !furniData) return null; + + const petFigureData = new PetFigureData(petData.figure); + const customParts = furniData.customParams.split(' '); + const petIndex = parseInt(customParts[0]); + + switch(furniData.specialType) + { + case FurniCategory._Str_7696: { + if(customParts.length < 2) return null; + + const currentPalette = GetRoomEngine().getPetColorResult(petIndex, petFigureData.paletteId); + const possiblePalettes = GetRoomEngine().getPetColorResultsForTag(petIndex, customParts[1]); + + let paletteId = -1; + + for(const result of possiblePalettes) + { + if(result.breed === currentPalette.breed) + { + paletteId = parseInt(result.id); + + break; + } + } + + return + } + case FurniCategory._Str_7297: { + if(customParts.length < 4) return null; + + const newCustomParts: PetCustomPart[] = []; + + const _local_6 = customParts[1].split(',').map(piece => parseInt(piece)); + const _local_7 = customParts[2].split(",").map(piece => parseInt(piece)); + const _local_8 = customParts[3].split(",").map(piece => parseInt(piece)); + + let _local_10 = 0; + + while(_local_10 < _local_6.length) + { + const _local_13 = _local_6[_local_10]; + const _local_15 = petFigureData.getCustomPart(_local_13); + + let _local_12 = _local_8[_local_10]; + + if (_local_15 != null) _local_12 = _local_15.paletteId; + + newCustomParts.push(new PetCustomPart(_local_13, _local_7[_local_10], _local_12)); + + _local_10++; + } + + return ; + } + case FurniCategory._Str_7954: { + if(customParts.length < 3) return null; + + const newCustomParts: PetCustomPart[] = []; + + const _local_6 = customParts[1].split(",").map(piece => parseInt(piece)); + const _local_8 = customParts[2].split(",").map(piece => parseInt(piece)); + + let _local_10 = 0; + + while(_local_10 < _local_6.length) + { + const _local_13 = _local_6[_local_10]; + const _local_15 = petFigureData.getCustomPart(_local_13); + + let _local_14 = -1; + + if(_local_15 != null) _local_14 = _local_15.partId; + + newCustomParts.push(new PetCustomPart(_local_6[_local_10], _local_14, _local_8[_local_10])); + + _local_10++; + } + + return ; + } + case FurniCategory._Str_6096: { + if(customParts.length < 4) return null; + + const newCustomParts: PetCustomPart[] = []; + + const _local_6 = customParts[1].split(',').map(piece => parseInt(piece)); + const _local_7 = customParts[2].split(",").map(piece => parseInt(piece)); + const _local_8 = customParts[3].split(",").map(piece => parseInt(piece)); + + let _local_10 = 0; + + while(_local_10 < _local_6.length) + { + newCustomParts.push(new PetCustomPart(_local_6[_local_10], _local_7[_local_10], _local_8[_local_10])); + + _local_10++; + } + + for(const _local_21 of petFigureData.customParts) + { + if(_local_6.indexOf(_local_21.layerId) === -1) + { + newCustomParts.push(_local_21); + } + } + + return ; + } + case FurniCategory._Str_8726: + case FurniCategory._Str_6915: + case FurniCategory._Str_9449: { + let posture = 'rip'; + + const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, petData.roomIndex, RoomObjectCategory.UNIT); + + if(roomObject) + { + posture = roomObject.model.getValue(RoomObjectVariable.FIGURE_POSTURE); + + if(posture === 'rip') + { + const level = petData.petLevel; + + if(level < 7) posture = `grw${ level }`; + else posture = 'std'; + } + } + + return ; + } + } + }, [ petData, furniData, roomSession ]); useEffect(() => { @@ -72,11 +211,60 @@ export const AvatarInfoUseProductConfirmView: FC + - +
+
+ { getPetImage } +
+
+
+ { (mode === _Str_11906) && + <> +
{ LocalizeText('useproduct.widget.text.shampoo', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.shampoo') }
+ } + { (mode === _Str_11214) && + <> +
{ LocalizeText('useproduct.widget.text.custompart', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.custompart') }
+ } + { (mode === _Str_11733) && + <> +
{ LocalizeText('useproduct.widget.text.custompartshampoo', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.custompartshampoo') }
+ } + { (mode === _Str_11369) && + <> +
{ LocalizeText('useproduct.widget.text.saddle', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.saddle') }
+ } + { (mode === _Str_8759) && + <> +
{ LocalizeText('useproduct.widget.text.revive_monsterplant', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.revive_monsterplant') }
+ } + { (mode === _Str_8432) && + <> +
{ LocalizeText('useproduct.widget.text.rebreed_monsterplant', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.rebreed_monsterplant') }
+ } + { (mode === _Str_9653) && + <> +
{ LocalizeText('useproduct.widget.text.fertilize_monsterplant', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.fertilize_monsterplant') }
+ } +
+
+ + +
+
+
) diff --git a/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx index f2e66720..aca532b0 100644 --- a/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx +++ b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx @@ -20,7 +20,7 @@ const _Str_14611: number = 7; export const AvatarInfoUseProductView: FC = props => { - const { item = null, setConfirmingProduct = null, close = null } = props; + const { item = null, updateConfirmingProduct = null, close = null } = props; const [ mode, setMode ] = useState(0); const { roomSession = null } = useRoomContext(); @@ -64,30 +64,23 @@ export const AvatarInfoUseProductView: FC = props const processAction = useCallback((name: string) => { - let hideMenu = true; - - if(name) + if(!name) return; + + switch(name) { - switch(name) - { - case 'use_product': - case 'use_product_shampoo': - case 'use_product_custom_part': - case 'use_product_custom_part_shampoo': - case 'use_product_saddle': - case 'replace_product_saddle': - case 'revive_monsterplant': - case 'rebreed_monsterplant': - case 'fertilize_monsterplant': - setConfirmingProduct(item); - break; - default: - break; - } + case 'use_product': + case 'use_product_shampoo': + case 'use_product_custom_part': + case 'use_product_custom_part_shampoo': + case 'use_product_saddle': + case 'replace_product_saddle': + case 'revive_monsterplant': + case 'rebreed_monsterplant': + case 'fertilize_monsterplant': + updateConfirmingProduct(item); + break; } - - if(hideMenu) close(); - }, [ item, setConfirmingProduct, close ]); + }, [ item, updateConfirmingProduct ]); return ( diff --git a/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.types.ts b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.types.ts index 1407ee5e..f759da68 100644 --- a/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.types.ts +++ b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.types.ts @@ -1,9 +1,8 @@ -import { Dispatch, SetStateAction } from 'react'; import { UseProductItem } from '../../../../events'; export interface AvatarInfoUseProductViewProps { item: UseProductItem; - setConfirmingProduct: Dispatch>; + updateConfirmingProduct: (product: UseProductItem) => void; close: () => void; } From 6302587ef894a3c6d5dc42fd686945d18585993b Mon Sep 17 00:00:00 2001 From: Bill Date: Sun, 11 Jul 2021 23:27:39 -0400 Subject: [PATCH 41/72] Add rarity-level view --- src/assets/images/infostand/rarity-level.png | Bin 0 -> 273 bytes src/views/shared/Shared.scss | 3 ++- .../shared/rarity-level/RarityLevelView.scss | 12 ++++++++++++ src/views/shared/rarity-level/RarityLevelView.tsx | 13 +++++++++++++ .../shared/rarity-level/RarityLevelView.types.ts | 4 ++++ 5 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 src/assets/images/infostand/rarity-level.png create mode 100644 src/views/shared/rarity-level/RarityLevelView.scss create mode 100644 src/views/shared/rarity-level/RarityLevelView.tsx create mode 100644 src/views/shared/rarity-level/RarityLevelView.types.ts diff --git a/src/assets/images/infostand/rarity-level.png b/src/assets/images/infostand/rarity-level.png new file mode 100644 index 0000000000000000000000000000000000000000..eb1278ef84dd547fd09f65247dbf3b3b3ddf26d9 GIT binary patch literal 273 zcmeAS@N?(olHy`uVBq!ia0vp^DnKm5!3-qrzQ4@^QjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nn{1`B?5dxT!Hk=P5x_6CU4!d_R_7>rA-FjK{7zWz1JFc0V$4>Aiv=M5WsM+ zd2b|8jI+QavY3H^?=T269?xHq0u;>iba4!^@LzlRF4qACj<&>T?f3uto = props => +{ + const { level = 0 } = props; + + return ( +
+
{ level }
+
+ ); +} diff --git a/src/views/shared/rarity-level/RarityLevelView.types.ts b/src/views/shared/rarity-level/RarityLevelView.types.ts new file mode 100644 index 00000000..e0bc2d80 --- /dev/null +++ b/src/views/shared/rarity-level/RarityLevelView.types.ts @@ -0,0 +1,4 @@ +export interface RarityLevelViewProps +{ + level: number; +} From fe998d16398235d1e8b2c39bca5109da60a5abc6 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 12 Jul 2021 03:59:40 -0400 Subject: [PATCH 42/72] Lots of widget updates --- .../monsterplant-preview.png | Bin src/assets/styles/utils.scss | 4 + src/views/room/RoomView.tsx | 3 +- .../FurnitureContextMenuWidgetHandler.ts | 40 +++++ .../handlers/RoomWidgetAvatarInfoHandler.ts | 3 +- src/views/room/handlers/index.ts | 1 + src/views/room/widgets/RoomWidgets.types.ts | 3 - .../avatar-info/AvatarInfoWidgetView.scss | 20 +++ .../avatar-info/AvatarInfoWidgetView.tsx | 3 +- .../avatar-info/AvatarInfoWidgetView.types.ts | 4 - .../avatar/AvatarInfoWidgetAvatarView.tsx | 2 +- .../views/name/AvatarInfoWidgetNameView.tsx | 2 +- .../AvatarInfoWidgetOwnAvatarView.tsx | 2 +- .../own-pet/AvatarInfoWidgetOwnPetView.tsx | 4 +- .../AvatarInfoWidgetRentableBotView.tsx | 4 +- .../AvatarInfoUseProductConfirmView.tsx | 49 ++++--- .../use-product/AvatarInfoUseProductView.tsx | 4 +- .../room/widgets/camera/CameraWidgetView.tsx | 3 +- .../widgets/camera/CameraWidgetView.types.ts | 4 - .../room/widgets/chat-input/ChatInputView.tsx | 3 +- .../widgets/chat-input/ChatInputView.types.ts | 6 - .../room/widgets/chat/ChatWidgetView.tsx | 3 +- .../room/widgets/chat/ChatWidgetView.types.ts | 6 - .../widgets/context-menu/ContextMenuView.tsx | 83 ++++++++--- .../context-menu/ContextMenuView.types.ts | 1 + .../furniture/FurnitureWidget.types.ts | 4 - .../widgets/furniture/FurnitureWidgets.scss | 2 +- .../furniture/FurnitureWidgetsView.tsx | 7 +- .../furniture/FurnitureWidgetsView.types.ts | 6 - .../context-menu/FurnitureContextMenuView.tsx | 137 +++++++++++++----- .../MonsterPlantSeedConfirmView.tsx | 83 +++++++++++ .../MonsterPlantSeedConfirmView.types.ts | 5 + .../PurchasableClothingConfirmView.tsx | 102 +++++++++++++ .../PurchasableClothingConfirmView.types.ts | 5 + .../furniture/dimmer/FurnitureDimmerView.tsx | 3 +- .../dimmer/FurnitureDimmerView.types.ts | 4 - .../FurnitureEngravingLockView.types.ts | 4 - .../FurnitureExchangeCreditView.tsx | 3 +- .../FurnitureExchangeCreditView.types.ts | 4 - .../FriendFurniLockData.ts} | 0 .../FurnitureFriendFurniView.scss} | 0 .../FurnitureFriendFurniView.tsx} | 5 +- .../high-score/FurnitureHighScoreView.tsx | 3 +- .../FurnitureHighScoreView.types.ts | 6 - .../FurnitureManipulationMenuView.tsx | 3 +- .../FurnitureManipulationMenuView.types.ts | 6 - .../mannequin/FurnitureMannequinView.tsx | 26 ++-- .../MannequinViewMode.ts} | 7 +- .../present/FurniturePresentView.tsx | 3 +- .../present/FurniturePresentView.types.ts | 6 - .../stickie/FurnitureStickieView.tsx | 3 +- .../stickie/FurnitureStickieView.types.ts | 6 - .../furniture/trophy/FurnitureTrophyView.tsx | 3 +- .../trophy/FurnitureTrophyView.types.ts | 4 - .../views/furni/InfoStandWidgetFurniView.tsx | 5 + 55 files changed, 499 insertions(+), 213 deletions(-) rename src/assets/images/room-widgets/{avatar-info => furni-context-menu}/monsterplant-preview.png (100%) create mode 100644 src/views/room/handlers/FurnitureContextMenuWidgetHandler.ts delete mode 100644 src/views/room/widgets/avatar-info/AvatarInfoWidgetView.types.ts delete mode 100644 src/views/room/widgets/camera/CameraWidgetView.types.ts delete mode 100644 src/views/room/widgets/chat-input/ChatInputView.types.ts delete mode 100644 src/views/room/widgets/chat/ChatWidgetView.types.ts delete mode 100644 src/views/room/widgets/furniture/FurnitureWidget.types.ts delete mode 100644 src/views/room/widgets/furniture/FurnitureWidgetsView.types.ts create mode 100644 src/views/room/widgets/furniture/context-menu/views/monsterplant-seed/MonsterPlantSeedConfirmView.tsx create mode 100644 src/views/room/widgets/furniture/context-menu/views/monsterplant-seed/MonsterPlantSeedConfirmView.types.ts create mode 100644 src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx create mode 100644 src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.types.ts delete mode 100644 src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.types.ts delete mode 100644 src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.types.ts delete mode 100644 src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.types.ts rename src/views/room/widgets/furniture/{engraving-lock/FurnitureEngravingLockData.ts => friend-furni/FriendFurniLockData.ts} (100%) rename src/views/room/widgets/furniture/{engraving-lock/FurnitureEngravingLockView.scss => friend-furni/FurnitureFriendFurniView.scss} (100%) rename src/views/room/widgets/furniture/{engraving-lock/FurnitureEngravingLockView.tsx => friend-furni/FurnitureFriendFurniView.tsx} (96%) delete mode 100644 src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.types.ts delete mode 100644 src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.types.ts rename src/views/room/widgets/furniture/mannequin/{FurnitureMannequinView.types.tsx => common/MannequinViewMode.ts} (61%) delete mode 100644 src/views/room/widgets/furniture/present/FurniturePresentView.types.ts delete mode 100644 src/views/room/widgets/furniture/stickie/FurnitureStickieView.types.ts delete mode 100644 src/views/room/widgets/furniture/trophy/FurnitureTrophyView.types.ts diff --git a/src/assets/images/room-widgets/avatar-info/monsterplant-preview.png b/src/assets/images/room-widgets/furni-context-menu/monsterplant-preview.png similarity index 100% rename from src/assets/images/room-widgets/avatar-info/monsterplant-preview.png rename to src/assets/images/room-widgets/furni-context-menu/monsterplant-preview.png diff --git a/src/assets/styles/utils.scss b/src/assets/styles/utils.scss index c2a43bac..51b4bcab 100644 --- a/src/assets/styles/utils.scss +++ b/src/assets/styles/utils.scss @@ -62,3 +62,7 @@ ul { .filter-none { filter: unset !important; } + +.w-unset { + width: unset; +} diff --git a/src/views/room/RoomView.tsx b/src/views/room/RoomView.tsx index fe7d0145..2bc5e352 100644 --- a/src/views/room/RoomView.tsx +++ b/src/views/room/RoomView.tsx @@ -9,7 +9,7 @@ import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine'; import { useRoomEngineEvent } from '../../hooks/events'; import { RoomContextProvider } from './context/RoomContext'; import { RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent } from './events'; -import { IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers'; +import { FurnitureContextMenuWidgetHandler, IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers'; import { RoomViewProps } from './RoomView.types'; import { RoomWidgetsView } from './widgets/RoomWidgetsView'; @@ -37,6 +37,7 @@ export const RoomView: FC = props => widgetHandlerManager.registerHandler(new RoomWidgetInfostandHandler()); widgetHandlerManager.registerHandler(new RoomWidgetChatInputHandler()); widgetHandlerManager.registerHandler(new RoomWidgetChatHandler()); + widgetHandlerManager.registerHandler(new FurnitureContextMenuWidgetHandler()); setWidgetHandler(widgetHandlerManager); diff --git a/src/views/room/handlers/FurnitureContextMenuWidgetHandler.ts b/src/views/room/handlers/FurnitureContextMenuWidgetHandler.ts new file mode 100644 index 00000000..11080342 --- /dev/null +++ b/src/views/room/handlers/FurnitureContextMenuWidgetHandler.ts @@ -0,0 +1,40 @@ +import { NitroEvent, RoomEngineTriggerWidgetEvent } from 'nitro-renderer'; +import { RoomWidgetUpdateEvent } from '../events'; +import { RoomWidgetMessage, RoomWidgetUseProductMessage } from '../messages'; +import { RoomWidgetHandler } from './RoomWidgetHandler'; + +export class FurnitureContextMenuWidgetHandler extends RoomWidgetHandler +{ + public processEvent(event: NitroEvent): void + { + } + + public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent + { + switch(message.type) + { + case RoomWidgetUseProductMessage.MONSTERPLANT_SEED: + const productMessage = (message as RoomWidgetUseProductMessage); + + this.container.roomSession.useMultistateItem(productMessage.objectId); + break; + } + + return null; + } + + public get eventTypes(): string[] + { + return [ + RoomEngineTriggerWidgetEvent.OPEN_FURNI_CONTEXT_MENU, + RoomEngineTriggerWidgetEvent.CLOSE_FURNI_CONTEXT_MENU + ]; + } + + public get messageTypes(): string[] + { + return [ + RoomWidgetUseProductMessage.MONSTERPLANT_SEED + ]; + } +} diff --git a/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts b/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts index 5b7f5538..6324a380 100644 --- a/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts +++ b/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts @@ -168,8 +168,7 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler RoomWidgetDanceMessage.DANCE, RoomWidgetAvatarExpressionMessage.AVATAR_EXPRESSION, RoomWidgetChangePostureMessage.CHANGE_POSTURE, - RoomWidgetUseProductMessage.PET_PRODUCT, - RoomWidgetUseProductMessage.MONSTERPLANT_SEED + RoomWidgetUseProductMessage.PET_PRODUCT ]; } } diff --git a/src/views/room/handlers/index.ts b/src/views/room/handlers/index.ts index 64596a0f..5c6464e2 100644 --- a/src/views/room/handlers/index.ts +++ b/src/views/room/handlers/index.ts @@ -1,3 +1,4 @@ +export * from './FurnitureContextMenuWidgetHandler'; export * from './IRoomWidgetHandler'; export * from './IRoomWidgetHandlerManager'; export * from './RoomWidgetAvatarInfoHandler'; diff --git a/src/views/room/widgets/RoomWidgets.types.ts b/src/views/room/widgets/RoomWidgets.types.ts index 199fc363..ea28fdd6 100644 --- a/src/views/room/widgets/RoomWidgets.types.ts +++ b/src/views/room/widgets/RoomWidgets.types.ts @@ -1,5 +1,2 @@ export interface RoomWidgetViewProps {} - -export interface RoomWidgetProps -{} diff --git a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.scss b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.scss index dffb096d..df009b29 100644 --- a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.scss +++ b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.scss @@ -1,6 +1,10 @@ .nitro-use-product-confirmation { + width: 350px; .product-preview { + display: flex; + justify-content: center; + align-items: center; width: 122px; height: 130px; background: url('../../../../assets/images/room-widgets/avatar-info/preview-background.png') no-repeat center; @@ -9,5 +13,21 @@ width: 122px; height: 130px; } + + .monsterplant-image { + width: 122px; + height: 130px; + background: url('../../../../assets/images/room-widgets/furni-context-menu/monsterplant-preview.png') no-repeat center; + } + } + + .mannequin-preview { + display: flex; + justify-content: center; + align-items: center; + width: 83px; + height: 130px; + background-image: url('../../../../assets/images/room-widgets/mannequin-widget/mannequin-spritesheet.png'); + overflow: hidden; } } diff --git a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx index 57ef9fdd..76af1582 100644 --- a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx +++ b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.tsx @@ -7,7 +7,6 @@ import { CreateEventDispatcherHook } from '../../../../hooks/events/event-dispat import { useRoomContext } from '../../context/RoomContext'; import { RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRentableBotChatEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../../events'; import { RoomWidgetRoomObjectMessage } from '../../messages'; -import { AvatarInfoWidgetViewProps } from './AvatarInfoWidgetView.types'; import { AvatarInfoWidgetAvatarView } from './views/avatar/AvatarInfoWidgetAvatarView'; import { AvatarInfoWidgetDecorateView } from './views/decorate/AvatarInfoWidgetDecorateView'; import { AvatarInfoWidgetNameView } from './views/name/AvatarInfoWidgetNameView'; @@ -19,7 +18,7 @@ import { AvatarInfoWidgetRentableBotView } from './views/rentable-bot/AvatarInfo import { AvatarInfoUseProductConfirmView } from './views/use-product-confirm/AvatarInfoUseProductConfirmView'; import { AvatarInfoUseProductView } from './views/use-product/AvatarInfoUseProductView'; -export const AvatarInfoWidgetView: FC = props => +export const AvatarInfoWidgetView: FC<{}> = props => { const { roomSession = null, eventDispatcher = null, widgetHandler = null } = useRoomContext(); const [ name, setName ] = useState(null); diff --git a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.types.ts b/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.types.ts deleted file mode 100644 index 23622184..00000000 --- a/src/views/room/widgets/avatar-info/AvatarInfoWidgetView.types.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { RoomWidgetProps } from '../RoomWidgets.types'; - -export interface AvatarInfoWidgetViewProps extends RoomWidgetProps -{} diff --git a/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.tsx b/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.tsx index 9f6d5415..a46ff0f4 100644 --- a/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.tsx +++ b/src/views/room/widgets/avatar-info/views/avatar/AvatarInfoWidgetAvatarView.tsx @@ -194,7 +194,7 @@ export const AvatarInfoWidgetAvatarView: FC = p }, []); return ( - + { userData.name } diff --git a/src/views/room/widgets/avatar-info/views/name/AvatarInfoWidgetNameView.tsx b/src/views/room/widgets/avatar-info/views/name/AvatarInfoWidgetNameView.tsx index 786741dd..d30da446 100644 --- a/src/views/room/widgets/avatar-info/views/name/AvatarInfoWidgetNameView.tsx +++ b/src/views/room/widgets/avatar-info/views/name/AvatarInfoWidgetNameView.tsx @@ -13,7 +13,7 @@ export const AvatarInfoWidgetNameView: FC = props }, [ nameData ]); return ( - +
{ nameData.name }
diff --git a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx index ebbf725e..58e851ef 100644 --- a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx +++ b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx @@ -105,7 +105,7 @@ export const AvatarInfoWidgetOwnAvatarView: FC + { userData.name } diff --git a/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx b/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx index a5b3a2ff..03ebc74a 100644 --- a/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx +++ b/src/views/room/widgets/avatar-info/views/own-pet/AvatarInfoWidgetOwnPetView.tsx @@ -1,4 +1,4 @@ -import { PetType, RoomObjectCategory, RoomObjectVariable } from 'nitro-renderer'; +import { PetType, RoomObjectCategory, RoomObjectType, RoomObjectVariable } from 'nitro-renderer'; import { FC, useCallback, useEffect, useMemo, useState } from 'react'; import { GetOwnRoomObject } from '../../../../../../api'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; @@ -139,7 +139,7 @@ export const AvatarInfoWidgetOwnPetView: FC = p }, []); return ( - + { petData.name } diff --git a/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx index ab5522ba..6f91a26b 100644 --- a/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx +++ b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx @@ -1,4 +1,4 @@ -import { BotCommandConfigurationEvent, BotRemoveComposer, BotSkillSaveComposer, Nitro, RequestBotCommandConfigurationComposer, RoomObjectCategory } from 'nitro-renderer'; +import { BotCommandConfigurationEvent, BotRemoveComposer, BotSkillSaveComposer, Nitro, RequestBotCommandConfigurationComposer, RoomObjectCategory, RoomObjectType } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import { CreateMessageHook, SendMessageHook } from '../../../../../../hooks/messages'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; @@ -136,7 +136,7 @@ export const AvatarInfoWidgetRentableBotView: FC + { rentableBotData.name } diff --git a/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx index 8a7b2bf9..4d781a25 100644 --- a/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx +++ b/src/views/room/widgets/avatar-info/views/use-product-confirm/AvatarInfoUseProductConfirmView.tsx @@ -26,6 +26,13 @@ export const AvatarInfoUseProductConfirmView: FC(null); const { roomSession = null, widgetHandler = null } = useRoomContext(); + const selectRoomObject = useCallback(() => + { + if(!petData) return; + + GetRoomEngine().selectRoomObject(roomSession.roomId, petData.roomIndex, RoomObjectCategory.UNIT); + }, [ roomSession, petData ]); + const useProduct = useCallback(() => { widgetHandler.processWidgetMessage(new RoomWidgetUseProductMessage(RoomWidgetUseProductMessage.PET_PRODUCT, item.requestRoomObjectId, petData.webID)); @@ -217,49 +224,51 @@ export const AvatarInfoUseProductConfirmView: FC -
-
- { getPetImage } +
+
+
+ { getPetImage } +
-
-
+
+
{ (mode === _Str_11906) && <> -
{ LocalizeText('useproduct.widget.text.shampoo', [ 'productName' ], [ furniData.name ] ) }
-
{ LocalizeText('useproduct.widget.info.shampoo') }
+
{ LocalizeText('useproduct.widget.text.shampoo', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.shampoo') }
} { (mode === _Str_11214) && <> -
{ LocalizeText('useproduct.widget.text.custompart', [ 'productName' ], [ furniData.name ] ) }
-
{ LocalizeText('useproduct.widget.info.custompart') }
+
{ LocalizeText('useproduct.widget.text.custompart', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.custompart') }
} { (mode === _Str_11733) && <> -
{ LocalizeText('useproduct.widget.text.custompartshampoo', [ 'productName' ], [ furniData.name ] ) }
-
{ LocalizeText('useproduct.widget.info.custompartshampoo') }
+
{ LocalizeText('useproduct.widget.text.custompartshampoo', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.custompartshampoo') }
} { (mode === _Str_11369) && <> -
{ LocalizeText('useproduct.widget.text.saddle', [ 'productName' ], [ furniData.name ] ) }
-
{ LocalizeText('useproduct.widget.info.saddle') }
+
{ LocalizeText('useproduct.widget.text.saddle', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.saddle') }
} { (mode === _Str_8759) && <> -
{ LocalizeText('useproduct.widget.text.revive_monsterplant', [ 'productName' ], [ furniData.name ] ) }
-
{ LocalizeText('useproduct.widget.info.revive_monsterplant') }
+
{ LocalizeText('useproduct.widget.text.revive_monsterplant', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.revive_monsterplant') }
} { (mode === _Str_8432) && <> -
{ LocalizeText('useproduct.widget.text.rebreed_monsterplant', [ 'productName' ], [ furniData.name ] ) }
-
{ LocalizeText('useproduct.widget.info.rebreed_monsterplant') }
+
{ LocalizeText('useproduct.widget.text.rebreed_monsterplant', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.rebreed_monsterplant') }
} { (mode === _Str_9653) && <> -
{ LocalizeText('useproduct.widget.text.fertilize_monsterplant', [ 'productName' ], [ furniData.name ] ) }
-
{ LocalizeText('useproduct.widget.info.fertilize_monsterplant') }
+
{ LocalizeText('useproduct.widget.text.fertilize_monsterplant', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.fertilize_monsterplant') }
}
-
+
diff --git a/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx index aca532b0..1162b43e 100644 --- a/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx +++ b/src/views/room/widgets/avatar-info/views/use-product/AvatarInfoUseProductView.tsx @@ -1,4 +1,4 @@ -import { RoomObjectCategory } from 'nitro-renderer'; +import { RoomObjectCategory, RoomObjectType } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import { GetFurnitureDataForRoomObject } from '../../../../../../api'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; @@ -83,7 +83,7 @@ export const AvatarInfoUseProductView: FC = props }, [ item, updateConfirmingProduct ]); return ( - + { item.name } diff --git a/src/views/room/widgets/camera/CameraWidgetView.tsx b/src/views/room/widgets/camera/CameraWidgetView.tsx index 23d083a1..5b57cdcf 100644 --- a/src/views/room/widgets/camera/CameraWidgetView.tsx +++ b/src/views/room/widgets/camera/CameraWidgetView.tsx @@ -7,13 +7,12 @@ import { RoomWidgetCameraEvent } from '../../../../events/room-widgets/camera/Ro import { useCameraEvent } from '../../../../hooks/events/nitro/camera/camera-event'; import { useUiEvent } from '../../../../hooks/events/ui/ui-event'; import { CreateMessageHook, SendMessageHook } from '../../../../hooks/messages/message-event'; -import { CameraWidgetViewProps } from './CameraWidgetView.types'; import { CameraWidgetContextProvider } from './context/CameraWidgetContext'; import { CameraWidgetCaptureView } from './views/capture/CameraWidgetCaptureView'; import { CameraWidgetCheckoutView } from './views/checkout/CameraWidgetCheckoutView'; import { CameraWidgetEditorView } from './views/editor/CameraWidgetEditorView'; -export const CameraWidgetView: FC = props => +export const CameraWidgetView: FC<{}> = props => { const [ effectsReady, setEffectsReady ] = useState(false); diff --git a/src/views/room/widgets/camera/CameraWidgetView.types.ts b/src/views/room/widgets/camera/CameraWidgetView.types.ts deleted file mode 100644 index dc1096c2..00000000 --- a/src/views/room/widgets/camera/CameraWidgetView.types.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { RoomWidgetProps } from '../RoomWidgets.types'; - -export interface CameraWidgetViewProps extends RoomWidgetProps -{} diff --git a/src/views/room/widgets/chat-input/ChatInputView.tsx b/src/views/room/widgets/chat-input/ChatInputView.tsx index 471376ff..4fad3a92 100644 --- a/src/views/room/widgets/chat-input/ChatInputView.tsx +++ b/src/views/room/widgets/chat-input/ChatInputView.tsx @@ -6,10 +6,9 @@ import { LocalizeText } from '../../../../utils/LocalizeText'; import { useRoomContext } from '../../context/RoomContext'; import { RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateChatInputContentEvent, RoomWidgetUpdateInfostandUserEvent } from '../../events'; import { RoomWidgetChatMessage, RoomWidgetChatTypingMessage } from '../../messages'; -import { ChatInputViewProps } from './ChatInputView.types'; import { ChatInputStyleSelectorView } from './style-selector/ChatInputStyleSelectorView'; -export const ChatInputView: FC = props => +export const ChatInputView: FC<{}> = props => { const [ chatValue, setChatValue ] = useState(''); const [ selectedUsername, setSelectedUsername ] = useState(''); diff --git a/src/views/room/widgets/chat-input/ChatInputView.types.ts b/src/views/room/widgets/chat-input/ChatInputView.types.ts deleted file mode 100644 index fe19aca1..00000000 --- a/src/views/room/widgets/chat-input/ChatInputView.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { RoomWidgetProps } from '../RoomWidgets.types'; - -export interface ChatInputViewProps extends RoomWidgetProps -{ - -} diff --git a/src/views/room/widgets/chat/ChatWidgetView.tsx b/src/views/room/widgets/chat/ChatWidgetView.tsx index 1612dc5f..18c5a781 100644 --- a/src/views/room/widgets/chat/ChatWidgetView.tsx +++ b/src/views/room/widgets/chat/ChatWidgetView.tsx @@ -3,11 +3,10 @@ import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { CreateEventDispatcherHook, useRoomEngineEvent } from '../../../../hooks/events'; import { useRoomContext } from '../../context/RoomContext'; import { RoomWidgetUpdateChatEvent } from '../../events'; -import { ChatWidgetViewProps } from './ChatWidgetView.types'; import { ChatWidgetMessageView } from './message/ChatWidgetMessageView'; import { ChatBubbleMessage } from './utils/ChatBubbleMessage'; -export const ChatWidgetView: FC = props => +export const ChatWidgetView: FC<{}> = props => { const [ chatMessages, setChatMessages ] = useState([]); const { roomSession = null, eventDispatcher = null } = useRoomContext(); diff --git a/src/views/room/widgets/chat/ChatWidgetView.types.ts b/src/views/room/widgets/chat/ChatWidgetView.types.ts deleted file mode 100644 index 8f5535be..00000000 --- a/src/views/room/widgets/chat/ChatWidgetView.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { RoomWidgetProps } from '../RoomWidgets.types'; - -export interface ChatWidgetViewProps extends RoomWidgetProps -{ - -} diff --git a/src/views/room/widgets/context-menu/ContextMenuView.tsx b/src/views/room/widgets/context-menu/ContextMenuView.tsx index c99f48b4..09b568db 100644 --- a/src/views/room/widgets/context-menu/ContextMenuView.tsx +++ b/src/views/room/widgets/context-menu/ContextMenuView.tsx @@ -1,24 +1,43 @@ -import { FixedSizeStack, Nitro } from 'nitro-renderer'; +import { FixedSizeStack, Nitro, NitroPoint, NitroRectangle, RoomObjectType } from 'nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; -import { GetRoomObjectBounds, GetRoomSession, GetTicker } from '../../../../api'; +import { GetRoomEngine, GetRoomObjectBounds, GetRoomSession, GetTicker } from '../../../../api'; import { ContextMenuViewProps } from './ContextMenuView.types'; +const LOCATION_STACK_SIZE: number = 25; +const BUBBLE_DROP_SPEED: number = 3; const fadeDelay = 3000; const fadeLength = 75; const SPACE_AROUND_EDGES = 10; export const ContextMenuView: FC = props => { - const { objectId = -1, category = -1, fades = false, className = '', close = null, children = null } = props; + const { objectId = -1, category = -1, userType = -1, fades = false, className = '', close = null, children = null } = props; const [ pos, setPos ] = useState<{ x: number, y: number }>({ x: null, y: null }); - const [ stack, setStack ] = useState(null); + const [ deltaYStack, setDeltaYStack ] = useState(null); + const [ currentDeltaY, setCurrentDeltaY ] = useState(-1000000); const [ opacity, setOpacity ] = useState(1); const [ isFading, setIsFading ] = useState(false); const [ fadeTime, setFadeTime ] = useState(0); const [ frozen, setFrozen ] = useState(false); const elementRef = useRef(); - const update = useCallback((time: number) => + const getOffset = useCallback((bounds: NitroRectangle) => + { + let height = -(elementRef.current.offsetHeight); + + if((userType > -1) && ((userType === RoomObjectType.USER) || (userType === RoomObjectType.BOT) || (userType === RoomObjectType.RENTABLE_BOT))) + { + height = (height + ((bounds.height > 50) ? 15 : 0)); + } + else + { + height = (height - 14); + } + + return height; + }, [ userType ]); + + const updateFade = useCallback((time: number) => { let newFadeTime = time; let newOpacity = 1; @@ -38,37 +57,59 @@ export const ContextMenuView: FC = props => { close(); - return; + return false; } setOpacity(newOpacity); } - const bounds = GetRoomObjectBounds(GetRoomSession().roomId, objectId, category); + return true; + }, [ isFading, close ]); - if(!bounds || !elementRef.current) return; + const updatePosition = useCallback((bounds: NitroRectangle, location: NitroPoint) => + { + if(!bounds || !location || !deltaYStack) return; - let left = Math.round((bounds.left + (bounds.width / 2)) - (elementRef.current.offsetWidth / 2)); - let top = Math.round((bounds.top - elementRef.current.offsetHeight)); + const offset = getOffset(bounds); + + deltaYStack.addValue((location.y - bounds.top)); + + let maxStack = deltaYStack.getMax(); + + if(maxStack < (currentDeltaY - BUBBLE_DROP_SPEED)) maxStack = (currentDeltaY - BUBBLE_DROP_SPEED); + + const deltaY = (location.y - maxStack); + + let x = (location.x - (elementRef.current.offsetWidth / 2)); + let y = (deltaY + offset); const maxLeft = ((Nitro.instance.width - elementRef.current.offsetWidth) - SPACE_AROUND_EDGES); const maxTop = ((Nitro.instance.height - elementRef.current.offsetHeight) - SPACE_AROUND_EDGES); - if(left < SPACE_AROUND_EDGES) left = SPACE_AROUND_EDGES; - else if(left > maxLeft) left = maxLeft; + if(x < SPACE_AROUND_EDGES) x = SPACE_AROUND_EDGES; + else if(x > maxLeft) x = maxLeft; - if(top < SPACE_AROUND_EDGES) top = SPACE_AROUND_EDGES; - else if(top > maxTop) top = maxTop; + if(y < SPACE_AROUND_EDGES) y = SPACE_AROUND_EDGES; + else if(y > maxTop) y = maxTop; - setPos({ - x: left, - y: top - }); - }, [ objectId, category, isFading, close ]); + setCurrentDeltaY(maxStack); + setPos({ x, y }); + }, [ deltaYStack, currentDeltaY, getOffset ]); + + const update = useCallback((time: number) => + { + if(!elementRef.current || !updateFade(time)) return; + + const bounds = GetRoomObjectBounds(GetRoomSession().roomId, objectId, category); + const location = GetRoomEngine().getRoomObjectScreenLocation(GetRoomSession().roomId, objectId, category); + + updatePosition(bounds, location); + }, [ objectId, category, updateFade, updatePosition ]); useEffect(() => { - setStack(new FixedSizeStack(25)); + setDeltaYStack(new FixedSizeStack(LOCATION_STACK_SIZE)); + setCurrentDeltaY(-1000000); }, []); useEffect(() => @@ -101,7 +142,7 @@ export const ContextMenuView: FC = props => }, [ fades ]); return ( -
setFrozen(true) } onMouseLeave={ event => setFrozen(false) }> +
{ children }
); diff --git a/src/views/room/widgets/context-menu/ContextMenuView.types.ts b/src/views/room/widgets/context-menu/ContextMenuView.types.ts index e3650194..c1527ad9 100644 --- a/src/views/room/widgets/context-menu/ContextMenuView.types.ts +++ b/src/views/room/widgets/context-menu/ContextMenuView.types.ts @@ -2,6 +2,7 @@ export interface ContextMenuViewProps { objectId: number; category: number; + userType?: number; fades?: boolean; className?: string; close: () => void; diff --git a/src/views/room/widgets/furniture/FurnitureWidget.types.ts b/src/views/room/widgets/furniture/FurnitureWidget.types.ts deleted file mode 100644 index e147144f..00000000 --- a/src/views/room/widgets/furniture/FurnitureWidget.types.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { RoomWidgetProps } from '../RoomWidgets.types'; - -export interface FurnitureWidgetProps extends RoomWidgetProps -{} diff --git a/src/views/room/widgets/furniture/FurnitureWidgets.scss b/src/views/room/widgets/furniture/FurnitureWidgets.scss index 2bf505ba..1a56f4e1 100644 --- a/src/views/room/widgets/furniture/FurnitureWidgets.scss +++ b/src/views/room/widgets/furniture/FurnitureWidgets.scss @@ -1,6 +1,6 @@ -@import './engraving-lock/FurnitureEngravingLockView'; @import './dimmer/FurnitureDimmerView'; @import './exchange-credit/FurnitureExchangeCreditView'; +@import './friend-furni/FurnitureFriendFurniView'; @import './manipulation-menu/FurnitureManipulationMenuView'; @import './mannequin/FurnitureMannequinView'; @import './stickie/FurnitureStickieView'; diff --git a/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx b/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx index ce58b376..aac85a29 100644 --- a/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx +++ b/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx @@ -2,9 +2,8 @@ import { FC } from 'react'; import { FurnitureBackgroundColorView } from './background-color/FurnitureBackgroundColorView'; import { FurnitureContextMenuView } from './context-menu/FurnitureContextMenuView'; import { FurnitureDimmerView } from './dimmer/FurnitureDimmerView'; -import { FurnitureEngravingLockView } from './engraving-lock/FurnitureEngravingLockView'; import { FurnitureExchangeCreditView } from './exchange-credit/FurnitureExchangeCreditView'; -import { FurnitureWidgetsViewProps } from './FurnitureWidgetsView.types'; +import { FurnitureFriendFurniView } from './friend-furni/FurnitureFriendFurniView'; import { FurnitureHighScoreView } from './high-score/FurnitureHighScoreView'; import { FurnitureManipulationMenuView } from './manipulation-menu/FurnitureManipulationMenuView'; import { FurnitureMannequinView } from './mannequin/FurnitureMannequinView'; @@ -12,14 +11,14 @@ import { FurniturePresentView } from './present/FurniturePresentView'; import { FurnitureStickieView } from './stickie/FurnitureStickieView'; import { FurnitureTrophyView } from './trophy/FurnitureTrophyView'; -export const FurnitureWidgetsView: FC = props => +export const FurnitureWidgetsView: FC<{}> = props => { return (
- + diff --git a/src/views/room/widgets/furniture/FurnitureWidgetsView.types.ts b/src/views/room/widgets/furniture/FurnitureWidgetsView.types.ts deleted file mode 100644 index 618f7649..00000000 --- a/src/views/room/widgets/furniture/FurnitureWidgetsView.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { FurnitureWidgetProps } from './FurnitureWidget.types'; - -export interface FurnitureWidgetsViewProps extends FurnitureWidgetProps -{ - -} diff --git a/src/views/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx b/src/views/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx index 9409b00d..275b5d52 100644 --- a/src/views/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx +++ b/src/views/room/widgets/furniture/context-menu/FurnitureContextMenuView.tsx @@ -1,73 +1,91 @@ -import { ContextMenuEnum, IRoomObject, RoomEngineObjectEvent, RoomEngineTriggerWidgetEvent, RoomObjectCategory } from 'nitro-renderer'; +import { ContextMenuEnum, RoomEngineTriggerWidgetEvent, RoomObjectCategory } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; import { GetRoomEngine, IsOwnerOfFurniture } from '../../../../../api'; import { useRoomEngineEvent } from '../../../../../hooks/events'; import { LocalizeText } from '../../../../../utils/LocalizeText'; import { useRoomContext } from '../../../context/RoomContext'; +import { RoomWidgetFurniActionMessage } from '../../../messages'; import { ContextMenuView } from '../../context-menu/ContextMenuView'; import { ContextMenuHeaderView } from '../../context-menu/views/header/ContextMenuHeaderView'; import { ContextMenuListItemView } from '../../context-menu/views/list-item/ContextMenuListItemView'; +import { MonsterPlantSeedConfirmView } from './views/monsterplant-seed/MonsterPlantSeedConfirmView'; +import { PurchasableClothingConfirmView } from './views/purchaseable-clothing/PurchasableClothingConfirmView'; const MONSTERPLANT_SEED_CONFIRMATION: string = 'MONSTERPLANT_SEED_CONFIRMATION'; +const PURCHASABLE_CLOTHING_CONFIRMATION: string = 'PURCHASABLE_CLOTHING_CONFIRMATION'; export const FurnitureContextMenuView: FC<{}> = props => { - const { roomSession = null, eventDispatcher = null, widgetHandler = null } = useRoomContext(); - const [ roomObject, setRoomObject ] = useState(null); - const [ contextMenu, setContextMenu ] = useState(null); + const [ objectId, setObjectId ] = useState(-1); + const [ mode, setMode ] = useState(null); + const [ confirmMode, setConfirmMode ] = useState(null); + const [ confirmingObjectId, setConfirmingObjectId ] = useState(-1); + const { roomSession = null, widgetHandler = null } = useRoomContext(); const close = useCallback(() => { - setRoomObject(null); - setContextMenu(null); + setObjectId(-1); + setMode(null); + }, []); + + const closeConfirm = useCallback(() => + { + setConfirmMode(null); + setConfirmingObjectId(-1); }, []); const onRoomEngineTriggerWidgetEvent = useCallback((event: RoomEngineTriggerWidgetEvent) => { - const roomObject = GetRoomEngine().getRoomObject(roomSession.roomId, event.objectId, event.category); + const object = GetRoomEngine().getRoomObject(roomSession.roomId, event.objectId, event.category); - if(!roomObject) return; + if(!object) return; switch(event.type) { + case RoomEngineTriggerWidgetEvent.REQUEST_MONSTERPLANT_SEED_PLANT_CONFIRMATION_DIALOG: + setConfirmingObjectId(object.id); + setConfirmMode(MONSTERPLANT_SEED_CONFIRMATION); + + close(); + return; + case RoomEngineTriggerWidgetEvent.REQUEST_PURCHASABLE_CLOTHING_CONFIRMATION_DIALOG: + setConfirmingObjectId(object.id); + setConfirmMode(PURCHASABLE_CLOTHING_CONFIRMATION); + + close(); + return; case RoomEngineTriggerWidgetEvent.OPEN_FURNI_CONTEXT_MENU: + setObjectId(object.id); + switch(event.contextMenu) { case ContextMenuEnum.FRIEND_FURNITURE: + setMode(ContextMenuEnum.FRIEND_FURNITURE); return; case ContextMenuEnum.MONSTERPLANT_SEED: - if(IsOwnerOfFurniture(roomObject)) - { - setRoomObject(roomObject); - setContextMenu(ContextMenuEnum.MONSTERPLANT_SEED); - } + if(IsOwnerOfFurniture(object)) setMode(ContextMenuEnum.MONSTERPLANT_SEED); return; case ContextMenuEnum.MYSTERY_BOX: return; case ContextMenuEnum.RANDOM_TELEPORT: + setMode(ContextMenuEnum.RANDOM_TELEPORT); return; case ContextMenuEnum.PURCHASABLE_CLOTHING: + if(IsOwnerOfFurniture(object)) setMode(ContextMenuEnum.PURCHASABLE_CLOTHING); return; } return; case RoomEngineTriggerWidgetEvent.CLOSE_FURNI_CONTEXT_MENU: - close(); + if(object.id === objectId) close(); return; } - }, [ roomSession, close ]); + }, [ roomSession, objectId, close ]); useRoomEngineEvent(RoomEngineTriggerWidgetEvent.OPEN_FURNI_CONTEXT_MENU, onRoomEngineTriggerWidgetEvent); useRoomEngineEvent(RoomEngineTriggerWidgetEvent.CLOSE_FURNI_CONTEXT_MENU, onRoomEngineTriggerWidgetEvent); - - const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) => - { - if(!roomObject || (event.objectId !== roomObject.id)) return; - - close(); - }, [ roomObject, close ]); - - useRoomEngineEvent(RoomEngineObjectEvent.REMOVED, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_MONSTERPLANT_SEED_PLANT_CONFIRMATION_DIALOG, onRoomEngineTriggerWidgetEvent); + useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_PURCHASABLE_CLOTHING_CONFIRMATION_DIALOG, onRoomEngineTriggerWidgetEvent); const processAction = useCallback((name: string) => { @@ -75,26 +93,69 @@ export const FurnitureContextMenuView: FC<{}> = props => { switch(name) { + case 'use_friend_furni': + roomSession.useMultistateItem(objectId); + break; case 'use_monsterplant_seed': - setContextMenu(MONSTERPLANT_SEED_CONFIRMATION); + setConfirmMode(MONSTERPLANT_SEED_CONFIRMATION); + setConfirmingObjectId(objectId); + break; + case 'use_random_teleport': + widgetHandler.processWidgetMessage(new RoomWidgetFurniActionMessage(RoomWidgetFurniActionMessage.USE, objectId, RoomObjectCategory.FLOOR)); + break; + case 'use_purchaseable_clothing': + setConfirmMode(PURCHASABLE_CLOTHING_CONFIRMATION); + setConfirmingObjectId(objectId); break; } } - }, [ ]); - if(!roomObject || !contextMenu) return null; + close(); + }, [ roomSession, widgetHandler, objectId, close ]); return ( - - { (contextMenu === ContextMenuEnum.MONSTERPLANT_SEED) && - <> - - { LocalizeText('furni.mnstr_seed.name') } - - processAction('use_monsterplant_seed') }> - { LocalizeText('widget.monsterplant_seed.button.use') } - - } - + <> + { (confirmMode === MONSTERPLANT_SEED_CONFIRMATION) && } + { (confirmMode === PURCHASABLE_CLOTHING_CONFIRMATION) && } + { (objectId >= 0) && mode && + + { (mode === ContextMenuEnum.FRIEND_FURNITURE) && + <> + + { LocalizeText('friendfurni.context.title') } + + processAction('use_friend_furni') }> + { LocalizeText('friendfurni.context.use') } + + } + { (mode === ContextMenuEnum.MONSTERPLANT_SEED) && + <> + + { LocalizeText('furni.mnstr_seed.name') } + + processAction('use_monsterplant_seed') }> + { LocalizeText('widget.monsterplant_seed.button.use') } + + } + { (mode === ContextMenuEnum.RANDOM_TELEPORT) && + <> + + { LocalizeText('furni.random_teleport.name') } + + processAction('use_random_teleport') }> + { LocalizeText('widget.random_teleport.button.use') } + + } + { (mode === ContextMenuEnum.PURCHASABLE_CLOTHING) && + <> + + { LocalizeText('furni.generic_usable.name') } + + processAction('use_purchaseable_clothing') }> + { LocalizeText('widget.generic_usable.button.use') } + + } + } + ) } diff --git a/src/views/room/widgets/furniture/context-menu/views/monsterplant-seed/MonsterPlantSeedConfirmView.tsx b/src/views/room/widgets/furniture/context-menu/views/monsterplant-seed/MonsterPlantSeedConfirmView.tsx new file mode 100644 index 00000000..acdeb4fa --- /dev/null +++ b/src/views/room/widgets/furniture/context-menu/views/monsterplant-seed/MonsterPlantSeedConfirmView.tsx @@ -0,0 +1,83 @@ +import { IFurnitureData, RoomObjectCategory } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { GetFurnitureDataForRoomObject } from '../../../../../../../api'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../../../layout'; +import { LocalizeText } from '../../../../../../../utils/LocalizeText'; +import { FurniCategory } from '../../../../../../inventory/common/FurniCategory'; +import { useRoomContext } from '../../../../../context/RoomContext'; +import { RoomWidgetUseProductMessage } from '../../../../../messages'; +import { MonsterPlantSeedConfirmViewProps } from './MonsterPlantSeedConfirmView.types'; + +const MODE_DEFAULT: number = -1; +const MODE_MONSTERPLANT_SEED: number = 0; + +export const MonsterPlantSeedConfirmView: FC = props => +{ + const { objectId = -1, close = null } = props; + const [ furniData, setFurniData ] = useState(null); + const [ mode, setMode ] = useState(MODE_DEFAULT); + const { roomSession = null, widgetHandler = null } = useRoomContext(); + + const useProduct = useCallback(() => + { + widgetHandler.processWidgetMessage(new RoomWidgetUseProductMessage(RoomWidgetUseProductMessage.MONSTERPLANT_SEED, objectId)); + + close(); + }, [ widgetHandler, objectId, close ]); + + useEffect(() => + { + if(!roomSession || (objectId === -1)) return; + + const furniData = GetFurnitureDataForRoomObject(roomSession.roomId, objectId, RoomObjectCategory.FLOOR); + + if(!furniData) return; + + setFurniData(furniData); + + let mode = MODE_DEFAULT; + + switch(furniData.specialType) + { + case FurniCategory.MONSTERPLANT_SEED: + mode = MODE_MONSTERPLANT_SEED; + break; + } + + if(mode === MODE_DEFAULT) + { + close(); + + return; + } + + setMode(mode); + }, [ roomSession, objectId, close ]); + + if(mode === MODE_DEFAULT) return null; + + return ( + + + +
+
+
+
+
+
+
+
+
{ LocalizeText('useproduct.widget.text.plant_seed', [ 'productName' ], [ furniData.name ] ) }
+
{ LocalizeText('useproduct.widget.info.plant_seed') }
+
+
+ + +
+
+
+ + + ); +} diff --git a/src/views/room/widgets/furniture/context-menu/views/monsterplant-seed/MonsterPlantSeedConfirmView.types.ts b/src/views/room/widgets/furniture/context-menu/views/monsterplant-seed/MonsterPlantSeedConfirmView.types.ts new file mode 100644 index 00000000..75fded04 --- /dev/null +++ b/src/views/room/widgets/furniture/context-menu/views/monsterplant-seed/MonsterPlantSeedConfirmView.types.ts @@ -0,0 +1,5 @@ +export interface MonsterPlantSeedConfirmViewProps +{ + objectId: number; + close: () => void; +} diff --git a/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx b/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx new file mode 100644 index 00000000..859a1f69 --- /dev/null +++ b/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx @@ -0,0 +1,102 @@ +import { FigureData, RedeemItemClothingComposer, RoomObjectCategory, UserFigureComposer } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import { GetAvatarRenderManager, GetConnection, GetFurnitureDataForRoomObject, GetSessionDataManager } from '../../../../../../../api'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../../../layout'; +import { LocalizeText } from '../../../../../../../utils/LocalizeText'; +import { FurniCategory } from '../../../../../../inventory/common/FurniCategory'; +import { AvatarImageView } from '../../../../../../shared/avatar-image/AvatarImageView'; +import { useRoomContext } from '../../../../../context/RoomContext'; +import { PurchasableClothingConfirmViewProps } from './PurchasableClothingConfirmView.types'; + +const MODE_DEFAULT: number = -1; +const MODE_PURCHASABLE_CLOTHING: number = 0; + +export const PurchasableClothingConfirmView: FC = props => +{ + const { objectId = -1, close = null } = props; + const [ mode, setMode ] = useState(MODE_DEFAULT); + const [ gender, setGender ] = useState(FigureData.MALE); + const [ newFigure, setNewFigure ] = useState(null); + const { roomSession = null } = useRoomContext(); + + const useProduct = useCallback(() => + { + GetConnection().send(new RedeemItemClothingComposer(objectId)); + GetConnection().send(new UserFigureComposer(gender, newFigure)); + + close(); + }, [ objectId, gender, newFigure, close ]); + + useEffect(() => + { + let mode = MODE_DEFAULT; + + const figure = GetSessionDataManager().figure; + const gender = GetSessionDataManager().gender; + const validSets: number[] = []; + + if(roomSession && (objectId >= 0)) + { + const furniData = GetFurnitureDataForRoomObject(roomSession.roomId, objectId, RoomObjectCategory.FLOOR); + + if(furniData) + { + switch(furniData.specialType) + { + case FurniCategory._Str_12534: + mode = MODE_PURCHASABLE_CLOTHING; + + const setIds = furniData.customParams.split(',').map(part => parseInt(part)); + + for(const setId of setIds) + { + if(GetAvatarRenderManager().isValidFigureSetForGender(setId, gender)) validSets.push(setId); + } + + break; + } + } + } + + if(mode === MODE_DEFAULT) + { + close(); + + return; + } + + setGender(gender); + setNewFigure(GetAvatarRenderManager().getFigureStringWithFigureIds(figure, gender, validSets)); + + // if owns clothing, change to it + + setMode(mode); + }, [ roomSession, objectId, close ]); + + if(mode === MODE_DEFAULT) return null; + + return ( + + + +
+
+
+ +
+
+
+
+
{ LocalizeText('useproduct.widget.text.bind_clothing') }
+
{ LocalizeText('useproduct.widget.info.bind_clothing') }
+
+
+ + +
+
+
+
+
+ ); +} diff --git a/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.types.ts b/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.types.ts new file mode 100644 index 00000000..f6f04211 --- /dev/null +++ b/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.types.ts @@ -0,0 +1,5 @@ +export interface PurchasableClothingConfirmViewProps +{ + objectId: number; + close: () => void; +} diff --git a/src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.tsx b/src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.tsx index 1d320b04..8c79722a 100644 --- a/src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.tsx +++ b/src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.tsx @@ -3,9 +3,8 @@ import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../ import { LocalizeText } from '../../../../../utils/LocalizeText'; import { useRoomContext } from '../../../context/RoomContext'; import { FurnitureDimmerData } from './FurnitureDimmerData'; -import { FurnitureDimmerViewProps } from './FurnitureDimmerView.types'; -export const FurnitureDimmerView: FC = props => +export const FurnitureDimmerView: FC<{}> = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); const [ dimmerData, setDimmerData ] = useState(null); diff --git a/src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.types.ts b/src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.types.ts deleted file mode 100644 index 6c267da7..00000000 --- a/src/views/room/widgets/furniture/dimmer/FurnitureDimmerView.types.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { FurnitureWidgetProps } from '../FurnitureWidget.types'; - -export interface FurnitureDimmerViewProps extends FurnitureWidgetProps -{} diff --git a/src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.types.ts b/src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.types.ts deleted file mode 100644 index b5d92bae..00000000 --- a/src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.types.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { FurnitureWidgetProps } from '../FurnitureWidget.types'; - -export interface FurnitureEngravingLockViewProps extends FurnitureWidgetProps -{} diff --git a/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.tsx b/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.tsx index d113b585..1743713f 100644 --- a/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.tsx +++ b/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.tsx @@ -8,9 +8,8 @@ import { LocalizeText } from '../../../../../utils/LocalizeText'; import { useRoomContext } from '../../../context/RoomContext'; import { RoomWidgetRoomObjectUpdateEvent } from '../../../events'; import { FurnitureExchangeCreditData } from './FurnitureExchangeCreditData'; -import { FurnitureExchangeCreditProps } from './FurnitureExchangeCreditView.types'; -export const FurnitureExchangeCreditView: FC = props => +export const FurnitureExchangeCreditView: FC<{}> = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); const [ exchangeCreditData, setExchangeCreditData ] = useState(null); diff --git a/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.types.ts b/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.types.ts deleted file mode 100644 index 32a48de0..00000000 --- a/src/views/room/widgets/furniture/exchange-credit/FurnitureExchangeCreditView.types.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { FurnitureWidgetProps } from '../FurnitureWidget.types'; - -export interface FurnitureExchangeCreditProps extends FurnitureWidgetProps -{} diff --git a/src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockData.ts b/src/views/room/widgets/furniture/friend-furni/FriendFurniLockData.ts similarity index 100% rename from src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockData.ts rename to src/views/room/widgets/furniture/friend-furni/FriendFurniLockData.ts diff --git a/src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.scss b/src/views/room/widgets/furniture/friend-furni/FurnitureFriendFurniView.scss similarity index 100% rename from src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.scss rename to src/views/room/widgets/furniture/friend-furni/FurnitureFriendFurniView.scss diff --git a/src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.tsx b/src/views/room/widgets/furniture/friend-furni/FurnitureFriendFurniView.tsx similarity index 96% rename from src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.tsx rename to src/views/room/widgets/furniture/friend-furni/FurnitureFriendFurniView.tsx index 80e87d07..2c6a6679 100644 --- a/src/views/room/widgets/furniture/engraving-lock/FurnitureEngravingLockView.tsx +++ b/src/views/room/widgets/furniture/friend-furni/FurnitureFriendFurniView.tsx @@ -10,10 +10,9 @@ import { LocalizeText } from '../../../../../utils/LocalizeText'; import { AvatarImageView } from '../../../../shared/avatar-image/AvatarImageView'; import { useRoomContext } from '../../../context/RoomContext'; import { RoomWidgetRoomObjectUpdateEvent } from '../../../events'; -import { FurnitureEngravingLockData } from './FurnitureEngravingLockData'; -import { FurnitureEngravingLockViewProps } from './FurnitureEngravingLockView.types'; +import { FurnitureEngravingLockData } from './FriendFurniLockData'; -export const FurnitureEngravingLockView: FC = props => +export const FurnitureFriendFurniView: FC<{}> = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); const [ engravingLockData, setEngravingLockData ] = useState(null); diff --git a/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.tsx b/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.tsx index c8e715c0..2b02a2a1 100644 --- a/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.tsx +++ b/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.tsx @@ -2,9 +2,8 @@ import { NitroEvent, RoomEngineTriggerWidgetEvent } from 'nitro-renderer'; import { FC } from 'react'; import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event'; import { useRoomContext } from '../../../context/RoomContext'; -import { FurnitureHighScoreViewProps } from './FurnitureHighScoreView.types'; -export const FurnitureHighScoreView: FC = props => +export const FurnitureHighScoreView: FC<{}> = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); diff --git a/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.types.ts b/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.types.ts deleted file mode 100644 index b387dab6..00000000 --- a/src/views/room/widgets/furniture/high-score/FurnitureHighScoreView.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { FurnitureWidgetProps } from '../FurnitureWidget.types'; - -export interface FurnitureHighScoreViewProps extends FurnitureWidgetProps -{ - -} diff --git a/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx b/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx index cee946ec..a4439b5b 100644 --- a/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx +++ b/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.tsx @@ -5,9 +5,8 @@ import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dis import { useRoomContext } from '../../../context/RoomContext'; import { RoomWidgetRoomObjectUpdateEvent } from '../../../events'; import { ObjectLocationView } from '../../object-location/ObjectLocationView'; -import { FurnitureManipulationMenuViewProps } from './FurnitureManipulationMenuView.types'; -export const FurnitureManipulationMenuView: FC = props => +export const FurnitureManipulationMenuView: FC<{}> = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); const [ isVisible, setIsVisible ] = useState(false); diff --git a/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.types.ts b/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.types.ts deleted file mode 100644 index 8fb33820..00000000 --- a/src/views/room/widgets/furniture/manipulation-menu/FurnitureManipulationMenuView.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { FurnitureWidgetProps } from '../FurnitureWidget.types'; - -export interface FurnitureManipulationMenuViewProps extends FurnitureWidgetProps -{ - -} diff --git a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx b/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx index a07a6cba..151e0a3e 100644 --- a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx +++ b/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx @@ -10,8 +10,8 @@ import { LocalizeText } from '../../../../../utils/LocalizeText'; import { AvatarImageView } from '../../../../shared/avatar-image/AvatarImageView'; import { useRoomContext } from '../../../context/RoomContext'; import { RoomWidgetRoomObjectUpdateEvent } from '../../../events'; +import { MannequinViewMode } from './common/MannequinViewMode'; import { FurnitureMannequinData } from './FurnitureMannequinData'; -import { FurnitureMannequinViewMode, FurnitureMannequinViewProps } from './FurnitureMannequinView.types'; const parts = [ AvatarFigurePartType.CHEST_ACCESSORY, @@ -23,7 +23,7 @@ const parts = [ ]; const baseAvatar = ['hd', 99999, 99998]; -export const FurnitureMannequinView: FC = props => +export const FurnitureMannequinView: FC<{}> = props => { const { eventDispatcher = null } = useRoomContext(); @@ -64,7 +64,7 @@ export const FurnitureMannequinView: FC = props => if(userCanEdit) { - setViewMode(FurnitureMannequinViewMode.EDIT); + setViewMode(MannequinViewMode.EDIT); } else { @@ -72,15 +72,15 @@ export const FurnitureMannequinView: FC = props => if(userGender.toUpperCase() !== mannequinData.gender.toUpperCase()) { - setViewMode(FurnitureMannequinViewMode.INCOMPATIBLE_GENDER); + setViewMode(MannequinViewMode.INCOMPATIBLE_GENDER); } else if(userClubLevel < mannequinData.clubLevel) { - setViewMode(FurnitureMannequinViewMode.CLUB); + setViewMode(MannequinViewMode.CLUB); } else { - setViewMode(FurnitureMannequinViewMode.DEFAULT); + setViewMode(MannequinViewMode.DEFAULT); } } }, []); @@ -138,11 +138,11 @@ export const FurnitureMannequinView: FC = props => return; case 'load_figure': loadMannequinFigure(Nitro.instance.avatar.createFigureContainer(Nitro.instance.sessionDataManager.figure)); - setViewMode(FurnitureMannequinViewMode.SAVE); + setViewMode(MannequinViewMode.SAVE); return; case 'back': loadMannequinFigure(Nitro.instance.avatar.createFigureContainer(mannequinData.figure)); - setViewMode(FurnitureMannequinViewMode.EDIT); + setViewMode(MannequinViewMode.EDIT); return; case 'save_name': GetRoomSession().connection.send(new FurnitureMannequinSaveNameComposer(mannequinData.objectId, mannequinData.name)); @@ -179,7 +179,7 @@ export const FurnitureMannequinView: FC = props =>
- { viewMode === FurnitureMannequinViewMode.DEFAULT && + { viewMode === MannequinViewMode.DEFAULT && <>
{ mannequinData.name }
@@ -187,7 +187,7 @@ export const FurnitureMannequinView: FC = props =>
processAction('wear') }>{ LocalizeText('mannequin.widget.wear') }
} - { viewMode === FurnitureMannequinViewMode.EDIT && + { viewMode === MannequinViewMode.EDIT && <> processAction('set_name', event.target.value) } onKeyDown={ event => handleKeyDown(event) } />
@@ -195,7 +195,7 @@ export const FurnitureMannequinView: FC = props =>
processAction('wear') }>{ LocalizeText('mannequin.widget.wear') }
} - { viewMode === FurnitureMannequinViewMode.SAVE && + { viewMode === MannequinViewMode.SAVE && <>
{ mannequinData.name }
@@ -206,9 +206,9 @@ export const FurnitureMannequinView: FC = props =>
processAction('save_figure') }>{ LocalizeText('mannequin.widget.save') }
} - { viewMode === FurnitureMannequinViewMode.CLUB && + { viewMode === MannequinViewMode.CLUB &&
{ LocalizeText('mannequin.widget.clubnotification') }
} - { viewMode === FurnitureMannequinViewMode.INCOMPATIBLE_GENDER && + { viewMode === MannequinViewMode.INCOMPATIBLE_GENDER &&
{ LocalizeText('mannequin.widget.wronggender') }
}
diff --git a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.types.tsx b/src/views/room/widgets/furniture/mannequin/common/MannequinViewMode.ts similarity index 61% rename from src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.types.tsx rename to src/views/room/widgets/furniture/mannequin/common/MannequinViewMode.ts index eae1f80c..e588eea4 100644 --- a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.types.tsx +++ b/src/views/room/widgets/furniture/mannequin/common/MannequinViewMode.ts @@ -1,9 +1,4 @@ -import { FurnitureWidgetProps } from '../FurnitureWidget.types'; - -export interface FurnitureMannequinViewProps extends FurnitureWidgetProps -{} - -export class FurnitureMannequinViewMode +export class MannequinViewMode { public static readonly EDIT: string = 'edit'; public static readonly SAVE: string = 'save'; diff --git a/src/views/room/widgets/furniture/present/FurniturePresentView.tsx b/src/views/room/widgets/furniture/present/FurniturePresentView.tsx index 7e5fedfc..f3f11d51 100644 --- a/src/views/room/widgets/furniture/present/FurniturePresentView.tsx +++ b/src/views/room/widgets/furniture/present/FurniturePresentView.tsx @@ -2,9 +2,8 @@ import { NitroEvent, RoomEngineTriggerWidgetEvent } from 'nitro-renderer'; import { FC } from 'react'; import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event'; import { useRoomContext } from '../../../context/RoomContext'; -import { FurniturePresentViewProps } from './FurniturePresentView.types'; -export const FurniturePresentView: FC = props => +export const FurniturePresentView: FC<{}> = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); diff --git a/src/views/room/widgets/furniture/present/FurniturePresentView.types.ts b/src/views/room/widgets/furniture/present/FurniturePresentView.types.ts deleted file mode 100644 index 81171e33..00000000 --- a/src/views/room/widgets/furniture/present/FurniturePresentView.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { FurnitureWidgetProps } from '../FurnitureWidget.types'; - -export interface FurniturePresentViewProps extends FurnitureWidgetProps -{ - -} diff --git a/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx b/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx index 3a34020b..d6174681 100644 --- a/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx +++ b/src/views/room/widgets/furniture/stickie/FurnitureStickieView.tsx @@ -9,9 +9,8 @@ import { useRoomContext } from '../../../context/RoomContext'; import { RoomWidgetRoomObjectUpdateEvent } from '../../../events'; import { FurnitureStickieData } from './FurnitureStickieData'; import { getStickieColorName, STICKIE_COLORS } from './FurnitureStickieUtils'; -import { FurnitureStickieViewProps } from './FurnitureStickieView.types'; -export const FurnitureStickieView: FC = props => +export const FurnitureStickieView: FC<{}> = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); const [ stickieData, setStickieData ] = useState(null); diff --git a/src/views/room/widgets/furniture/stickie/FurnitureStickieView.types.ts b/src/views/room/widgets/furniture/stickie/FurnitureStickieView.types.ts deleted file mode 100644 index b45c08f5..00000000 --- a/src/views/room/widgets/furniture/stickie/FurnitureStickieView.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { FurnitureWidgetProps } from '../FurnitureWidget.types'; - -export interface FurnitureStickieViewProps extends FurnitureWidgetProps -{ - -} diff --git a/src/views/room/widgets/furniture/trophy/FurnitureTrophyView.tsx b/src/views/room/widgets/furniture/trophy/FurnitureTrophyView.tsx index 5eba165f..9a1e6b45 100644 --- a/src/views/room/widgets/furniture/trophy/FurnitureTrophyView.tsx +++ b/src/views/room/widgets/furniture/trophy/FurnitureTrophyView.tsx @@ -8,9 +8,8 @@ import { LocalizeText } from '../../../../../utils/LocalizeText'; import { useRoomContext } from '../../../context/RoomContext'; import { RoomWidgetRoomObjectUpdateEvent } from '../../../events'; import { FurnitureTrophyData } from './FurnitureTrophyData'; -import { FurnitureTrophyViewProps } from './FurnitureTrophyView.types'; -export const FurnitureTrophyView: FC = props => +export const FurnitureTrophyView: FC<{}> = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); const [ trophyData, setTrophyData ] = useState(null); diff --git a/src/views/room/widgets/furniture/trophy/FurnitureTrophyView.types.ts b/src/views/room/widgets/furniture/trophy/FurnitureTrophyView.types.ts deleted file mode 100644 index d6d43f31..00000000 --- a/src/views/room/widgets/furniture/trophy/FurnitureTrophyView.types.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { FurnitureWidgetProps } from '../FurnitureWidget.types'; - -export interface FurnitureTrophyViewProps extends FurnitureWidgetProps -{} diff --git a/src/views/room/widgets/infostand/views/furni/InfoStandWidgetFurniView.tsx b/src/views/room/widgets/infostand/views/furni/InfoStandWidgetFurniView.tsx index 0415db5f..ea6495d6 100644 --- a/src/views/room/widgets/infostand/views/furni/InfoStandWidgetFurniView.tsx +++ b/src/views/room/widgets/infostand/views/furni/InfoStandWidgetFurniView.tsx @@ -3,6 +3,7 @@ import { FC, useCallback, useEffect, useState } from 'react'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { BadgeImageView } from '../../../../../shared/badge-image/BadgeImageView'; import { LimitedEditionCompactPlateView } from '../../../../../shared/limited-edition/compact-plate/LimitedEditionCompactPlateView'; +import { RarityLevelView } from '../../../../../shared/rarity-level/RarityLevelView'; import { useRoomContext } from '../../../../context/RoomContext'; import { RoomWidgetFurniActionMessage } from '../../../../messages'; import { InfoStandBaseView } from '../base/InfoStandBaseView'; @@ -183,6 +184,10 @@ export const InfoStandWidgetFurniView: FC = props
} + { (furniData.stuffData.rarityLevel > -1) && +
+ +
} { furniData.image.src.length && }
From ffb0b898ef6b1c6d4c6c57eb2fa54b849dd1ecbf Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 12 Jul 2021 12:27:29 -0400 Subject: [PATCH 43/72] Add pet view --- .../views/pet/AvatarInfoWidgetPetView.tsx | 150 +++++++++++++++++- 1 file changed, 146 insertions(+), 4 deletions(-) diff --git a/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.tsx b/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.tsx index 59eac211..4935a64d 100644 --- a/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.tsx +++ b/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.tsx @@ -1,9 +1,151 @@ -import { FC } from 'react'; +import { PetType, RoomControllerLevel, RoomObjectCategory, RoomObjectType, RoomObjectVariable } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useMemo, useState } from 'react'; +import { GetOwnRoomObject, GetSessionDataManager } from '../../../../../../api'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { useRoomContext } from '../../../../context/RoomContext'; +import { RoomWidgetMessage, RoomWidgetUserActionMessage } from '../../../../messages'; +import { ContextMenuView } from '../../../context-menu/ContextMenuView'; +import { ContextMenuHeaderView } from '../../../context-menu/views/header/ContextMenuHeaderView'; +import { ContextMenuListItemView } from '../../../context-menu/views/list-item/ContextMenuListItemView'; import { AvatarInfoWidgetPetViewProps } from './AvatarInfoWidgetPetView.types'; +const _Str_2906: number = 0; +const _Str_5818: number = 1; +const _Str_5938: number = 2; +const _Str_13388: number = 3; + export const AvatarInfoWidgetPetView: FC = props => { - const { petData = null } = props; - - return null; + const { petData = null, close = null } = props; + const [ mode, setMode ] = useState(_Str_2906); + const [ respectsLeft, setRespectsLeft ] = useState(0); + const { roomSession = null, widgetHandler = null } = useRoomContext(); + + useEffect(() => + { + setMode(prevValue => + { + if(petData.petType === PetType.MONSTERPLANT) return _Str_13388; + else if(petData.saddle && !petData.rider) return _Str_5818; + else if(petData.rider) return _Str_5938; + + return _Str_2906; + }); + + setRespectsLeft(petData.respectsPetLeft); + }, [ petData ]) + + const processAction = useCallback((name: string) => + { + let messageType: string = null; + let message: RoomWidgetMessage = null; + let hideMenu = true; + + if(name) + { + switch(name) + { + case 'respect': + let newRespectsLeft = 0; + + setRespectsLeft(prevValue => + { + newRespectsLeft = (prevValue - 1); + + return newRespectsLeft; + }); + + messageType = RoomWidgetUserActionMessage.RESPECT_PET; + + if(newRespectsLeft > 0) hideMenu = false; + break; + case 'treat': + messageType = RoomWidgetUserActionMessage.TREAT_PET; + break; + case 'pass_handitem': + messageType = RoomWidgetUserActionMessage.GIVE_CARRY_ITEM_TO_PET; + break; + case 'pick_up': + messageType = RoomWidgetUserActionMessage.PICKUP_PET; + break; + case 'mount': + messageType = RoomWidgetUserActionMessage.MOUNT_PET; + break; + case 'dismount': + messageType = RoomWidgetUserActionMessage.DISMOUNT_PET; + break; + } + + if(messageType) message = new RoomWidgetUserActionMessage(messageType, petData.id); + + if(message) widgetHandler.processWidgetMessage(message); + } + + if(hideMenu) close(); + }, [ widgetHandler, petData, close ]); + + const canPickUp = useMemo(() => + { + return (roomSession.isRoomOwner || (roomSession.controllerLevel >= RoomControllerLevel.GUEST) || GetSessionDataManager().isModerator); + }, [ roomSession ]); + + const canGiveHandItem = useMemo(() => + { + let flag = false; + + const roomObject = GetOwnRoomObject(); + + if(roomObject) + { + const carryId = roomObject.model.getValue(RoomObjectVariable.FIGURE_CARRY_OBJECT); + + if((carryId > 0) && (carryId < 999999)) flag = true; + } + + return flag; + }, []); + + return ( + + + { petData.name } + + { (mode === _Str_2906) && (respectsLeft > 0) && + processAction('respect') }> + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + } + { (mode === _Str_5818) && + <> + processAction('mount') }> + { LocalizeText('infostand.button.mount') } + + { (respectsLeft > 0) && + processAction('respect') }> + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + } + } + { (mode === _Str_5938) && + <> + processAction('dismount') }> + { LocalizeText('infostand.button.dismount') } + + { (respectsLeft > 0) && + processAction('respect') }> + { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } + } + } + { (mode === _Str_13388) && !petData.dead && ((petData.energy / petData.maximumEnergy) < 0.98) && + processAction('treat') }> + { LocalizeText('infostand.button.treat') } + } + { canPickUp && + processAction('pick_up') }> + { LocalizeText('infostand.button.pickup') } + } + { canGiveHandItem && + processAction('pass_hand_item') }> + { LocalizeText('infostand.button.pass_hand_item') } + } + + ); } From 0e4a9c3bea38fd2ed2bede2605de68a22e06e74f Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 13 Jul 2021 00:27:38 -0400 Subject: [PATCH 44/72] Add UseMountEffect --- src/hooks/UseMountEffect.tsx | 3 +++ src/hooks/index.ts | 13 +++++++++++++ 2 files changed, 16 insertions(+) create mode 100644 src/hooks/UseMountEffect.tsx create mode 100644 src/hooks/index.ts diff --git a/src/hooks/UseMountEffect.tsx b/src/hooks/UseMountEffect.tsx new file mode 100644 index 00000000..cb6f7bf6 --- /dev/null +++ b/src/hooks/UseMountEffect.tsx @@ -0,0 +1,3 @@ +import { useEffect } from 'react'; + +export const UseMountEffect = (fun: Function) => useEffect(() => fun(), []); diff --git a/src/hooks/index.ts b/src/hooks/index.ts new file mode 100644 index 00000000..41928f94 --- /dev/null +++ b/src/hooks/index.ts @@ -0,0 +1,13 @@ +export * from './events'; +export * from './events/core'; +export * from './events/core/configuration'; +export * from './events/nitro'; +export * from './events/nitro/avatar'; +export * from './events/nitro/camera'; +export * from './events/nitro/communication'; +export * from './events/nitro/localization'; +export * from './events/nitro/room'; +export * from './events/nitro/session'; +export * from './events/ui'; +export * from './messages'; +export * from './UseMountEffect'; From 79b0a8e2329e73d7a0da1412915b0e65ae873d0a Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 13 Jul 2021 00:31:56 -0400 Subject: [PATCH 45/72] Add RoomColorView --- src/api/nitro/room/DispatchResizeEvent.ts | 22 --- src/api/nitro/room/index.ts | 1 - src/views/room/RoomColorView.tsx | 152 ++++++++++++++++++ src/views/room/RoomView.tsx | 46 +++++- src/views/room/context/RoomContext.tsx | 1 + src/views/room/context/RoomContext.types.ts | 1 + .../events/RoomWidgetUpdateRoomViewEvent.ts | 21 +++ src/views/room/widgets/RoomWidgetsView.tsx | 5 +- 8 files changed, 217 insertions(+), 32 deletions(-) delete mode 100644 src/api/nitro/room/DispatchResizeEvent.ts create mode 100644 src/views/room/RoomColorView.tsx create mode 100644 src/views/room/events/RoomWidgetUpdateRoomViewEvent.ts diff --git a/src/api/nitro/room/DispatchResizeEvent.ts b/src/api/nitro/room/DispatchResizeEvent.ts deleted file mode 100644 index 04391187..00000000 --- a/src/api/nitro/room/DispatchResizeEvent.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Nitro } from 'nitro-renderer'; -import { InitializeRoomInstanceRenderingCanvas } from './InitializeRoomInstanceRenderingCanvas'; - -let resizeTimer: ReturnType = null; - -export function WindowResizeEvent(roomId: number, canvasId: number) -{ - if(resizeTimer) clearTimeout(resizeTimer); - - resizeTimer = setTimeout(() => - { - Nitro.instance.renderer.resize(window.innerWidth, window.innerHeight); - - InitializeRoomInstanceRenderingCanvas(roomId, canvasId, Nitro.instance.width, Nitro.instance.height); - - //this._events.dispatchEvent(new RoomWidgetRoomViewUpdateEvent(RoomWidgetRoomViewUpdateEvent.SIZE_CHANGED, this.getRoomViewRect())); - - //this.setRoomBackground(); - - Nitro.instance.render(); - }, 1); -} diff --git a/src/api/nitro/room/index.ts b/src/api/nitro/room/index.ts index 6a06237f..b18567a6 100644 --- a/src/api/nitro/room/index.ts +++ b/src/api/nitro/room/index.ts @@ -1,5 +1,4 @@ export * from './DispatchMouseEvent'; -export * from './DispatchResizeEvent'; export * from './DispatchTouchEvent'; export * from './GetOwnRoomObject'; export * from './GetRoomEngine'; diff --git a/src/views/room/RoomColorView.tsx b/src/views/room/RoomColorView.tsx new file mode 100644 index 00000000..b298becf --- /dev/null +++ b/src/views/room/RoomColorView.tsx @@ -0,0 +1,152 @@ +import { ColorConverter, Nitro, NitroAdjustmentFilter, NitroContainer, NitroSprite, NitroTexture, RoomBackgroundColorEvent, RoomEngineEvent, RoomId, RoomObjectHSLColorEnabledEvent } from 'nitro-renderer'; +import { FC, useCallback, useState } from 'react'; +import { GetRoomEngine } from '../../api'; +import { UseMountEffect } from '../../hooks'; +import { CreateEventDispatcherHook, useRoomEngineEvent } from '../../hooks/events'; +import { useRoomContext } from './context/RoomContext'; +import { RoomWidgetUpdateRoomViewEvent } from './events/RoomWidgetUpdateRoomViewEvent'; + +const ROOM_FILTER: NitroAdjustmentFilter = new NitroAdjustmentFilter(); + +export const RoomColorView: FC<{}> = props => +{ + const [ roomBackground, setRoomBackground ] = useState(null); + const [ roomBackgroundColor, setRoomBackgroundColor ] = useState(0x000000); + const [ roomFilter, setRoomFilter ] = useState(null); + const [ roomFilterColor, setRoomFilterColor ] = useState(-1); + const { roomSession = null, canvasId = -1, eventDispatcher = null } = useRoomContext(); + + const getRenderingCanvas = useCallback(() => + { + return GetRoomEngine().getRoomInstanceRenderingCanvas(roomSession.roomId, canvasId); + }, [ roomSession, canvasId ]); + + const getRoomBackground = useCallback(() => + { + if(roomBackground) return roomBackground; + + const canvas = getRenderingCanvas(); + + if(!canvas) return null; + + const displayObject = (canvas.master as NitroContainer); + const background = new NitroSprite(NitroTexture.WHITE); + + displayObject.addChildAt(background, 0); + + setRoomBackground(background); + + return background; + }, [ roomBackground, getRenderingCanvas ]); + + const updateRoomBackground = useCallback(() => + { + const background = getRoomBackground(); + + if(!background) return; + + background.tint = roomBackgroundColor; + background.width = Nitro.instance.width; + background.height = Nitro.instance.height; + }, [ roomBackgroundColor, getRoomBackground ]); + + const updateRoomBackgroundColor = useCallback((hue: number, saturation: number, lightness: number) => + { + setRoomBackgroundColor(ColorConverter.hslToRGB(((((hue & 0xFF) << 16) + ((saturation & 0xFF) << 8)) + (lightness & 0xFF)))); + + const background = getRoomBackground(); + + if(!background) return; + + if(!hue && !saturation && !lightness) + { + background.visible = false; + } + else + { + updateRoomBackground(); + + background.visible = true; + } + }, [ getRoomBackground, updateRoomBackground ]); + + const getRoomFilter = useCallback(() => + { + if(roomFilter) return roomFilter; + + const canvas = getRenderingCanvas(); + + if(!canvas) return null; + + const display = canvas.master; + + if(!display) return null; + + setRoomFilter(ROOM_FILTER); + + display.filters = [ ROOM_FILTER ]; + + return ROOM_FILTER; + }, [ roomFilter, getRenderingCanvas ]); + + const updateRoomFilter = useCallback(() => + { + const colorMatrix = getRoomFilter(); + + if(!colorMatrix) return; + + const r = ((roomFilterColor >> 16) & 0xFF); + const g = ((roomFilterColor >> 8) & 0xFF); + const b = (roomFilterColor & 0xFF); + + colorMatrix.red = (r / 255); + colorMatrix.green = (g / 255); + colorMatrix.blue = (b / 255); + }, [ roomFilterColor, getRoomFilter ]); + + const updateRoomFilterColor = useCallback((color: number, brightness: number) => + { + setRoomFilterColor(ColorConverter.hslToRGB(((ColorConverter.rgbToHSL(color) & 0xFFFF00) + brightness))); + + updateRoomFilter(); + }, [ updateRoomFilter ]); + + const onRoomEngineEvent = useCallback((event: RoomEngineEvent) => + { + if(!RoomId.isRoomPreviewerId(event.roomId)) return; + + switch(event.type) + { + case RoomObjectHSLColorEnabledEvent.ROOM_BACKGROUND_COLOR: { + const hslColorEvent = (event as RoomObjectHSLColorEnabledEvent); + + if(hslColorEvent.enable) updateRoomBackgroundColor(hslColorEvent.hue, hslColorEvent.saturation, hslColorEvent.lightness); + else updateRoomBackgroundColor(0, 0, 0); + + return; + } + case RoomBackgroundColorEvent.ROOM_COLOR: { + const colorEvent = (event as RoomBackgroundColorEvent); + + if(colorEvent.bgOnly) updateRoomFilterColor(0xFF0000, 0xFF); + else updateRoomFilterColor(colorEvent.color, colorEvent.brightness); + + return; + } + } + }, [ updateRoomBackgroundColor, updateRoomFilterColor ]); + + useRoomEngineEvent(RoomObjectHSLColorEnabledEvent.ROOM_BACKGROUND_COLOR, onRoomEngineEvent); + useRoomEngineEvent(RoomBackgroundColorEvent.ROOM_COLOR, onRoomEngineEvent); + + const onRoomWidgetUpdateRoomViewEvent = useCallback((event: RoomWidgetUpdateRoomViewEvent) => + { + updateRoomBackground(); + }, [ updateRoomBackground ]); + + CreateEventDispatcherHook(RoomWidgetUpdateRoomViewEvent.SIZE_CHANGED, eventDispatcher, onRoomWidgetUpdateRoomViewEvent); + + UseMountEffect(updateRoomBackground); + + return null; +} diff --git a/src/views/room/RoomView.tsx b/src/views/room/RoomView.tsx index 2bc5e352..d55390f9 100644 --- a/src/views/room/RoomView.tsx +++ b/src/views/room/RoomView.tsx @@ -1,15 +1,16 @@ -import { EventDispatcher, Nitro, RoomEngineEvent, RoomEngineObjectEvent, RoomGeometry, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomVariableEnum, Vector3d } from 'nitro-renderer'; +import { EventDispatcher, Nitro, NitroRectangle, RoomEngineEvent, RoomEngineObjectEvent, RoomGeometry, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomVariableEnum, RoomZoomEvent, Vector3d } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; -import { CanManipulateFurniture, IsFurnitureSelectionDisabled, ProcessRoomObjectOperation } from '../../api'; +import { CanManipulateFurniture, InitializeRoomInstanceRenderingCanvas, IsFurnitureSelectionDisabled, ProcessRoomObjectOperation } from '../../api'; import { DispatchMouseEvent } from '../../api/nitro/room/DispatchMouseEvent'; -import { WindowResizeEvent } from '../../api/nitro/room/DispatchResizeEvent'; import { DispatchTouchEvent } from '../../api/nitro/room/DispatchTouchEvent'; import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine'; import { useRoomEngineEvent } from '../../hooks/events'; import { RoomContextProvider } from './context/RoomContext'; import { RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent } from './events'; +import { RoomWidgetUpdateRoomViewEvent } from './events/RoomWidgetUpdateRoomViewEvent'; import { FurnitureContextMenuWidgetHandler, IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers'; +import { RoomColorView } from './RoomColorView'; import { RoomViewProps } from './RoomView.types'; import { RoomWidgetsView } from './widgets/RoomWidgetsView'; @@ -17,6 +18,7 @@ export const RoomView: FC = props => { const { roomSession = null } = props; const [ roomCanvas, setRoomCanvas ] = useState(null); + const [ canvasId, setCanvasId ] = useState(-1); const [ widgetHandler, setWidgetHandler ] = useState(null); useEffect(() => @@ -26,6 +28,7 @@ export const RoomView: FC = props => window.onresize = null; setRoomCanvas(null); + setCanvasId(-1); setWidgetHandler(null); return; @@ -91,9 +94,22 @@ export const RoomView: FC = props => canvas.ontouchend = event => DispatchTouchEvent(roomSession.roomId, canvasId, event); canvas.ontouchcancel = event => DispatchTouchEvent(roomSession.roomId, canvasId, event); - window.onresize = event => WindowResizeEvent(roomSession.roomId, canvasId); + window.onresize = () => + { + Nitro.instance.renderer.resize(window.innerWidth, window.innerHeight); + + InitializeRoomInstanceRenderingCanvas(roomSession.roomId, canvasId, Nitro.instance.width, Nitro.instance.height); + + const bounds = canvas.getBoundingClientRect(); + const rectangle = new NitroRectangle((bounds.x || 0), (bounds.y || 0), (bounds.width || 0), (bounds.height || 0)); + + widgetHandlerManager.eventDispatcher.dispatchEvent(new RoomWidgetUpdateRoomViewEvent(RoomWidgetUpdateRoomViewEvent.SIZE_CHANGED, rectangle)); + + Nitro.instance.render(); + } setRoomCanvas(canvas); + setCanvasId(canvasId); }, [ roomSession ]); const onRoomEngineEvent = useCallback((event: RoomEngineEvent) => @@ -108,11 +124,23 @@ export const RoomView: FC = props => case RoomEngineEvent.GAME_MODE: widgetHandler.eventDispatcher.dispatchEvent(new RoomWidgetRoomEngineUpdateEvent(RoomWidgetRoomEngineUpdateEvent.GAME_MODE, event.roomId)); return; + case RoomZoomEvent.ROOM_ZOOM: { + const zoomEvent = (event as RoomZoomEvent); + + let zoomLevel = ((zoomEvent.level < 1) ? 0.5 : (1 << (Math.floor(zoomEvent.level) - 1))); + + if(zoomEvent.forceFlip || zoomEvent.asDelta) zoomLevel = zoomEvent.level; + + GetRoomEngine().setRoomInstanceRenderingCanvasScale(roomSession.roomId, 1, zoomLevel, null, null, false, zoomEvent.asDelta); + + return; + } } - }, [ widgetHandler ]); + }, [ widgetHandler, roomSession ]); useRoomEngineEvent(RoomEngineEvent.NORMAL_MODE, onRoomEngineEvent); useRoomEngineEvent(RoomEngineEvent.GAME_MODE, onRoomEngineEvent); + useRoomEngineEvent(RoomZoomEvent.ROOM_ZOOM, onRoomEngineEvent); const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) => { @@ -206,11 +234,15 @@ export const RoomView: FC = props => if(!roomSession) return null; return ( - +
{ roomCanvas && createPortal(null, document.getElementById('room-view').appendChild(roomCanvas)) } - { widgetHandler && } + { widgetHandler && + <> + + + }
); diff --git a/src/views/room/context/RoomContext.tsx b/src/views/room/context/RoomContext.tsx index 40e2417a..a4ae5222 100644 --- a/src/views/room/context/RoomContext.tsx +++ b/src/views/room/context/RoomContext.tsx @@ -3,6 +3,7 @@ import { IRoomContext, RoomContextProps } from './RoomContext.types'; const RoomContext = createContext({ roomSession: null, + canvasId: -1, eventDispatcher: null, widgetHandler: null }); diff --git a/src/views/room/context/RoomContext.types.ts b/src/views/room/context/RoomContext.types.ts index b9aade0c..3a0f4f50 100644 --- a/src/views/room/context/RoomContext.types.ts +++ b/src/views/room/context/RoomContext.types.ts @@ -5,6 +5,7 @@ import { IRoomWidgetHandlerManager } from '../handlers'; export interface IRoomContext { roomSession: IRoomSession; + canvasId: number; eventDispatcher: IEventDispatcher; widgetHandler: IRoomWidgetHandlerManager; } diff --git a/src/views/room/events/RoomWidgetUpdateRoomViewEvent.ts b/src/views/room/events/RoomWidgetUpdateRoomViewEvent.ts new file mode 100644 index 00000000..5c1b0715 --- /dev/null +++ b/src/views/room/events/RoomWidgetUpdateRoomViewEvent.ts @@ -0,0 +1,21 @@ +import { NitroRectangle } from 'nitro-renderer'; +import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; + +export class RoomWidgetUpdateRoomViewEvent extends RoomWidgetUpdateEvent +{ + public static SIZE_CHANGED: string = 'RWURVE_SIZE_CHANGED'; + + private _roomViewRectangle: NitroRectangle; + + constructor(type: string, view: NitroRectangle) + { + super(type); + + this._roomViewRectangle = view; + } + + public get roomViewRectangle(): NitroRectangle + { + return this._roomViewRectangle; + } +} diff --git a/src/views/room/widgets/RoomWidgetsView.tsx b/src/views/room/widgets/RoomWidgetsView.tsx index 57523e17..9e080424 100644 --- a/src/views/room/widgets/RoomWidgetsView.tsx +++ b/src/views/room/widgets/RoomWidgetsView.tsx @@ -1,4 +1,4 @@ -import { NitroEvent, RoomEngineUseProductEvent, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent } from 'nitro-renderer'; +import { NitroEvent, RoomEngineDimmerStateEvent, RoomEngineUseProductEvent, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; import { useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks/events'; import { LocalizeText } from '../../../utils/LocalizeText'; @@ -13,7 +13,7 @@ import { RoomWidgetViewProps } from './RoomWidgets.types'; export const RoomWidgetsView: FC = props => { - const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); + const { widgetHandler = null } = useRoomContext(); const onNitroEvent = useCallback((event: NitroEvent) => { @@ -35,6 +35,7 @@ export const RoomWidgetsView: FC = props => useRoomSessionManagerEvent(RoomSessionPetInfoUpdateEvent.PET_INFO, onNitroEvent); useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY, onNitroEvent); useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM, onNitroEvent); + useRoomEngineEvent(RoomEngineDimmerStateEvent.ROOM_COLOR, onNitroEvent); const onRoomErrorEvent = useCallback((event: RoomSessionEvent) => { From bc9d0aa4a1527f8a63bf3f81437ee07baf2dbabc Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 13 Jul 2021 13:30:20 -0400 Subject: [PATCH 46/72] Update events --- src/views/room-host/RoomHostView.tsx | 20 +- src/views/room/RoomColorView.tsx | 14 +- src/views/room/RoomView.tsx | 127 +----------- .../FurnitureContextMenuWidgetHandler.ts | 7 +- src/views/room/handlers/IRoomWidgetHandler.ts | 1 + .../handlers/RoomWidgetAvatarInfoHandler.ts | 7 +- .../room/handlers/RoomWidgetChatHandler.ts | 7 +- .../handlers/RoomWidgetChatInputHandler.ts | 7 +- src/views/room/handlers/RoomWidgetHandler.ts | 2 + .../room/handlers/RoomWidgetHandlerManager.ts | 16 +- .../handlers/RoomWidgetInfostandHandler.ts | 7 +- .../RoomWidgetFurniToWidgetMessage.ts | 46 +++++ src/views/room/messages/index.ts | 1 + src/views/room/widgets/RoomWidgetsView.tsx | 188 +++++++++++++++--- .../views/pet/AvatarInfoWidgetPetView.tsx | 7 +- 15 files changed, 267 insertions(+), 190 deletions(-) create mode 100644 src/views/room/messages/RoomWidgetFurniToWidgetMessage.ts diff --git a/src/views/room-host/RoomHostView.tsx b/src/views/room-host/RoomHostView.tsx index 96facf6c..110f03e6 100644 --- a/src/views/room-host/RoomHostView.tsx +++ b/src/views/room-host/RoomHostView.tsx @@ -1,4 +1,4 @@ -import { IRoomSession, RoomEngineEvent, RoomId, RoomSessionErrorMessageEvent, RoomSessionEvent } from 'nitro-renderer'; +import { IRoomSession, RoomEngineEvent, RoomId, RoomSessionEvent } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; import { SetActiveRoomId } from '../../api/nitro/room/SetActiveRoomId'; import { GetRoomSession } from '../../api/nitro/session/GetRoomSession'; @@ -51,24 +51,6 @@ export const RoomHostView: FC = props => useRoomSessionManagerEvent(RoomSessionEvent.CREATED, onRoomSessionEvent); useRoomSessionManagerEvent(RoomSessionEvent.ENDED, onRoomSessionEvent); - const onRoomSessionErrorMessageEvent = useCallback((event: RoomSessionErrorMessageEvent) => - { - console.log(event); - }, []); - - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_KICKED, onRoomSessionErrorMessageEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_PETS_FORBIDDEN_IN_HOTEL, onRoomSessionErrorMessageEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_PETS_FORBIDDEN_IN_FLAT, onRoomSessionErrorMessageEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_MAX_PETS, onRoomSessionErrorMessageEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_MAX_NUMBER_OF_OWN_PETS, onRoomSessionErrorMessageEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_NO_FREE_TILES_FOR_PET, onRoomSessionErrorMessageEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_SELECTED_TILE_NOT_FREE_FOR_PET, onRoomSessionErrorMessageEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOTS_FORBIDDEN_IN_HOTEL, onRoomSessionErrorMessageEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOTS_FORBIDDEN_IN_FLAT, onRoomSessionErrorMessageEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOT_LIMIT_REACHED, onRoomSessionErrorMessageEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_SELECTED_TILE_NOT_FREE_FOR_BOT, onRoomSessionErrorMessageEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOT_NAME_NOT_ACCEPTED, onRoomSessionErrorMessageEvent); - return (
diff --git a/src/views/room/RoomColorView.tsx b/src/views/room/RoomColorView.tsx index b298becf..85474b9c 100644 --- a/src/views/room/RoomColorView.tsx +++ b/src/views/room/RoomColorView.tsx @@ -6,8 +6,6 @@ import { CreateEventDispatcherHook, useRoomEngineEvent } from '../../hooks/event import { useRoomContext } from './context/RoomContext'; import { RoomWidgetUpdateRoomViewEvent } from './events/RoomWidgetUpdateRoomViewEvent'; -const ROOM_FILTER: NitroAdjustmentFilter = new NitroAdjustmentFilter(); - export const RoomColorView: FC<{}> = props => { const [ roomBackground, setRoomBackground ] = useState(null); @@ -30,7 +28,7 @@ export const RoomColorView: FC<{}> = props => if(!canvas) return null; const displayObject = (canvas.master as NitroContainer); - const background = new NitroSprite(NitroTexture.WHITE); + const background = new NitroSprite(NitroTexture.WHITE); displayObject.addChildAt(background, 0); @@ -82,11 +80,13 @@ export const RoomColorView: FC<{}> = props => if(!display) return null; - setRoomFilter(ROOM_FILTER); + const filter = new NitroAdjustmentFilter(); - display.filters = [ ROOM_FILTER ]; + setRoomFilter(filter); - return ROOM_FILTER; + display.filters = [ filter ]; + + return filter; }, [ roomFilter, getRenderingCanvas ]); const updateRoomFilter = useCallback(() => @@ -113,7 +113,7 @@ export const RoomColorView: FC<{}> = props => const onRoomEngineEvent = useCallback((event: RoomEngineEvent) => { - if(!RoomId.isRoomPreviewerId(event.roomId)) return; + if(RoomId.isRoomPreviewerId(event.roomId)) return; switch(event.type) { diff --git a/src/views/room/RoomView.tsx b/src/views/room/RoomView.tsx index d55390f9..4103324b 100644 --- a/src/views/room/RoomView.tsx +++ b/src/views/room/RoomView.tsx @@ -1,13 +1,11 @@ -import { EventDispatcher, Nitro, NitroRectangle, RoomEngineEvent, RoomEngineObjectEvent, RoomGeometry, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomVariableEnum, RoomZoomEvent, Vector3d } from 'nitro-renderer'; -import { FC, useCallback, useEffect, useState } from 'react'; +import { EventDispatcher, Nitro, NitroRectangle, RoomGeometry, RoomVariableEnum, Vector3d } from 'nitro-renderer'; +import { FC, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; -import { CanManipulateFurniture, InitializeRoomInstanceRenderingCanvas, IsFurnitureSelectionDisabled, ProcessRoomObjectOperation } from '../../api'; +import { InitializeRoomInstanceRenderingCanvas } from '../../api'; import { DispatchMouseEvent } from '../../api/nitro/room/DispatchMouseEvent'; import { DispatchTouchEvent } from '../../api/nitro/room/DispatchTouchEvent'; import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine'; -import { useRoomEngineEvent } from '../../hooks/events'; import { RoomContextProvider } from './context/RoomContext'; -import { RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent } from './events'; import { RoomWidgetUpdateRoomViewEvent } from './events/RoomWidgetUpdateRoomViewEvent'; import { FurnitureContextMenuWidgetHandler, IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers'; import { RoomColorView } from './RoomColorView'; @@ -112,125 +110,6 @@ export const RoomView: FC = props => setCanvasId(canvasId); }, [ roomSession ]); - const onRoomEngineEvent = useCallback((event: RoomEngineEvent) => - { - if(!widgetHandler || RoomId.isRoomPreviewerId(event.roomId)) return; - - switch(event.type) - { - case RoomEngineEvent.NORMAL_MODE: - widgetHandler.eventDispatcher.dispatchEvent(new RoomWidgetRoomEngineUpdateEvent(RoomWidgetRoomEngineUpdateEvent.NORMAL_MODE, event.roomId)); - return; - case RoomEngineEvent.GAME_MODE: - widgetHandler.eventDispatcher.dispatchEvent(new RoomWidgetRoomEngineUpdateEvent(RoomWidgetRoomEngineUpdateEvent.GAME_MODE, event.roomId)); - return; - case RoomZoomEvent.ROOM_ZOOM: { - const zoomEvent = (event as RoomZoomEvent); - - let zoomLevel = ((zoomEvent.level < 1) ? 0.5 : (1 << (Math.floor(zoomEvent.level) - 1))); - - if(zoomEvent.forceFlip || zoomEvent.asDelta) zoomLevel = zoomEvent.level; - - GetRoomEngine().setRoomInstanceRenderingCanvasScale(roomSession.roomId, 1, zoomLevel, null, null, false, zoomEvent.asDelta); - - return; - } - } - }, [ widgetHandler, roomSession ]); - - useRoomEngineEvent(RoomEngineEvent.NORMAL_MODE, onRoomEngineEvent); - useRoomEngineEvent(RoomEngineEvent.GAME_MODE, onRoomEngineEvent); - useRoomEngineEvent(RoomZoomEvent.ROOM_ZOOM, onRoomEngineEvent); - - const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) => - { - if(!roomSession || !widgetHandler) return; - - const objectId = event.objectId; - const category = event.category; - - let updateEvent: RoomWidgetRoomObjectUpdateEvent = null; - - switch(event.type) - { - case RoomEngineObjectEvent.SELECTED: - if(!IsFurnitureSelectionDisabled(event)) updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_SELECTED, objectId, category, event.roomId); - break; - case RoomEngineObjectEvent.DESELECTED: - updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, objectId, category, event.roomId); - break; - case RoomEngineObjectEvent.ADDED: { - let addedEventType: string = null; - - switch(category) - { - case RoomObjectCategory.FLOOR: - case RoomObjectCategory.WALL: - addedEventType = RoomWidgetRoomObjectUpdateEvent.FURNI_ADDED; - break; - case RoomObjectCategory.UNIT: - addedEventType = RoomWidgetRoomObjectUpdateEvent.USER_ADDED; - break; - } - - if(addedEventType) updateEvent = new RoomWidgetRoomObjectUpdateEvent(addedEventType, objectId, category, event.roomId); - break; - } - case RoomEngineObjectEvent.REMOVED: { - let removedEventType: string = null; - - switch(category) - { - case RoomObjectCategory.FLOOR: - case RoomObjectCategory.WALL: - removedEventType = RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED; - break; - case RoomObjectCategory.UNIT: - removedEventType = RoomWidgetRoomObjectUpdateEvent.USER_REMOVED; - break; - } - - if(removedEventType) updateEvent = new RoomWidgetRoomObjectUpdateEvent(removedEventType, objectId, category, event.roomId); - break; - } - case RoomEngineObjectEvent.MOUSE_ENTER: - updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OVER, objectId, category, event.roomId); - break; - case RoomEngineObjectEvent.MOUSE_LEAVE: - updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OUT, objectId, category, event.roomId); - break; - case RoomEngineObjectEvent.REQUEST_MOVE: - if(CanManipulateFurniture(roomSession, objectId, category)) ProcessRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_MOVE); - break; - case RoomEngineObjectEvent.REQUEST_ROTATE: - if(CanManipulateFurniture(roomSession, objectId, category)) ProcessRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_ROTATE_POSITIVE); - break; - case RoomEngineObjectEvent.REQUEST_MANIPULATION: - if(CanManipulateFurniture(roomSession, objectId, category)) updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_REQUEST_MANIPULATION, objectId, category, event.roomId); - break; - } - - if(updateEvent) - { - let dispatchEvent = true; - - if(updateEvent instanceof RoomWidgetRoomObjectUpdateEvent) dispatchEvent = (!RoomId.isRoomPreviewerId(updateEvent.roomId)); - - if(dispatchEvent) widgetHandler.eventDispatcher.dispatchEvent(updateEvent); - } - }, [ roomSession, widgetHandler ]); - - useRoomEngineEvent(RoomEngineObjectEvent.SELECTED, onRoomEngineObjectEvent); - useRoomEngineEvent(RoomEngineObjectEvent.DESELECTED, onRoomEngineObjectEvent); - useRoomEngineEvent(RoomEngineObjectEvent.ADDED, onRoomEngineObjectEvent); - useRoomEngineEvent(RoomEngineObjectEvent.REMOVED, onRoomEngineObjectEvent); - useRoomEngineEvent(RoomEngineObjectEvent.PLACED, onRoomEngineObjectEvent); - useRoomEngineEvent(RoomEngineObjectEvent.MOUSE_ENTER, onRoomEngineObjectEvent); - useRoomEngineEvent(RoomEngineObjectEvent.MOUSE_LEAVE, onRoomEngineObjectEvent); - useRoomEngineEvent(RoomEngineObjectEvent.REQUEST_MOVE, onRoomEngineObjectEvent); - useRoomEngineEvent(RoomEngineObjectEvent.REQUEST_ROTATE, onRoomEngineObjectEvent); - useRoomEngineEvent(RoomEngineObjectEvent.REQUEST_MANIPULATION, onRoomEngineObjectEvent); - if(!roomSession) return null; return ( diff --git a/src/views/room/handlers/FurnitureContextMenuWidgetHandler.ts b/src/views/room/handlers/FurnitureContextMenuWidgetHandler.ts index 11080342..b0e8192d 100644 --- a/src/views/room/handlers/FurnitureContextMenuWidgetHandler.ts +++ b/src/views/room/handlers/FurnitureContextMenuWidgetHandler.ts @@ -1,4 +1,4 @@ -import { NitroEvent, RoomEngineTriggerWidgetEvent } from 'nitro-renderer'; +import { NitroEvent, RoomEngineTriggerWidgetEvent, RoomWidgetEnum } from 'nitro-renderer'; import { RoomWidgetUpdateEvent } from '../events'; import { RoomWidgetMessage, RoomWidgetUseProductMessage } from '../messages'; import { RoomWidgetHandler } from './RoomWidgetHandler'; @@ -23,6 +23,11 @@ export class FurnitureContextMenuWidgetHandler extends RoomWidgetHandler return null; } + public get type(): string + { + return RoomWidgetEnum.FURNITURE_CONTEXT_MENU; + } + public get eventTypes(): string[] { return [ diff --git a/src/views/room/handlers/IRoomWidgetHandler.ts b/src/views/room/handlers/IRoomWidgetHandler.ts index 82cea5a6..0c7a7936 100644 --- a/src/views/room/handlers/IRoomWidgetHandler.ts +++ b/src/views/room/handlers/IRoomWidgetHandler.ts @@ -8,6 +8,7 @@ export interface IRoomWidgetHandler processEvent: (event: NitroEvent) => void; processWidgetMessage: (message: RoomWidgetMessage) => RoomWidgetUpdateEvent; container: IRoomWidgetHandlerManager; + type: string; eventTypes: string[]; messageTypes: string[]; } diff --git a/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts b/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts index 6324a380..d75eac3f 100644 --- a/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts +++ b/src/views/room/handlers/RoomWidgetAvatarInfoHandler.ts @@ -1,4 +1,4 @@ -import { NitroEvent, RoomEngineUseProductEvent, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionDanceEvent, RoomSessionUserDataUpdateEvent } from 'nitro-renderer'; +import { NitroEvent, RoomEngineUseProductEvent, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionDanceEvent, RoomSessionUserDataUpdateEvent, RoomWidgetEnum } from 'nitro-renderer'; import { GetRoomEngine, GetRoomSession, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; import { FurniCategory } from '../../inventory/common/FurniCategory'; import { RoomWidgetAvatarInfoEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateUserDataEvent, RoomWidgetUseProductBubbleEvent, UseProductItem } from '../events'; @@ -151,6 +151,11 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler if(useProductBubbles.length) this.container.eventDispatcher.dispatchEvent(new RoomWidgetUseProductBubbleEvent(RoomWidgetUseProductBubbleEvent.USE_PRODUCT_BUBBLES, useProductBubbles)); } + public get type(): string + { + return RoomWidgetEnum.AVATAR_INFO; + } + public get eventTypes(): string[] { return [ diff --git a/src/views/room/handlers/RoomWidgetChatHandler.ts b/src/views/room/handlers/RoomWidgetChatHandler.ts index 63de3b7b..5532ae86 100644 --- a/src/views/room/handlers/RoomWidgetChatHandler.ts +++ b/src/views/room/handlers/RoomWidgetChatHandler.ts @@ -1,4 +1,4 @@ -import { AvatarFigurePartType, AvatarScaleType, AvatarSetType, IAvatarImageListener, INitroPoint, IVector3D, NitroEvent, NitroPoint, PetFigureData, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionChatEvent, SystemChatStyleEnum, TextureUtils, Vector3d } from 'nitro-renderer'; +import { AvatarFigurePartType, AvatarScaleType, AvatarSetType, IAvatarImageListener, INitroPoint, IVector3D, NitroEvent, NitroPoint, PetFigureData, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionChatEvent, RoomWidgetEnum, SystemChatStyleEnum, TextureUtils, Vector3d } from 'nitro-renderer'; import { GetAvatarRenderManager, GetRoomEngine } from '../../../api'; import { LocalizeText } from '../../../utils/LocalizeText'; import { RoomWidgetUpdateChatEvent, RoomWidgetUpdateEvent } from '../events'; @@ -191,6 +191,11 @@ export class RoomWidgetChatHandler extends RoomWidgetHandler implements IAvatarI return false; } + public get type(): string + { + return RoomWidgetEnum.CHAT_WIDGET; + } + public get eventTypes(): string[] { return [ diff --git a/src/views/room/handlers/RoomWidgetChatInputHandler.ts b/src/views/room/handlers/RoomWidgetChatInputHandler.ts index 18b0b2b9..be32fea5 100644 --- a/src/views/room/handlers/RoomWidgetChatInputHandler.ts +++ b/src/views/room/handlers/RoomWidgetChatInputHandler.ts @@ -1,4 +1,4 @@ -import { AvatarExpressionEnum, HabboClubLevelEnum, NitroEvent, RoomControllerLevel, RoomSessionChatEvent, RoomSettingsComposer, RoomZoomEvent } from 'nitro-renderer'; +import { AvatarExpressionEnum, HabboClubLevelEnum, NitroEvent, RoomControllerLevel, RoomSessionChatEvent, RoomSettingsComposer, RoomWidgetEnum, RoomZoomEvent } from 'nitro-renderer'; import { GetRoomEngine, GetSessionDataManager } from '../../../api'; import { SendMessageHook } from '../../../hooks/messages'; import { RoomWidgetFloodControlEvent, RoomWidgetUpdateEvent } from '../events'; @@ -181,6 +181,11 @@ export class RoomWidgetChatInputHandler extends RoomWidgetHandler return null; } + public get type(): string + { + return RoomWidgetEnum.CHAT_INPUT_WIDGET; + } + public get eventTypes(): string[] { return [ diff --git a/src/views/room/handlers/RoomWidgetHandler.ts b/src/views/room/handlers/RoomWidgetHandler.ts index 747ed477..9edf0667 100644 --- a/src/views/room/handlers/RoomWidgetHandler.ts +++ b/src/views/room/handlers/RoomWidgetHandler.ts @@ -22,6 +22,8 @@ export abstract class RoomWidgetHandler implements IRoomWidgetHandler this._container = container; } + public abstract get type(): string; + public abstract get eventTypes(): string[]; public abstract get messageTypes(): string[]; diff --git a/src/views/room/handlers/RoomWidgetHandlerManager.ts b/src/views/room/handlers/RoomWidgetHandlerManager.ts index 7eae5591..e22969b7 100644 --- a/src/views/room/handlers/RoomWidgetHandlerManager.ts +++ b/src/views/room/handlers/RoomWidgetHandlerManager.ts @@ -1,4 +1,4 @@ -import { IEventDispatcher, IRoomSession, NitroEvent } from 'nitro-renderer'; +import { IEventDispatcher, IRoomSession, NitroEvent, RoomEngineTriggerWidgetEvent } from 'nitro-renderer'; import { RoomWidgetUpdateEvent } from '../events'; import { RoomWidgetMessage } from '../messages'; import { IRoomWidgetHandler } from './IRoomWidgetHandler'; @@ -22,6 +22,8 @@ export class RoomWidgetHandlerManager implements IRoomWidgetHandlerManager { const eventTypes = handler.eventTypes; + eventTypes.push(RoomEngineTriggerWidgetEvent.OPEN_WIDGET, RoomEngineTriggerWidgetEvent.CLOSE_WIDGET); + if(eventTypes && eventTypes.length) { for(const name of eventTypes) @@ -76,8 +78,18 @@ export class RoomWidgetHandlerManager implements IRoomWidgetHandlerManager for(const handler of handlers) { if(!handler) continue; + + let dispatch = true; + + if((event.type === RoomEngineTriggerWidgetEvent.OPEN_WIDGET) || (event.type === RoomEngineTriggerWidgetEvent.CLOSE_WIDGET)) + { + if(event instanceof RoomEngineTriggerWidgetEvent) + { + dispatch = (handler.type === event.widget); + } + } - handler.processEvent(event); + if(dispatch) handler.processEvent(event); } } diff --git a/src/views/room/handlers/RoomWidgetInfostandHandler.ts b/src/views/room/handlers/RoomWidgetInfostandHandler.ts index 463955e9..53d4c86b 100644 --- a/src/views/room/handlers/RoomWidgetInfostandHandler.ts +++ b/src/views/room/handlers/RoomWidgetInfostandHandler.ts @@ -1,4 +1,4 @@ -import { IFurnitureData, Nitro, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer'; +import { IFurnitureData, Nitro, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer'; import { GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../events'; import { FriendListSendFriendRequestEvent } from '../../../events/friend-list/FriendListSendFriendRequestEvent'; @@ -757,6 +757,11 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler return -1; } + public get type(): string + { + return RoomWidgetEnum.INFOSTAND; + } + public get eventTypes(): string[] { return [ diff --git a/src/views/room/messages/RoomWidgetFurniToWidgetMessage.ts b/src/views/room/messages/RoomWidgetFurniToWidgetMessage.ts new file mode 100644 index 00000000..59054ff2 --- /dev/null +++ b/src/views/room/messages/RoomWidgetFurniToWidgetMessage.ts @@ -0,0 +1,46 @@ +import { RoomWidgetMessage } from './RoomWidgetMessage'; + +export class RoomWidgetFurniToWidgetMessage extends RoomWidgetMessage +{ + public static REQUEST_CREDITFURNI: string = 'RWFWM_MESSAGE_REQUEST_CREDITFURNI'; + public static REQUEST_STICKIE: string = 'RWFWM_MESSAGE_REQUEST_STICKIE'; + public static REQUEST_PRESENT: string = 'RWFWM_MESSAGE_REQUEST_PRESENT'; + public static REQUEST_TROPHY: string = 'RWFWM_MESSAGE_REQUEST_TROPHY'; + public static REQUEST_TEASER: string = 'RWFWM_MESSAGE_REQUEST_TEASER'; + public static REQUEST_ECOTRONBOX: string = 'RWFWM_MESSAGE_REQUEST_ECOTRONBOX'; + public static REQUEST_DIMMER: string = 'RWFWM_MESSAGE_REQUEST_DIMMER'; + public static REQUEST_PLACEHOLDER: string = 'RWFWM_MESSAGE_REQUEST_PLACEHOLDER'; + public static REQUEST_CLOTHING_CHANGE: string = 'RWFWM_MESSAGE_REQUEST_CLOTHING_CHANGE'; + public static REQUEST_PLAYLIST_EDITOR: string = 'RWFWM_MESSAGE_REQUEST_PLAYLIST_EDITOR'; + public static REQUEST_ACHIEVEMENT_RESOLUTION_ENGRAVING: string = 'RWFWM_WIDGET_MESSAGE_REQUEST_ACHIEVEMENT_RESOLUTION_ENGRAVING'; + public static REQUEST_ACHIEVEMENT_RESOLUTION_FAILED: string = 'RWFWM_WIDGET_MESSAGE_REQUEST_ACHIEVEMENT_RESOLUTION_FAILED'; + public static REQUEST_BADGE_DISPLAY_ENGRAVING: string = 'RWFWM_WIDGET_MESSAGE_REQUEST_BADGE_DISPLAY_ENGRAVING'; + + private _objectId: number; + private _category: number; + private _roomId: number; + + constructor(type: string, objectId: number, category: number, roomId: number) + { + super(type); + + this._objectId = objectId; + this._category = category; + this._roomId = roomId; + } + + public get objectId(): number + { + return this._objectId; + } + + public get category(): number + { + return this._category; + } + + public get roomId(): number + { + return this._roomId; + } +} diff --git a/src/views/room/messages/index.ts b/src/views/room/messages/index.ts index d3ccbe7d..bc86f9f3 100644 --- a/src/views/room/messages/index.ts +++ b/src/views/room/messages/index.ts @@ -6,6 +6,7 @@ export * from './RoomWidgetChatSelectAvatarMessage'; export * from './RoomWidgetChatTypingMessage'; export * from './RoomWidgetDanceMessage'; export * from './RoomWidgetFurniActionMessage'; +export * from './RoomWidgetFurniToWidgetMessage'; export * from './RoomWidgetMessage'; export * from './RoomWidgetRequestWidgetMessage'; export * from './RoomWidgetRoomObjectMessage'; diff --git a/src/views/room/widgets/RoomWidgetsView.tsx b/src/views/room/widgets/RoomWidgetsView.tsx index 9e080424..19e7da1e 100644 --- a/src/views/room/widgets/RoomWidgetsView.tsx +++ b/src/views/room/widgets/RoomWidgetsView.tsx @@ -1,8 +1,10 @@ -import { NitroEvent, RoomEngineDimmerStateEvent, RoomEngineUseProductEvent, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent } from 'nitro-renderer'; +import { RoomEngineDimmerStateEvent, RoomEngineEvent, RoomEngineObjectEvent, RoomEngineUseProductEvent, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent, RoomZoomEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; +import { CanManipulateFurniture, GetRoomEngine, IsFurnitureSelectionDisabled, ProcessRoomObjectOperation } from '../../../api'; import { useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks/events'; import { LocalizeText } from '../../../utils/LocalizeText'; import { useRoomContext } from '../context/RoomContext'; +import { RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent } from '../events'; import { AvatarInfoWidgetView } from './avatar-info/AvatarInfoWidgetView'; import { CameraWidgetView } from './camera/CameraWidgetView'; import { ChatInputView } from './chat-input/ChatInputView'; @@ -13,31 +15,157 @@ import { RoomWidgetViewProps } from './RoomWidgets.types'; export const RoomWidgetsView: FC = props => { - const { widgetHandler = null } = useRoomContext(); + const { roomSession = null, eventDispatcher = null, widgetHandler = null } = useRoomContext(); - const onNitroEvent = useCallback((event: NitroEvent) => + const onRoomEngineEvent = useCallback((event: RoomEngineEvent) => + { + if(!eventDispatcher || RoomId.isRoomPreviewerId(event.roomId)) return; + + switch(event.type) + { + case RoomEngineEvent.NORMAL_MODE: + eventDispatcher.dispatchEvent(new RoomWidgetRoomEngineUpdateEvent(RoomWidgetRoomEngineUpdateEvent.NORMAL_MODE, event.roomId)); + return; + case RoomEngineEvent.GAME_MODE: + eventDispatcher.dispatchEvent(new RoomWidgetRoomEngineUpdateEvent(RoomWidgetRoomEngineUpdateEvent.GAME_MODE, event.roomId)); + return; + case RoomZoomEvent.ROOM_ZOOM: { + const zoomEvent = (event as RoomZoomEvent); + + let zoomLevel = ((zoomEvent.level < 1) ? 0.5 : (1 << (Math.floor(zoomEvent.level) - 1))); + + if(zoomEvent.forceFlip || zoomEvent.asDelta) zoomLevel = zoomEvent.level; + + GetRoomEngine().setRoomInstanceRenderingCanvasScale(event.roomId, 1, zoomLevel, null, null, false, zoomEvent.asDelta); + + return; + } + case RoomEngineDimmerStateEvent.ROOM_COLOR: { + return; + } + } + }, [ eventDispatcher ]); + + useRoomEngineEvent(RoomEngineEvent.NORMAL_MODE, onRoomEngineEvent); + useRoomEngineEvent(RoomEngineEvent.GAME_MODE, onRoomEngineEvent); + useRoomEngineEvent(RoomZoomEvent.ROOM_ZOOM, onRoomEngineEvent); + useRoomEngineEvent(RoomEngineDimmerStateEvent.ROOM_COLOR, onRoomEngineEvent); + + const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) => + { + if(!roomSession || !widgetHandler) return; + + const objectId = event.objectId; + const category = event.category; + + let updateEvent: RoomWidgetRoomObjectUpdateEvent = null; + + switch(event.type) + { + case RoomEngineObjectEvent.SELECTED: + if(!IsFurnitureSelectionDisabled(event)) updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_SELECTED, objectId, category, event.roomId); + break; + case RoomEngineObjectEvent.DESELECTED: + updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, objectId, category, event.roomId); + break; + case RoomEngineObjectEvent.ADDED: { + let addedEventType: string = null; + + switch(category) + { + case RoomObjectCategory.FLOOR: + case RoomObjectCategory.WALL: + addedEventType = RoomWidgetRoomObjectUpdateEvent.FURNI_ADDED; + break; + case RoomObjectCategory.UNIT: + addedEventType = RoomWidgetRoomObjectUpdateEvent.USER_ADDED; + break; + } + + if(addedEventType) updateEvent = new RoomWidgetRoomObjectUpdateEvent(addedEventType, objectId, category, event.roomId); + break; + } + case RoomEngineObjectEvent.REMOVED: { + let removedEventType: string = null; + + switch(category) + { + case RoomObjectCategory.FLOOR: + case RoomObjectCategory.WALL: + removedEventType = RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED; + break; + case RoomObjectCategory.UNIT: + removedEventType = RoomWidgetRoomObjectUpdateEvent.USER_REMOVED; + break; + } + + if(removedEventType) updateEvent = new RoomWidgetRoomObjectUpdateEvent(removedEventType, objectId, category, event.roomId); + break; + } + case RoomEngineObjectEvent.REQUEST_MOVE: + if(CanManipulateFurniture(roomSession, objectId, category)) ProcessRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_MOVE); + break; + case RoomEngineObjectEvent.REQUEST_ROTATE: + if(CanManipulateFurniture(roomSession, objectId, category)) ProcessRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_ROTATE_POSITIVE); + break; + case RoomEngineObjectEvent.REQUEST_MANIPULATION: + if(CanManipulateFurniture(roomSession, objectId, category)) updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_REQUEST_MANIPULATION, objectId, category, event.roomId); + break; + case RoomEngineObjectEvent.MOUSE_ENTER: + updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OVER, objectId, category, event.roomId); + break; + case RoomEngineObjectEvent.MOUSE_LEAVE: + updateEvent = new RoomWidgetRoomObjectUpdateEvent(RoomWidgetRoomObjectUpdateEvent.OBJECT_ROLL_OUT, objectId, category, event.roomId); + break; + case RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY: + case RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM: + widgetHandler.processEvent(event); + break; + } + + if(updateEvent) + { + let dispatchEvent = true; + + if(updateEvent instanceof RoomWidgetRoomObjectUpdateEvent) dispatchEvent = (!RoomId.isRoomPreviewerId(updateEvent.roomId)); + + if(dispatchEvent) widgetHandler.eventDispatcher.dispatchEvent(updateEvent); + } + }, [ roomSession, widgetHandler ]); + + useRoomEngineEvent(RoomEngineObjectEvent.SELECTED, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineObjectEvent.DESELECTED, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineObjectEvent.ADDED, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineObjectEvent.REMOVED, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineObjectEvent.PLACED, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineObjectEvent.REQUEST_MOVE, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineObjectEvent.REQUEST_ROTATE, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineObjectEvent.REQUEST_MANIPULATION, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineObjectEvent.MOUSE_ENTER, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineObjectEvent.MOUSE_LEAVE, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM, onRoomEngineObjectEvent); + + const onRoomSessionEvent = useCallback((event: RoomSessionEvent) => { if(!widgetHandler) return; widgetHandler.processEvent(event); }, [ widgetHandler ]); - useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onNitroEvent); - useRoomSessionManagerEvent(RoomSessionChatEvent.FLOOD_EVENT, onNitroEvent); - useRoomSessionManagerEvent(RoomSessionDanceEvent.RSDE_DANCE, onNitroEvent); - useRoomSessionManagerEvent(RoomSessionUserBadgesEvent.RSUBE_BADGES, onNitroEvent); - useRoomSessionManagerEvent(RoomSessionDoorbellEvent.DOORBELL, onNitroEvent); - useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_REJECTED, onNitroEvent); - useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_ACCEPTED, onNitroEvent); - useRoomSessionManagerEvent(RoomSessionDimmerPresetsEvent.ROOM_DIMMER_PRESETS, onNitroEvent); - useRoomSessionManagerEvent(RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST, onNitroEvent); - useRoomSessionManagerEvent(RoomSessionPresentEvent.RSPE_PRESENT_OPENED, onNitroEvent); - useRoomSessionManagerEvent(RoomSessionPetInfoUpdateEvent.PET_INFO, onNitroEvent); - useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY, onNitroEvent); - useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM, onNitroEvent); - useRoomEngineEvent(RoomEngineDimmerStateEvent.ROOM_COLOR, onNitroEvent); + useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionChatEvent.FLOOD_EVENT, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionDanceEvent.RSDE_DANCE, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionUserBadgesEvent.RSUBE_BADGES, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionDoorbellEvent.DOORBELL, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_REJECTED, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_ACCEPTED, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionDimmerPresetsEvent.ROOM_DIMMER_PRESETS, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionFriendRequestEvent.RSFRE_FRIEND_REQUEST, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionPresentEvent.RSPE_PRESENT_OPENED, onRoomSessionEvent); + useRoomSessionManagerEvent(RoomSessionPetInfoUpdateEvent.PET_INFO, onRoomSessionEvent); - const onRoomErrorEvent = useCallback((event: RoomSessionEvent) => + const onRoomSessionErrorMessageEvent = useCallback((event: RoomSessionErrorMessageEvent) => { if(!event) return; @@ -88,18 +216,18 @@ export const RoomWidgetsView: FC = props => } }, []); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_KICKED, onRoomErrorEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_PETS_FORBIDDEN_IN_HOTEL, onRoomErrorEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_PETS_FORBIDDEN_IN_FLAT, onRoomErrorEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_MAX_PETS, onRoomErrorEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_MAX_NUMBER_OF_OWN_PETS, onRoomErrorEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_NO_FREE_TILES_FOR_PET, onRoomErrorEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_SELECTED_TILE_NOT_FREE_FOR_PET, onRoomErrorEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOTS_FORBIDDEN_IN_HOTEL, onRoomErrorEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOTS_FORBIDDEN_IN_FLAT, onRoomErrorEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOT_LIMIT_REACHED, onRoomErrorEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_SELECTED_TILE_NOT_FREE_FOR_BOT, onRoomErrorEvent); - useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOT_NAME_NOT_ACCEPTED, onRoomErrorEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_KICKED, onRoomSessionErrorMessageEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_PETS_FORBIDDEN_IN_HOTEL, onRoomSessionErrorMessageEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_PETS_FORBIDDEN_IN_FLAT, onRoomSessionErrorMessageEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_MAX_PETS, onRoomSessionErrorMessageEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_MAX_NUMBER_OF_OWN_PETS, onRoomSessionErrorMessageEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_NO_FREE_TILES_FOR_PET, onRoomSessionErrorMessageEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_SELECTED_TILE_NOT_FREE_FOR_PET, onRoomSessionErrorMessageEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOTS_FORBIDDEN_IN_HOTEL, onRoomSessionErrorMessageEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOTS_FORBIDDEN_IN_FLAT, onRoomSessionErrorMessageEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOT_LIMIT_REACHED, onRoomSessionErrorMessageEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_SELECTED_TILE_NOT_FREE_FOR_BOT, onRoomSessionErrorMessageEvent); + useRoomSessionManagerEvent(RoomSessionErrorMessageEvent.RSEME_BOT_NAME_NOT_ACCEPTED, onRoomSessionErrorMessageEvent); if(!widgetHandler) return null; diff --git a/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.tsx b/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.tsx index 4935a64d..84a4a0c4 100644 --- a/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.tsx +++ b/src/views/room/widgets/avatar-info/views/pet/AvatarInfoWidgetPetView.tsx @@ -116,9 +116,10 @@ export const AvatarInfoWidgetPetView: FC = props = } { (mode === _Str_5818) && <> - processAction('mount') }> - { LocalizeText('infostand.button.mount') } - + { !!petData.publiclyRideable && + processAction('mount') }> + { LocalizeText('infostand.button.mount') } + } { (respectsLeft > 0) && processAction('respect') }> { LocalizeText('infostand.button.petrespect', [ 'count' ], [ respectsLeft.toString() ]) } From 183f4f6d53dc5d56f87de87455035513212e1564 Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 16 Jul 2021 13:17:52 -0400 Subject: [PATCH 47/72] Add unseen tracker --- public/configuration.json | 1 + src/assets/styles/index.scss | 1 + src/assets/styles/slider.scss | 54 +++++++ .../inventory/UnseenItemTrackerUpdateEvent.ts | 20 +++ src/events/inventory/index.ts | 1 + .../card/grid/item/NitroCardGridItemView.scss | 6 +- .../card/grid/item/NitroCardGridItemView.tsx | 4 +- .../grid/item/NitroCardGridItemView.types.ts | 1 + .../card/header/NitroCardHeaderView.scss | 6 + .../card/header/NitroCardHeaderView.tsx | 2 +- .../tabs/tabs-item/NitroCardTabsItemView.scss | 7 + .../tabs/tabs-item/NitroCardTabsItemView.tsx | 8 +- .../tabs-item/NitroCardTabsItemView.types.ts | 1 + .../inventory/InventoryMessageHandler.tsx | 31 +++- src/views/inventory/InventoryView.tsx | 56 ++++++- src/views/inventory/common/BadgeItem.ts | 26 ++++ src/views/inventory/common/BotUtilities.ts | 19 ++- .../inventory/common/FurnitureUtilities.ts | 33 ++-- src/views/inventory/common/GroupItem.ts | 2 +- src/views/inventory/common/PetUtilities.ts | 8 +- .../common/unseen/IUnseenItemTracker.ts | 13 ++ .../common/unseen/UnseenItemCategory.ts | 10 ++ .../common/unseen/UnseenItemTracker.ts | 145 ++++++++++++++++++ .../inventory/context/InventoryContext.tsx | 3 +- .../context/InventoryContext.types.ts | 2 + .../reducers/InventoryBotReducer.tsx | 4 +- .../reducers/InventoryFurnitureReducer.tsx | 6 +- .../reducers/InventoryPetReducer.tsx | 4 +- .../views/bot/item/InventoryBotItemView.tsx | 11 +- .../furniture/InventoryFurnitureView.tsx | 2 +- .../item/InventoryFurnitureItemView.tsx | 11 +- .../views/pet/item/InventoryPetItemView.tsx | 11 +- src/views/room-host/RoomHostView.tsx | 3 +- src/views/room-host/RoomHostView.types.ts | 4 - src/views/room/RoomColorView.tsx | 67 +++++--- ...WidgetUpdateBackgroundColorPreviewEvent.ts | 35 +++++ src/views/room/events/index.ts | 1 + src/views/room/widgets/RoomWidgetsView.tsx | 6 +- .../context/CameraWidgetContext.types.ts | 2 +- .../furniture/FurnitureWidgetsView.tsx | 2 + .../FurnitureBackgroundColorView.tsx | 111 ++++++++++---- .../FurnitureCustomStackHeightView.tsx | 49 ++++++ .../widgets/infostand/InfoStandWidgetView.tsx | 3 +- .../infostand/InfoStandWidgetView.types.ts | 6 - .../shared/furni-image/FurniImageView.tsx | 3 +- .../room-previewer/RoomPreviewerView.tsx | 4 +- src/views/toolbar/ToolbarView.scss | 5 +- src/views/toolbar/ToolbarView.tsx | 60 +++++++- 48 files changed, 741 insertions(+), 129 deletions(-) create mode 100644 src/assets/styles/slider.scss create mode 100644 src/events/inventory/UnseenItemTrackerUpdateEvent.ts create mode 100644 src/views/inventory/common/BadgeItem.ts create mode 100644 src/views/inventory/common/unseen/IUnseenItemTracker.ts create mode 100644 src/views/inventory/common/unseen/UnseenItemCategory.ts create mode 100644 src/views/inventory/common/unseen/UnseenItemTracker.ts delete mode 100644 src/views/room-host/RoomHostView.types.ts create mode 100644 src/views/room/events/RoomWidgetUpdateBackgroundColorPreviewEvent.ts create mode 100644 src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx delete mode 100644 src/views/room/widgets/infostand/InfoStandWidgetView.types.ts diff --git a/public/configuration.json b/public/configuration.json index b7972877..8180a6a8 100644 --- a/public/configuration.json +++ b/public/configuration.json @@ -750,6 +750,7 @@ "${images.url}/additions/number_3.png", "${images.url}/additions/number_4.png", "${images.url}/additions/number_5.png", + "${images.url}/additions/pet_experience_bubble.png", "${images.url}/loading_icon.png", "${images.url}/clear_icon.png", "${images.url}/big_arrow.png" diff --git a/src/assets/styles/index.scss b/src/assets/styles/index.scss index ccfaba62..015324b5 100644 --- a/src/assets/styles/index.scss +++ b/src/assets/styles/index.scss @@ -5,6 +5,7 @@ @import './fontawesome/brands'; @import './fontawesome/regular'; @import './scrollbars'; +@import './slider'; @import './grid'; @import './icons'; @import './utils'; diff --git a/src/assets/styles/slider.scss b/src/assets/styles/slider.scss new file mode 100644 index 00000000..a9bb5e64 --- /dev/null +++ b/src/assets/styles/slider.scss @@ -0,0 +1,54 @@ +.nitro-slider { + display: flex; + align-items: center; + width: 100%; + height: 25px; + + .track { + height: 3px; + border-radius: $border-radius; + overflow: hidden; + + &.track-0 { + background-color: $primary; + } + + &.track-1 { + background-color: $muted; + } + } + + .thumb { + border-radius: 50%; + width: 25px; + height: 25px; + background-color: gray; + font-size: 10px; + text-align: center; + line-height: 25px; + padding: 0 3px; + + &:hover, + .active { + cursor: pointer; + } + + &.active { + outline: none; + } + + &.degree { + + &:after { + content: "\00b0" + } + } + + &.percent { + + &:after { + content: "\0025" + } + } + } +} diff --git a/src/events/inventory/UnseenItemTrackerUpdateEvent.ts b/src/events/inventory/UnseenItemTrackerUpdateEvent.ts new file mode 100644 index 00000000..c1302e1b --- /dev/null +++ b/src/events/inventory/UnseenItemTrackerUpdateEvent.ts @@ -0,0 +1,20 @@ +import { NitroEvent } from 'nitro-renderer'; + +export class UnseenItemTrackerUpdateEvent extends NitroEvent +{ + public static UPDATE_COUNT: string = 'UITUE_UPDATE_COUNTER'; + + private _count: number; + + constructor(count: number) + { + super(UnseenItemTrackerUpdateEvent.UPDATE_COUNT); + + this._count = count; + } + + public get count(): number + { + return this._count; + } +} diff --git a/src/events/inventory/index.ts b/src/events/inventory/index.ts index e795837f..2b21bce9 100644 --- a/src/events/inventory/index.ts +++ b/src/events/inventory/index.ts @@ -1,3 +1,4 @@ export * from './InventoryEvent'; export * from './InventoryTradeRequestEvent'; export * from './InventoryTradeStartEvent'; +export * from './UnseenItemTrackerUpdateEvent'; diff --git a/src/layout/card/grid/item/NitroCardGridItemView.scss b/src/layout/card/grid/item/NitroCardGridItemView.scss index 988d0535..2ff2f0fd 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.scss +++ b/src/layout/card/grid/item/NitroCardGridItemView.scss @@ -6,7 +6,7 @@ width: 100%; height: 100%; border-color: $grid-border-color !important; - background-color: $grid-bg-color !important; + background-color: $grid-bg-color; background-position: center; background-repeat: no-repeat; overflow: hidden; @@ -15,6 +15,10 @@ border-color: $grid-active-border-color !important; background-color: $grid-active-bg-color !important; } + + &.unseen { + background-color: rgba($success, 0.4); + } .badge { top: 2px; diff --git a/src/layout/card/grid/item/NitroCardGridItemView.tsx b/src/layout/card/grid/item/NitroCardGridItemView.tsx index 904c4fea..985a24bd 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.tsx +++ b/src/layout/card/grid/item/NitroCardGridItemView.tsx @@ -4,13 +4,13 @@ import { NitroCardGridItemViewProps } from './NitroCardGridItemView.types'; export const NitroCardGridItemView: FC = props => { - const { itemActive = false, itemCount = 1, itemUnique = false, itemUniqueNumber = 0, itemImage = null, className = '', style = {}, children = null, ...rest } = props; + const { itemImage = null, itemActive = false, itemCount = 1, itemUnique = false, itemUniqueNumber = 0, itemUnseen = false, className = '', style = {}, children = null, ...rest } = props; const imageUrl = `url(${ itemImage })`; return (
-
+
{ (itemCount > 1) && { itemCount } } { itemUnique && diff --git a/src/layout/card/grid/item/NitroCardGridItemView.types.ts b/src/layout/card/grid/item/NitroCardGridItemView.types.ts index 20bda705..da6295c3 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.types.ts +++ b/src/layout/card/grid/item/NitroCardGridItemView.types.ts @@ -7,4 +7,5 @@ export interface NitroCardGridItemViewProps extends DetailsHTMLAttributes = props =>
-
{ headerText }
+
{ headerText }
event.stopPropagation() } onClick={ onCloseClick }>
diff --git a/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.scss b/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.scss index 8cac99e3..bbd3c283 100644 --- a/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.scss +++ b/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.scss @@ -3,4 +3,11 @@ &:last-child() { margin-right: 0 !important; } + + .count { + color: $white; + font-size: 10px; + line-height: 10px; + padding: 2px 3px; + } } diff --git a/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.tsx b/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.tsx index 43595ae0..d907ad36 100644 --- a/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.tsx +++ b/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.tsx @@ -4,11 +4,15 @@ import { NitroCardTabsItemViewProps } from './NitroCardTabsItemView.types'; export const NitroCardTabsItemView: FC = props => { - const { children = null, isActive = false, onClick = null } = props; + const { children = null, isActive = false, count = 0, onClick = null } = props; return (
  • - { children } + + { children } + { (count > 0) && + { count } } +
  • ); } diff --git a/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.types.ts b/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.types.ts index 4da57987..8c47b917 100644 --- a/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.types.ts +++ b/src/layout/card/tabs/tabs-item/NitroCardTabsItemView.types.ts @@ -3,5 +3,6 @@ import { MouseEventHandler } from 'react'; export interface NitroCardTabsItemViewProps { isActive?: boolean; + count?: number; onClick?: MouseEventHandler; } diff --git a/src/views/inventory/InventoryMessageHandler.tsx b/src/views/inventory/InventoryMessageHandler.tsx index e00fb7f4..36b442a8 100644 --- a/src/views/inventory/InventoryMessageHandler.tsx +++ b/src/views/inventory/InventoryMessageHandler.tsx @@ -1,4 +1,4 @@ -import { AdvancedMap, BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory, TradingAcceptEvent, TradingCloseEvent, TradingCompletedEvent, TradingConfirmationEvent, TradingListItemEvent, TradingNotOpenEvent, TradingOpenEvent, TradingOpenFailedEvent, TradingOtherNotAllowedEvent, TradingYouAreNotAllowedEvent } from 'nitro-renderer'; +import { AdvancedMap, BadgesEvent, BotAddedToInventoryEvent, BotInventoryMessageEvent, BotRemovedFromInventoryEvent, FurnitureListAddOrUpdateEvent, FurnitureListEvent, FurnitureListInvalidateEvent, FurnitureListItemParser, FurnitureListRemovedEvent, FurniturePostItPlacedEvent, PetAddedToInventoryEvent, PetData, PetInventoryEvent, PetRemovedFromInventory, TradingAcceptEvent, TradingCloseEvent, TradingCompletedEvent, TradingConfirmationEvent, TradingListItemEvent, TradingNotOpenEvent, TradingOpenEvent, TradingOpenFailedEvent, TradingOtherNotAllowedEvent, TradingYouAreNotAllowedEvent, UnseenItemsEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; import { GetRoomSession, GetSessionDataManager } from '../../api'; import { CreateMessageHook } from '../../hooks/messages/message-event'; @@ -17,7 +17,7 @@ let petMsgFragments: Map[] = null; export const InventoryMessageHandler: FC = props => { - const { dispatchFurnitureState = null, dispatchBotState = null, dispatchPetState = null, dispatchBadgeState = null } = useInventoryContext(); + const { dispatchFurnitureState = null, dispatchBotState = null, dispatchPetState = null, dispatchBadgeState = null, unseenTracker = null } = useInventoryContext(); const onFurnitureListAddOrUpdateEvent = useCallback((event: FurnitureListAddOrUpdateEvent) => { @@ -43,9 +43,9 @@ export const InventoryMessageHandler: FC = props = dispatchFurnitureState({ type: InventoryFurnitureActions.PROCESS_FRAGMENT, - payload: { fragment } + payload: { fragment, unseenTracker } }); - }, [ dispatchFurnitureState ]); + }, [ unseenTracker, dispatchFurnitureState ]); const onFurnitureListInvalidateEvent = useCallback((event: FurnitureListInvalidateEvent) => { @@ -82,9 +82,9 @@ export const InventoryMessageHandler: FC = props = dispatchBotState({ type: InventoryBotActions.PROCESS_FRAGMENT, - payload: { fragment } + payload: { fragment, unseenTracker } }); - }, [ dispatchBotState ]); + }, [ dispatchBotState, unseenTracker ]); const onBotAddedToInventoryEvent = useCallback((event: BotAddedToInventoryEvent) => { @@ -122,9 +122,9 @@ export const InventoryMessageHandler: FC = props = dispatchPetState({ type: InventoryPetActions.PROCESS_FRAGMENT, - payload: { fragment } + payload: { fragment, unseenTracker } }); - }, [dispatchPetState ]); + }, [ dispatchPetState, unseenTracker ]); const onPetAddedToInventoryEvent = useCallback((event: PetAddedToInventoryEvent) => { @@ -294,6 +294,20 @@ export const InventoryMessageHandler: FC = props = console.log(parser); }, []); + const onUnseenItemsEvent = useCallback((event: UnseenItemsEvent) => + { + const parser = event.getParser(); + + console.log(parser); + + for(const category of parser.categories) + { + const itemIds = parser.getItemsByCategory(category); + + unseenTracker.addItems(category, itemIds); + } + }, [ unseenTracker ]); + CreateMessageHook(FurnitureListAddOrUpdateEvent, onFurnitureListAddOrUpdateEvent); CreateMessageHook(FurnitureListEvent, onFurnitureListEvent); CreateMessageHook(FurnitureListInvalidateEvent, onFurnitureListInvalidateEvent); @@ -316,6 +330,7 @@ export const InventoryMessageHandler: FC = props = CreateMessageHook(TradingOpenFailedEvent, onTradingOpenFailedEvent); CreateMessageHook(TradingOtherNotAllowedEvent, onTradingOtherNotAllowedEvent); CreateMessageHook(TradingYouAreNotAllowedEvent, onTradingYouAreNotAllowedEvent); + CreateMessageHook(UnseenItemsEvent, onUnseenItemsEvent); return null; } diff --git a/src/views/inventory/InventoryView.tsx b/src/views/inventory/InventoryView.tsx index 8f7b0a9b..3a0a3f63 100644 --- a/src/views/inventory/InventoryView.tsx +++ b/src/views/inventory/InventoryView.tsx @@ -10,6 +10,9 @@ import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, Nitro import { LocalizeText } from '../../utils/LocalizeText'; import { isObjectMoverRequested, setObjectMoverRequested } from './common/InventoryUtilities'; import { TradeState } from './common/TradeState'; +import { IUnseenItemTracker } from './common/unseen/IUnseenItemTracker'; +import { UnseenItemCategory } from './common/unseen/UnseenItemCategory'; +import { UnseenItemTracker } from './common/unseen/UnseenItemTracker'; import { InventoryContextProvider } from './context/InventoryContext'; import { InventoryMessageHandler } from './InventoryMessageHandler'; import { InventoryTabs, InventoryViewProps } from './InventoryView.types'; @@ -23,18 +26,20 @@ import { InventoryFurnitureView } from './views/furniture/InventoryFurnitureView import { InventoryPetView } from './views/pet/InventoryPetView'; import { InventoryTradeView } from './views/trade/InventoryTradeView'; -const tabs = [ InventoryTabs.FURNITURE, InventoryTabs.BOTS, InventoryTabs.PETS, InventoryTabs.BADGES ]; +const TABS = [ InventoryTabs.FURNITURE, InventoryTabs.BOTS, InventoryTabs.PETS, InventoryTabs.BADGES ]; +const UNSEEN_CATEGORIES = [ UnseenItemCategory.FURNI, UnseenItemCategory.BOT, UnseenItemCategory.PET, UnseenItemCategory.BADGE ]; export const InventoryView: FC = props => { const [ isVisible, setIsVisible ] = useState(false); - const [ currentTab, setCurrentTab ] = useState(tabs[0]); + const [ currentTab, setCurrentTab ] = useState(TABS[0]); const [ roomSession, setRoomSession ] = useState(null); const [ roomPreviewer, setRoomPreviewer ] = useState(null); const [ furnitureState, dispatchFurnitureState ] = useReducer(InventoryFurnitureReducer, initialInventoryFurniture); const [ botState, dispatchBotState ] = useReducer(InventoryBotReducer, initialInventoryBot); const [ petState, dispatchPetState ] = useReducer(InventoryPetReducer, initialInventoryPet); const [ badgeState, dispatchBadgeState ] = useReducer(InventoryBadgeReducer, initialInventoryBadge); + const [ unseenTracker ] = useState(new UnseenItemTracker()); const close = useCallback(() => { @@ -119,6 +124,45 @@ export const InventoryView: FC = props => useRoomSessionManagerEvent(RoomSessionEvent.CREATED, onRoomSessionEvent); useRoomSessionManagerEvent(RoomSessionEvent.ENDED, onRoomSessionEvent); + const resetTrackerForTab = useCallback((name: string) => + { + const tabIndex = TABS.indexOf(name); + + if(tabIndex === -1) return; + + const unseenCategory = UNSEEN_CATEGORIES[tabIndex]; + + if(unseenCategory === -1) return; + + const count = unseenTracker.getCount(unseenCategory); + + if(!count) return; + + unseenTracker.resetCategory(unseenCategory); + + switch(unseenCategory) + { + case UnseenItemCategory.FURNI: + for(const groupItem of furnitureState.groupItems) groupItem.hasUnseenItems = false; + + return; + } + }, [ furnitureState.groupItems, unseenTracker ]); + + const switchTab = useCallback((prevTab: string, nextTab: string) => + { + if(nextTab) setCurrentTab(nextTab); + + resetTrackerForTab(prevTab); + }, [ resetTrackerForTab ]); + + useEffect(() => + { + if(isVisible) return; + + if(currentTab) resetTrackerForTab(currentTab); + }, [ currentTab, isVisible, resetTrackerForTab ]); + useEffect(() => { setRoomPreviewer(new RoomPreviewer(GetRoomEngine(), ++RoomPreviewer.PREVIEW_COUNTER)); @@ -143,7 +187,7 @@ export const InventoryView: FC = props => }, [ furnitureState.tradeData, isVisible ]); return ( - + { isVisible && @@ -151,10 +195,12 @@ export const InventoryView: FC = props => { !furnitureState.tradeData && <> - { tabs.map((name, index) => + { TABS.map((name, index) => { + const unseenCount = unseenTracker.getCount(UNSEEN_CATEGORIES[index]); + return ( - setCurrentTab(name) }> + switchTab(currentTab, name) } count={ unseenCount }> { LocalizeText(name) } ); diff --git a/src/views/inventory/common/BadgeItem.ts b/src/views/inventory/common/BadgeItem.ts new file mode 100644 index 00000000..159a87d5 --- /dev/null +++ b/src/views/inventory/common/BadgeItem.ts @@ -0,0 +1,26 @@ +export class BadgeItem +{ + private _code: string; + private _isUnseen: boolean; + + constructor(code: string) + { + this._code = code; + this._isUnseen = false; + } + + public get code(): string + { + return this._code; + } + + public get isUnseen(): boolean + { + return this._isUnseen; + } + + public set isUnseen(flag: boolean) + { + this._isUnseen = flag; + } +} diff --git a/src/views/inventory/common/BotUtilities.ts b/src/views/inventory/common/BotUtilities.ts index ac8f8c78..144c8b33 100644 --- a/src/views/inventory/common/BotUtilities.ts +++ b/src/views/inventory/common/BotUtilities.ts @@ -4,6 +4,8 @@ import { InventoryEvent } from '../../../events'; import { dispatchUiEvent } from '../../../hooks/events/ui/ui-event'; import { BotItem } from './BotItem'; import { getPlacingItemId, setObjectMoverRequested, setPlacingItemId } from './InventoryUtilities'; +import { IUnseenItemTracker } from './unseen/IUnseenItemTracker'; +import { UnseenItemCategory } from './unseen/UnseenItemCategory'; export function cancelRoomObjectPlacement(): void { @@ -45,7 +47,7 @@ function getAllItemIds(botItems: BotItem[]): number[] return itemIds; } -export function processBotFragment(set: BotItem[], fragment: BotData[]): BotItem[] +export function processBotFragment(set: BotItem[], fragment: BotData[], unseenTracker: IUnseenItemTracker): BotItem[] { const existingIds = getAllItemIds(set); const addedDatas: BotData[] = []; @@ -55,12 +57,19 @@ export function processBotFragment(set: BotItem[], fragment: BotData[]): BotItem for(const itemId of existingIds) { + let remove = true; + for(const botData of fragment) { - if(botData.id === itemId) continue; + if(botData.id === itemId) + { + remove = false; - removedIds.push(itemId); + break; + } } + + if(remove) removedIds.push(itemId); } const emptyExistingSet = (existingIds.length === 0); @@ -69,7 +78,7 @@ export function processBotFragment(set: BotItem[], fragment: BotData[]): BotItem for(const botData of addedDatas) { - addSingleBotItem(botData, set, true); + addSingleBotItem(botData, set, unseenTracker.isUnseen(UnseenItemCategory.BOT, botData.id)); } return set; @@ -109,6 +118,8 @@ export function addSingleBotItem(botData: BotData, set: BotItem[], unseen: boole if(unseen) { + botItem.isUnseen = true; + set.unshift(botItem); } else diff --git a/src/views/inventory/common/FurnitureUtilities.ts b/src/views/inventory/common/FurnitureUtilities.ts index 06b13a84..9a96d7c5 100644 --- a/src/views/inventory/common/FurnitureUtilities.ts +++ b/src/views/inventory/common/FurnitureUtilities.ts @@ -7,6 +7,8 @@ import { FurniCategory } from './FurniCategory'; import { FurnitureItem } from './FurnitureItem'; import { GroupItem } from './GroupItem'; import { getPlacingItemId, setObjectMoverRequested, setPlacingItemId } from './InventoryUtilities'; +import { IUnseenItemTracker } from './unseen/IUnseenItemTracker'; +import { UnseenItemCategory } from './unseen/UnseenItemCategory'; export function attemptItemPlacement(groupItem: GroupItem, flag: boolean = false): boolean { @@ -121,7 +123,7 @@ function getAllItemIds(groupItems: GroupItem[]): number[] return itemIds; } -export function processFurniFragment(set: GroupItem[], fragment: Map): GroupItem[] +export function processFurniFragment(set: GroupItem[], fragment: Map, unseenTracker: IUnseenItemTracker): GroupItem[] { const existingIds = getAllItemIds(set); const addedIds: number[] = []; @@ -143,7 +145,7 @@ export function processFurniFragment(set: GroupItem[], fragment: Map): PetItem[] +export function processPetFragment(set: PetItem[], fragment: Map, unseenTracker: IUnseenItemTracker): PetItem[] { const existingIds = getAllItemIds(set); const addedIds: number[] = []; @@ -95,7 +97,7 @@ export function processPetFragment(set: PetItem[], fragment: Map = new Map(); + + public dispose(): void + { + this._unseenItems.clear(); + } + + public resetCategory(category: number): boolean + { + if(!this.getCount(category)) return false; + + this._unseenItems.delete(category); + + this.dispatchUpdateEvent(); + + this.sendResetCategoryMessage(category); + + return true; + } + + public resetItems(category: number, itemIds: number[]): boolean + { + if(!this.getCount(category)) return false; + + const existing = this._unseenItems.get(category); + + for(const itemId of itemIds) + { + existing.splice(existing.indexOf(itemId), 1); + } + + this.dispatchUpdateEvent(); + + this.sendResetItemsMessage(category, itemIds); + + return true; + } + + public resetCategoryIfEmpty(category: number): boolean + { + if(this.getCount(category)) return false; + + this._unseenItems.delete(category); + + this.dispatchUpdateEvent(); + + this.sendResetCategoryMessage(category); + + return true; + } + + public isUnseen(category: number, itemId: number): boolean + { + if(!this._unseenItems.get(category)) return false; + + const items = this._unseenItems.get(category); + + return (items.indexOf(itemId) >= 0); + } + + public removeUnseen(category: number, itemId: number): boolean + { + if(!this._unseenItems.get(category)) return false; + + const items = this._unseenItems.get(category); + const index = items.indexOf(itemId); + + if(index === -1) return false; + + items.splice(index, 1); + + this.dispatchUpdateEvent(); + + return true; + } + + public getIds(category: number): number[] + { + if(!this._unseenItems) return []; + + return this._unseenItems.get(category); + } + + public getCount(category: number): number + { + if(!this._unseenItems.get(category)) return 0; + + return this._unseenItems.get(category).length; + } + + public getFullCount(): number + { + let count = 0; + + for(const key of this._unseenItems.keys()) + { + count += this.getCount(key); + } + + return count; + } + + public addItems(category: number, itemIds: number[]): void + { + if(!itemIds) return; + + let unseenItems = this._unseenItems.get(category); + + if(!unseenItems) + { + unseenItems = []; + + this._unseenItems.set(category, unseenItems); + } + + for(const itemId of itemIds) + { + if(unseenItems.indexOf(itemId) === -1) unseenItems.push(itemId); + } + + this.dispatchUpdateEvent(); + } + + private dispatchUpdateEvent(): void + { + dispatchUiEvent(new UnseenItemTrackerUpdateEvent(this.getFullCount())); + } + + private sendResetCategoryMessage(category: number): void + { + SendMessageHook(new UnseenResetCategoryComposer(category)); + } + + private sendResetItemsMessage(category: number, itemIds: number[]): void + { + SendMessageHook(new UnseenResetItemsComposer(category, ...itemIds)); + } +} diff --git a/src/views/inventory/context/InventoryContext.tsx b/src/views/inventory/context/InventoryContext.tsx index 6500fbc7..5a5dfc4f 100644 --- a/src/views/inventory/context/InventoryContext.tsx +++ b/src/views/inventory/context/InventoryContext.tsx @@ -9,7 +9,8 @@ const InventoryContext = createContext({ petState: null, dispatchPetState: null, badgeState: null, - dispatchBadgeState: null + dispatchBadgeState: null, + unseenTracker: null }); export const InventoryContextProvider: FC = props => diff --git a/src/views/inventory/context/InventoryContext.types.ts b/src/views/inventory/context/InventoryContext.types.ts index 546f2b75..2c47eaf8 100644 --- a/src/views/inventory/context/InventoryContext.types.ts +++ b/src/views/inventory/context/InventoryContext.types.ts @@ -1,4 +1,5 @@ import { Dispatch, ProviderProps } from 'react'; +import { IUnseenItemTracker } from '../common/unseen/IUnseenItemTracker'; import { IInventoryBadgeAction, IInventoryBadgeState } from '../reducers/InventoryBadgeReducer'; import { IInventoryBotAction, IInventoryBotState } from '../reducers/InventoryBotReducer'; import { IInventoryFurnitureAction, IInventoryFurnitureState } from '../reducers/InventoryFurnitureReducer'; @@ -14,6 +15,7 @@ export interface IInventoryContext dispatchPetState: Dispatch; badgeState: IInventoryBadgeState; dispatchBadgeState: Dispatch; + unseenTracker: IUnseenItemTracker; } export interface InventoryContextProps extends ProviderProps diff --git a/src/views/inventory/reducers/InventoryBotReducer.tsx b/src/views/inventory/reducers/InventoryBotReducer.tsx index 3b8cf142..fadf0164 100644 --- a/src/views/inventory/reducers/InventoryBotReducer.tsx +++ b/src/views/inventory/reducers/InventoryBotReducer.tsx @@ -2,6 +2,7 @@ import { BotData } from 'nitro-renderer'; import { Reducer } from 'react'; import { BotItem } from '../common/BotItem'; import { addSingleBotItem, processBotFragment, removeBotItemById } from '../common/BotUtilities'; +import { IUnseenItemTracker } from '../common/unseen/IUnseenItemTracker'; export interface IInventoryBotState { @@ -19,6 +20,7 @@ export interface IInventoryBotAction botId?: number; botData?: BotData; fragment?: BotData[]; + unseenTracker?: IUnseenItemTracker; } } @@ -62,7 +64,7 @@ export const InventoryBotReducer: Reducer; + unseenTracker?: IUnseenItemTracker; } } @@ -62,7 +64,7 @@ export const InventoryPetReducer: Reducer = props => } }, [ isActive, isMouseDown, botItem, dispatchBotState ]); + useEffect(() => + { + if(!isActive) return; + + botItem.isUnseen = false; + }, [ isActive, botItem ]); + return ( - + ); diff --git a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx index be45bc0b..01450fe4 100644 --- a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx +++ b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx @@ -17,7 +17,7 @@ import { InventoryFurnitureSearchView } from './search/InventoryFurnitureSearchV export const InventoryFurnitureView: FC = props => { const { roomSession = null, roomPreviewer = null } = props; - const { furnitureState = null, dispatchFurnitureState = null } = useInventoryContext(); + const { furnitureState = null, dispatchFurnitureState = null, unseenTracker = null } = useInventoryContext(); const { needsFurniUpdate = false, groupItem = null, groupItems = [] } = furnitureState; const [ filteredGroupItems, setFilteredGroupItems ] = useState(groupItems); diff --git a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx index 657ea66c..345fe287 100644 --- a/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx +++ b/src/views/inventory/views/furniture/item/InventoryFurnitureItemView.tsx @@ -1,5 +1,5 @@ import { MouseEventType } from 'nitro-renderer'; -import { FC, MouseEvent, useCallback, useState } from 'react'; +import { FC, MouseEvent, useCallback, useEffect, useState } from 'react'; import { NitroCardGridItemView } from '../../../../../layout/card/grid/item/NitroCardGridItemView'; import { attemptItemPlacement } from '../../../common/FurnitureUtilities'; import { useInventoryContext } from '../../../context/InventoryContext'; @@ -37,7 +37,14 @@ export const InventoryFurnitureItemView: FC = p } }, [ isActive, isMouseDown, groupItem, dispatchFurnitureState ]); + useEffect(() => + { + if(!isActive) return; + + groupItem.hasUnseenItems = false; + }, [ isActive, groupItem ]); + const count = groupItem.getUnlockedCount(); - return ; + return ; } diff --git a/src/views/inventory/views/pet/item/InventoryPetItemView.tsx b/src/views/inventory/views/pet/item/InventoryPetItemView.tsx index 0cbc8e8f..165142f1 100644 --- a/src/views/inventory/views/pet/item/InventoryPetItemView.tsx +++ b/src/views/inventory/views/pet/item/InventoryPetItemView.tsx @@ -1,5 +1,5 @@ import { MouseEventType } from 'nitro-renderer'; -import { FC, MouseEvent, useCallback, useState } from 'react'; +import { FC, MouseEvent, useCallback, useEffect, useState } from 'react'; import { NitroCardGridItemView } from '../../../../../layout/card/grid/item/NitroCardGridItemView'; import { PetImageView } from '../../../../shared/pet-image/PetImageView'; import { attemptPetPlacement } from '../../../common/PetUtilities'; @@ -36,9 +36,16 @@ export const InventoryPetItemView: FC = props => return; } }, [ isActive, isMouseDown, petItem, dispatchPetState ]); + + useEffect(() => + { + if(!isActive) return; + + petItem.isUnseen = false; + }, [ isActive, petItem ]); return ( - + ); diff --git a/src/views/room-host/RoomHostView.tsx b/src/views/room-host/RoomHostView.tsx index 110f03e6..f1bb789d 100644 --- a/src/views/room-host/RoomHostView.tsx +++ b/src/views/room-host/RoomHostView.tsx @@ -6,9 +6,8 @@ import { StartRoomSession } from '../../api/nitro/session/StartRoomSession'; import { useRoomEngineEvent } from '../../hooks/events/nitro/room/room-engine-event'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; import { RoomView } from '../room/RoomView'; -import { RoomHostViewProps } from './RoomHostView.types'; -export const RoomHostView: FC = props => +export const RoomHostView: FC<{}> = props => { const [ roomSession, setRoomSession ] = useState(null); diff --git a/src/views/room-host/RoomHostView.types.ts b/src/views/room-host/RoomHostView.types.ts deleted file mode 100644 index 910ce021..00000000 --- a/src/views/room-host/RoomHostView.types.ts +++ /dev/null @@ -1,4 +0,0 @@ -export interface RoomHostViewProps -{ - -} diff --git a/src/views/room/RoomColorView.tsx b/src/views/room/RoomColorView.tsx index 85474b9c..b7616615 100644 --- a/src/views/room/RoomColorView.tsx +++ b/src/views/room/RoomColorView.tsx @@ -4,12 +4,14 @@ import { GetRoomEngine } from '../../api'; import { UseMountEffect } from '../../hooks'; import { CreateEventDispatcherHook, useRoomEngineEvent } from '../../hooks/events'; import { useRoomContext } from './context/RoomContext'; +import { RoomWidgetUpdateBackgroundColorPreviewEvent } from './events'; import { RoomWidgetUpdateRoomViewEvent } from './events/RoomWidgetUpdateRoomViewEvent'; export const RoomColorView: FC<{}> = props => { const [ roomBackground, setRoomBackground ] = useState(null); - const [ roomBackgroundColor, setRoomBackgroundColor ] = useState(0x000000); + const [ roomBackgroundColor, setRoomBackgroundColor ] = useState(0); + const [ originalRoomBackgroundColor, setOriginalRoomBackgroundColor ] = useState(0); const [ roomFilter, setRoomFilter ] = useState(null); const [ roomFilterColor, setRoomFilterColor ] = useState(-1); const { roomSession = null, canvasId = -1, eventDispatcher = null } = useRoomContext(); @@ -37,20 +39,25 @@ export const RoomColorView: FC<{}> = props => return background; }, [ roomBackground, getRenderingCanvas ]); - const updateRoomBackground = useCallback(() => + const updateRoomBackground = useCallback((color: number) => { const background = getRoomBackground(); if(!background) return; - background.tint = roomBackgroundColor; + if(color === undefined) color = 0x000000; + + background.tint = color; background.width = Nitro.instance.width; background.height = Nitro.instance.height; - }, [ roomBackgroundColor, getRoomBackground ]); + }, [ getRoomBackground ]); - const updateRoomBackgroundColor = useCallback((hue: number, saturation: number, lightness: number) => + const updateRoomBackgroundColor = useCallback((hue: number, saturation: number, lightness: number, original: boolean = false) => { - setRoomBackgroundColor(ColorConverter.hslToRGB(((((hue & 0xFF) << 16) + ((saturation & 0xFF) << 8)) + (lightness & 0xFF)))); + const newColor = ColorConverter.hslToRGB(((((hue & 0xFF) << 16) + ((saturation & 0xFF) << 8)) + (lightness & 0xFF))); + + setRoomBackgroundColor(newColor); + if(original) setOriginalRoomBackgroundColor(newColor); const background = getRoomBackground(); @@ -62,7 +69,7 @@ export const RoomColorView: FC<{}> = props => } else { - updateRoomBackground(); + updateRoomBackground(newColor); background.visible = true; } @@ -89,26 +96,27 @@ export const RoomColorView: FC<{}> = props => return filter; }, [ roomFilter, getRenderingCanvas ]); - const updateRoomFilter = useCallback(() => + const updateRoomFilter = useCallback((color: number) => { const colorMatrix = getRoomFilter(); if(!colorMatrix) return; - const r = ((roomFilterColor >> 16) & 0xFF); - const g = ((roomFilterColor >> 8) & 0xFF); - const b = (roomFilterColor & 0xFF); + const r = ((color >> 16) & 0xFF); + const g = ((color >> 8) & 0xFF); + const b = (color & 0xFF); colorMatrix.red = (r / 255); colorMatrix.green = (g / 255); colorMatrix.blue = (b / 255); - }, [ roomFilterColor, getRoomFilter ]); + }, [ getRoomFilter ]); const updateRoomFilterColor = useCallback((color: number, brightness: number) => { - setRoomFilterColor(ColorConverter.hslToRGB(((ColorConverter.rgbToHSL(color) & 0xFFFF00) + brightness))); + const newColor = ColorConverter.hslToRGB(((ColorConverter.rgbToHSL(color) & 0xFFFF00) + brightness)); - updateRoomFilter(); + setRoomFilterColor(newColor); + updateRoomFilter(newColor); }, [ updateRoomFilter ]); const onRoomEngineEvent = useCallback((event: RoomEngineEvent) => @@ -120,15 +128,15 @@ export const RoomColorView: FC<{}> = props => case RoomObjectHSLColorEnabledEvent.ROOM_BACKGROUND_COLOR: { const hslColorEvent = (event as RoomObjectHSLColorEnabledEvent); - if(hslColorEvent.enable) updateRoomBackgroundColor(hslColorEvent.hue, hslColorEvent.saturation, hslColorEvent.lightness); - else updateRoomBackgroundColor(0, 0, 0); + if(hslColorEvent.enable) updateRoomBackgroundColor(hslColorEvent.hue, hslColorEvent.saturation, hslColorEvent.lightness, true); + else updateRoomBackgroundColor(0, 0, 0, true); return; } case RoomBackgroundColorEvent.ROOM_COLOR: { const colorEvent = (event as RoomBackgroundColorEvent); - if(colorEvent.bgOnly) updateRoomFilterColor(0xFF0000, 0xFF); + if(colorEvent.bgOnly) updateRoomFilterColor(0x000000, 0xFF); else updateRoomFilterColor(colorEvent.color, colorEvent.brightness); return; @@ -141,11 +149,32 @@ export const RoomColorView: FC<{}> = props => const onRoomWidgetUpdateRoomViewEvent = useCallback((event: RoomWidgetUpdateRoomViewEvent) => { - updateRoomBackground(); - }, [ updateRoomBackground ]); + updateRoomBackground(roomBackgroundColor); + }, [ roomBackgroundColor, updateRoomBackground ]); CreateEventDispatcherHook(RoomWidgetUpdateRoomViewEvent.SIZE_CHANGED, eventDispatcher, onRoomWidgetUpdateRoomViewEvent); + const onRoomWidgetUpdateBackgroundColorPreviewEvent = useCallback((event: RoomWidgetUpdateBackgroundColorPreviewEvent) => + { + switch(event.type) + { + case RoomWidgetUpdateBackgroundColorPreviewEvent.PREVIEW: { + updateRoomBackgroundColor(event.hue, event.saturation, event.lightness); + return; + } + case RoomWidgetUpdateBackgroundColorPreviewEvent.CLEAR_PREVIEW: { + const color = originalRoomBackgroundColor; + + setRoomBackgroundColor(color); + updateRoomBackground(color); + return; + } + } + }, [ originalRoomBackgroundColor, updateRoomBackgroundColor, updateRoomBackground ]); + + CreateEventDispatcherHook(RoomWidgetUpdateBackgroundColorPreviewEvent.PREVIEW, eventDispatcher, onRoomWidgetUpdateBackgroundColorPreviewEvent); + CreateEventDispatcherHook(RoomWidgetUpdateBackgroundColorPreviewEvent.CLEAR_PREVIEW, eventDispatcher, onRoomWidgetUpdateBackgroundColorPreviewEvent); + UseMountEffect(updateRoomBackground); return null; diff --git a/src/views/room/events/RoomWidgetUpdateBackgroundColorPreviewEvent.ts b/src/views/room/events/RoomWidgetUpdateBackgroundColorPreviewEvent.ts new file mode 100644 index 00000000..30135a3b --- /dev/null +++ b/src/views/room/events/RoomWidgetUpdateBackgroundColorPreviewEvent.ts @@ -0,0 +1,35 @@ +import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; + +export class RoomWidgetUpdateBackgroundColorPreviewEvent extends RoomWidgetUpdateEvent +{ + public static PREVIEW = 'RWUBCPE_PREVIEW'; + public static CLEAR_PREVIEW = 'RWUBCPE_CLEAR_PREVIEW'; + + private _hue: number; + private _saturation: number; + private _lightness: number; + + constructor(type: string, hue: number = 0, saturation: number = 0, lightness: number = 0) + { + super(type); + + this._hue = hue; + this._saturation = saturation; + this._lightness = lightness; + } + + public get hue(): number + { + return this._hue; + } + + public get saturation(): number + { + return this._saturation; + } + + public get lightness(): number + { + return this._lightness; + } +} diff --git a/src/views/room/events/index.ts b/src/views/room/events/index.ts index 88858e0f..c76fb712 100644 --- a/src/views/room/events/index.ts +++ b/src/views/room/events/index.ts @@ -3,6 +3,7 @@ export * from './RoomWidgetFloodControlEvent'; export * from './RoomWidgetObjectNameEvent'; export * from './RoomWidgetRoomEngineUpdateEvent'; export * from './RoomWidgetRoomObjectUpdateEvent'; +export * from './RoomWidgetUpdateBackgroundColorPreviewEvent'; export * from './RoomWidgetUpdateChatEvent'; export * from './RoomWidgetUpdateChatInputContentEvent'; export * from './RoomWidgetUpdateDanceStatusEvent'; diff --git a/src/views/room/widgets/RoomWidgetsView.tsx b/src/views/room/widgets/RoomWidgetsView.tsx index 19e7da1e..f5bf25fb 100644 --- a/src/views/room/widgets/RoomWidgetsView.tsx +++ b/src/views/room/widgets/RoomWidgetsView.tsx @@ -1,4 +1,4 @@ -import { RoomEngineDimmerStateEvent, RoomEngineEvent, RoomEngineObjectEvent, RoomEngineUseProductEvent, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent, RoomZoomEvent } from 'nitro-renderer'; +import { RoomEngineDimmerStateEvent, RoomEngineEvent, RoomEngineObjectEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent, RoomZoomEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; import { CanManipulateFurniture, GetRoomEngine, IsFurnitureSelectionDisabled, ProcessRoomObjectOperation } from '../../../api'; import { useRoomEngineEvent, useRoomSessionManagerEvent } from '../../../hooks/events'; @@ -119,6 +119,8 @@ export const RoomWidgetsView: FC = props => break; case RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY: case RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM: + case RoomEngineTriggerWidgetEvent.OPEN_WIDGET: + case RoomEngineTriggerWidgetEvent.CLOSE_WIDGET: widgetHandler.processEvent(event); break; } @@ -145,6 +147,8 @@ export const RoomWidgetsView: FC = props => useRoomEngineEvent(RoomEngineObjectEvent.MOUSE_LEAVE, onRoomEngineObjectEvent); useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_INVENTORY, onRoomEngineObjectEvent); useRoomEngineEvent(RoomEngineUseProductEvent.USE_PRODUCT_FROM_ROOM, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineTriggerWidgetEvent.OPEN_WIDGET, onRoomEngineObjectEvent); + useRoomEngineEvent(RoomEngineTriggerWidgetEvent.CLOSE_WIDGET, onRoomEngineObjectEvent); const onRoomSessionEvent = useCallback((event: RoomSessionEvent) => { diff --git a/src/views/room/widgets/camera/context/CameraWidgetContext.types.ts b/src/views/room/widgets/camera/context/CameraWidgetContext.types.ts index f0c3ca0b..8a25cb92 100644 --- a/src/views/room/widgets/camera/context/CameraWidgetContext.types.ts +++ b/src/views/room/widgets/camera/context/CameraWidgetContext.types.ts @@ -1,5 +1,5 @@ +import { IRoomCameraWidgetSelectedEffect } from 'nitro-renderer/src/nitro/camera/IRoomCameraWidgetSelectedEffect'; import { ProviderProps } from 'react'; -import { IRoomCameraWidgetSelectedEffect } from '../../../../../../../nitro-renderer/src/nitro/camera/IRoomCameraWidgetSelectedEffect'; export interface ICameraWidgetContext { diff --git a/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx b/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx index aac85a29..14ba1a55 100644 --- a/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx +++ b/src/views/room/widgets/furniture/FurnitureWidgetsView.tsx @@ -1,6 +1,7 @@ import { FC } from 'react'; import { FurnitureBackgroundColorView } from './background-color/FurnitureBackgroundColorView'; import { FurnitureContextMenuView } from './context-menu/FurnitureContextMenuView'; +import { FurnitureCustomStackHeightView } from './custom-stack-height/FurnitureCustomStackHeightView'; import { FurnitureDimmerView } from './dimmer/FurnitureDimmerView'; import { FurnitureExchangeCreditView } from './exchange-credit/FurnitureExchangeCreditView'; import { FurnitureFriendFurniView } from './friend-furni/FurnitureFriendFurniView'; @@ -17,6 +18,7 @@ export const FurnitureWidgetsView: FC<{}> = props =>
    + diff --git a/src/views/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx b/src/views/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx index d698a70f..7719bf0b 100644 --- a/src/views/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx +++ b/src/views/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx @@ -1,21 +1,29 @@ -import { NitroEvent, RoomControllerLevel, RoomEngineObjectEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer'; -import { FC, useCallback, useState } from 'react'; +import { ApplyTonerComposer, RoomControllerLevel, RoomEngineObjectEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; import { GetRoomEngine, GetSessionDataManager } from '../../../../../api'; +import { SendMessageHook } from '../../../../../hooks'; import { CreateEventDispatcherHook, useRoomEngineEvent } from '../../../../../hooks/events'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout'; import { LocalizeText } from '../../../../../utils/LocalizeText'; import { useRoomContext } from '../../../context/RoomContext'; -import { RoomWidgetRoomObjectUpdateEvent } from '../../../events'; +import { RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateBackgroundColorPreviewEvent } from '../../../events'; export const FurnitureBackgroundColorView: FC<{}> = props => { - const [ furniId, setFurniId ] = useState(-1); const [ objectId, setObjectId ] = useState(-1); const [ hue, setHue ] = useState(0); const [ saturation, setSaturation ] = useState(0); - const [ light, setLight ] = useState(0); + const [ lightness, setLightness ] = useState(0); const { roomSession = null, eventDispatcher = null } = useRoomContext(); + const close = useCallback(() => + { + eventDispatcher.dispatchEvent(new RoomWidgetUpdateBackgroundColorPreviewEvent(RoomWidgetUpdateBackgroundColorPreviewEvent.CLEAR_PREVIEW)); + + setObjectId(-1); + }, [ eventDispatcher ]); + const canOpenBackgroundToner = useCallback(() => { const isRoomOwner = roomSession.isRoomOwner; @@ -25,49 +33,98 @@ export const FurnitureBackgroundColorView: FC<{}> = props => return (isRoomOwner || hasLevel || isGodMode); }, [ roomSession ]); - const onNitroEvent = useCallback((event: NitroEvent) => + const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) => { switch(event.type) { case RoomEngineTriggerWidgetEvent.REQUEST_BACKGROUND_COLOR: { if(!canOpenBackgroundToner()) return; - - const roomEngineObjectEvent = (event as RoomEngineObjectEvent); - const roomObject = GetRoomEngine().getRoomObject(roomEngineObjectEvent.roomId, roomEngineObjectEvent.objectId, roomEngineObjectEvent.category); + + const roomObject = GetRoomEngine().getRoomObject(event.roomId, event.objectId, event.category); const model = roomObject.model; - setFurniId(roomObject.id); - setObjectId(roomObject.instanceId); - setHue(parseInt(model.getValue(RoomObjectVariable.FURNITURE_ROOM_BACKGROUND_COLOR_HUE))); - setSaturation(parseInt(model.getValue(RoomObjectVariable.FURNITURE_ROOM_BACKGROUND_COLOR_SATURATION))); - setLight(parseInt(model.getValue(RoomObjectVariable.FURNITURE_ROOM_BACKGROUND_COLOR_LIGHTNESS))); + setObjectId(roomObject.id); + setHue(parseInt(model.getValue(RoomObjectVariable.FURNITURE_ROOM_BACKGROUND_COLOR_HUE))); + setSaturation(parseInt(model.getValue(RoomObjectVariable.FURNITURE_ROOM_BACKGROUND_COLOR_SATURATION))); + setLightness(parseInt(model.getValue(RoomObjectVariable.FURNITURE_ROOM_BACKGROUND_COLOR_LIGHTNESS))); return; } case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: { - const widgetEvent = (event as RoomWidgetRoomObjectUpdateEvent); + if(objectId !== event.objectId) return; - setObjectId(prevValue => - { - if(prevValue === widgetEvent.id) return null; - - return prevValue; - }); + close(); return; } } - }, [ canOpenBackgroundToner ]); + }, [ objectId, canOpenBackgroundToner, close ]); - useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_BACKGROUND_COLOR, onNitroEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onNitroEvent); + useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_BACKGROUND_COLOR, onRoomEngineObjectEvent); + CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomEngineObjectEvent); + + const processAction = useCallback((name: string) => + { + switch(name) + { + case 'apply': + SendMessageHook(new ApplyTonerComposer(objectId, hue, saturation, lightness)); + break; + case 'toggle': + roomSession.useMultistateItem(objectId); + break; + } + }, [ roomSession, objectId, hue, saturation, lightness ]); + + useEffect(() => + { + if(objectId === -1) return; + + eventDispatcher.dispatchEvent(new RoomWidgetUpdateBackgroundColorPreviewEvent(RoomWidgetUpdateBackgroundColorPreviewEvent.PREVIEW, hue, saturation, lightness)); + }, [ eventDispatcher, objectId, hue, saturation, lightness ]); if(objectId === -1) return null; return ( - - setObjectId(-1) } /> + + - background toner +
    + + setHue(event) } + thumbClassName={ 'thumb degree' } + renderThumb={ (props, state) =>
    { state.valueNow }
    } /> +
    +
    + + setSaturation(event) } + thumbClassName={ 'thumb percent' } + renderThumb={ (props, state) =>
    { state.valueNow }
    } /> +
    +
    + + setLightness(event) } + thumbClassName={ 'thumb percent' } + renderThumb={ (props, state) =>
    { state.valueNow }
    } /> +
    +
    + + +
    ); diff --git a/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx b/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx new file mode 100644 index 00000000..de0fb14c --- /dev/null +++ b/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx @@ -0,0 +1,49 @@ +import { RoomEngineObjectEvent } from 'nitro-renderer'; +import { FC, useCallback, useState } from 'react'; +import { CreateEventDispatcherHook } from '../../../../../hooks/events'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout'; +import { LocalizeText } from '../../../../../utils/LocalizeText'; +import { useRoomContext } from '../../../context/RoomContext'; +import { RoomWidgetRoomObjectUpdateEvent } from '../../../events'; + +export const FurnitureCustomStackHeightView: FC<{}> = props => +{ + const [ objectId, setObjectId ] = useState(-1); + const { roomSession = null, eventDispatcher = null } = useRoomContext(); + + const close = useCallback(() => + { + setObjectId(-1); + }, []); + + const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) => + { + switch(event.type) + { + // case RoomEngineTriggerWidgetEvent.REQUEST_CUSTOM_STACK_HEIGHT: { + // setObjectId(event.objectId); + // return; + // } + case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: { + if(objectId !== event.objectId) return; + + close(); + return; + } + } + }, [ objectId, close ]); + + //useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_CUSTOM_STACK_HEIGHT, onRoomEngineObjectEvent); + CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomEngineObjectEvent); + + if(objectId === -1) return null; + + return ( + + + + custom stack height + + + ); +} diff --git a/src/views/room/widgets/infostand/InfoStandWidgetView.tsx b/src/views/room/widgets/infostand/InfoStandWidgetView.tsx index 2f6b332a..6c3b2827 100644 --- a/src/views/room/widgets/infostand/InfoStandWidgetView.tsx +++ b/src/views/room/widgets/infostand/InfoStandWidgetView.tsx @@ -3,14 +3,13 @@ import { CreateEventDispatcherHook } from '../../../../hooks/events/event-dispat import { useRoomContext } from '../../context/RoomContext'; import { RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../../events'; import { RoomWidgetRoomObjectMessage } from '../../messages'; -import { InfoStandWidgetViewProps } from './InfoStandWidgetView.types'; import { InfoStandWidgetBotView } from './views/bot/InfoStandWidgetBotView'; import { InfoStandWidgetFurniView } from './views/furni/InfoStandWidgetFurniView'; import { InfoStandWidgetPetView } from './views/pet/InfoStandWidgetPetView'; import { InfoStandWidgetRentableBotView } from './views/rentable-bot/InfoStandWidgetRentableBotView'; import { InfoStandWidgetUserView } from './views/user/InfoStandWidgetUserView'; -export const InfoStandWidgetView: FC = props => +export const InfoStandWidgetView: FC<{}> = props => { const { eventDispatcher = null, widgetHandler = null } = useRoomContext(); const [ infoStandEvent, setInfoStandEvent ] = useState(null); diff --git a/src/views/room/widgets/infostand/InfoStandWidgetView.types.ts b/src/views/room/widgets/infostand/InfoStandWidgetView.types.ts deleted file mode 100644 index b87ed575..00000000 --- a/src/views/room/widgets/infostand/InfoStandWidgetView.types.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { RoomWidgetProps } from '../RoomWidgets.types'; - -export interface InfoStandWidgetViewProps extends RoomWidgetProps -{ - -} diff --git a/src/views/shared/furni-image/FurniImageView.tsx b/src/views/shared/furni-image/FurniImageView.tsx index bc85db31..b8378954 100644 --- a/src/views/shared/furni-image/FurniImageView.tsx +++ b/src/views/shared/furni-image/FurniImageView.tsx @@ -1,5 +1,4 @@ import { IGetImageListener, ImageResult, TextureUtils, Vector3d } from 'nitro-renderer'; -import { RenderTexture } from 'pixi.js'; import { FC, useCallback, useEffect, useState } from 'react'; import { GetRoomEngine } from '../../../api'; import { ProductTypeEnum } from '../../catalog/common/ProductTypeEnum'; @@ -17,7 +16,7 @@ export const FurniImageView: FC = props => const furniType = type.toLocaleLowerCase(); const listener: IGetImageListener = { - imageReady: (id: number, texture: RenderTexture, image: HTMLImageElement) => + imageReady: (id, texture, image) => { if(!image && texture) { diff --git a/src/views/shared/room-previewer/RoomPreviewerView.tsx b/src/views/shared/room-previewer/RoomPreviewerView.tsx index baf96f44..cc4a3016 100644 --- a/src/views/shared/room-previewer/RoomPreviewerView.tsx +++ b/src/views/shared/room-previewer/RoomPreviewerView.tsx @@ -1,4 +1,4 @@ -import { ColorConverter, IRoomRenderingCanvas, Nitro } from 'nitro-renderer'; +import { ColorConverter, IRoomRenderingCanvas, Nitro, TextureUtils } from 'nitro-renderer'; import { createRef, FC, useCallback, useEffect, useState } from 'react'; import { RoomPreviewerViewProps } from './RoomPreviewerView.types'; @@ -18,7 +18,7 @@ export const RoomPreviewerView: FC = props => if(!renderingCanvas.canvasUpdated) return; - elementRef.current.style.backgroundImage = `url(${ Nitro.instance.renderer.extract.base64(renderingCanvas.master) })`; + elementRef.current.style.backgroundImage = `url(${ TextureUtils.generateImageUrl(renderingCanvas.master) })`; }, [ roomPreviewer, renderingCanvas, elementRef ]); const setupPreviewer = useCallback(() => diff --git a/src/views/toolbar/ToolbarView.scss b/src/views/toolbar/ToolbarView.scss index 0ec04a74..44abb043 100644 --- a/src/views/toolbar/ToolbarView.scss +++ b/src/views/toolbar/ToolbarView.scss @@ -13,7 +13,7 @@ box-shadow: inset 0px 5px lighten(rgba($dark,.6),2.5), inset 0 -4px darken(rgba($dark,.6),4); #toolbar-chat-input-container { - margin-left: 25px; + margin: 0 10px; } .navigation-items { @@ -31,6 +31,7 @@ cursor: pointer; width: 50px; margin: 0 1px; + position: relative; .toolbar-avatar { height: 50px; @@ -47,6 +48,7 @@ .icon, .toolbar-avatar { + position: relative; transition: transform .2s ease-out; &:hover, &.active { @@ -119,6 +121,7 @@ max-width: 120px; max-height: 150px; z-index: 500; + filter: drop-shadow(2px 1px 0 rgba($white, 1)) drop-shadow(-2px 1px 0 rgba($white, 1)) drop-shadow(0 -2px 0 rgba($white, 1)); } @import './me/ToolbarMeView'; diff --git a/src/views/toolbar/ToolbarView.tsx b/src/views/toolbar/ToolbarView.tsx index ac6e325d..28419e69 100644 --- a/src/views/toolbar/ToolbarView.tsx +++ b/src/views/toolbar/ToolbarView.tsx @@ -1,8 +1,10 @@ +import { Dispose, DropBounce, EaseOut, JumpBy, Motions, NitroToolbarAnimateIconEvent, Queue, Wait } from 'nitro-renderer'; import { UserInfoEvent } from 'nitro-renderer/src/nitro/communication/messages/incoming/user/data/UserInfoEvent'; import { UserInfoDataParser } from 'nitro-renderer/src/nitro/communication/messages/parser/user/data/UserInfoDataParser'; import { FC, useCallback, useState } from 'react'; -import { AvatarEditorEvent, CatalogEvent, FriendListEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent } from '../../events'; -import { dispatchUiEvent } from '../../hooks/events/ui/ui-event'; +import { AvatarEditorEvent, CatalogEvent, FriendListEvent, InventoryEvent, NavigatorEvent, RoomWidgetCameraEvent, UnseenItemTrackerUpdateEvent } from '../../events'; +import { useRoomEngineEvent } from '../../hooks'; +import { dispatchUiEvent, useUiEvent } from '../../hooks/events/ui/ui-event'; import { CreateMessageHook } from '../../hooks/messages/message-event'; import { TransitionAnimation } from '../../layout/transitions/TransitionAnimation'; import { TransitionAnimationTypes } from '../../layout/transitions/TransitionAnimation.types'; @@ -16,8 +18,8 @@ export const ToolbarView: FC = props => const [ userInfo, setUserInfo ] = useState(null); const [ isMeExpanded, setMeExpanded ] = useState(false); + const [ unseenInventoryCount, setUnseenInventoryCount ] = useState(0); - const unseenInventoryCount = 0; const unseenFriendListCount = 0; const unseenAchievementsCount = 0; @@ -28,6 +30,56 @@ export const ToolbarView: FC = props => setUserInfo(parser.userInfo); }, []); + CreateMessageHook(UserInfoEvent, onUserInfoEvent); + + const onUnseenItemTrackerUpdateEvent = useCallback((event: UnseenItemTrackerUpdateEvent) => + { + setUnseenInventoryCount(event.count); + }, []); + + useUiEvent(UnseenItemTrackerUpdateEvent.UPDATE_COUNT, onUnseenItemTrackerUpdateEvent); + + const animationIconToToolbar = useCallback((iconName: string, image: HTMLImageElement, x: number, y: number) => + { + const target = (document.body.getElementsByClassName(iconName)[0] as HTMLElement); + + if(!target) return; + + image.className = 'toolbar-icon-animation'; + image.style.visibility = 'visible'; + image.style.left = (x + 'px'); + image.style.top = (y + 'px'); + + document.body.append(image); + + const targetBounds = target.getBoundingClientRect(); + const imageBounds = image.getBoundingClientRect(); + + const left = (imageBounds.x - targetBounds.x); + const top = (imageBounds.y - targetBounds.y); + const squared = Math.sqrt(((left * left) + (top * top))); + const wait = (500 - Math.abs(((((1 / squared) * 100) * 500) * 0.5))); + const height = 20; + + const motionName = (`ToolbarBouncing[${ iconName }]`); + + if(!Motions.getMotionByTag(motionName)) + { + Motions.runMotion(new Queue(new Wait((wait + 8)), new DropBounce(target, 400, 12))).tag = motionName; + } + + const motion = new Queue(new EaseOut(new JumpBy(image, wait, ((targetBounds.x - imageBounds.x) + height), (targetBounds.y - imageBounds.y), 100, 1), 1), new Dispose(image)); + + Motions.runMotion(motion); + }, []); + + const onNitroToolbarAnimateIconEvent = useCallback((event: NitroToolbarAnimateIconEvent) => + { + animationIconToToolbar('icon-inventory', event.image, event.x, event.y); + }, [ animationIconToToolbar ]); + + useRoomEngineEvent(NitroToolbarAnimateIconEvent.ANIMATE_ICON, onNitroToolbarAnimateIconEvent); + const handleToolbarItemClick = useCallback((item: string) => { switch(item) @@ -54,8 +106,6 @@ export const ToolbarView: FC = props => } }, []); - CreateMessageHook(UserInfoEvent, onUserInfoEvent); - return (
    From b8f5aa93ebbebf88f0e33001e2b6f4acb628a24e Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 16 Jul 2021 13:18:02 -0400 Subject: [PATCH 48/72] Update dependencies --- package-lock.json | 709 ++++++++++++++++++++++++---------------------- package.json | 29 +- 2 files changed, 390 insertions(+), 348 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4bd0f3e9..84714f6c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2015,16 +2015,16 @@ } }, "@testing-library/dom": { - "version": "7.30.3", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.30.3.tgz", - "integrity": "sha512-7JhIg2MW6WPwyikH2iL3o7z+FTVgSOd2jqCwTAHqK7Qal2gRRYiUQyURAxtbK9VXm/UTyG9bRihv8C5Tznr2zw==", + "version": "7.31.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-7.31.2.tgz", + "integrity": "sha512-3UqjCpey6HiTZT92vODYLPxTBWlM8ZOOjr3LX5F37/VRipW2M1kX6I/Cm4VXzteZqfGfagg8yXywpcOgQBlNsQ==", "requires": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", "@types/aria-query": "^4.2.0", "aria-query": "^4.2.2", "chalk": "^4.1.0", - "dom-accessibility-api": "^0.5.4", + "dom-accessibility-api": "^0.5.6", "lz-string": "^1.4.4", "pretty-format": "^26.6.2" }, @@ -2038,9 +2038,9 @@ } }, "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz", + "integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==", "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -2075,9 +2075,9 @@ } }, "@testing-library/jest-dom": { - "version": "5.11.10", - "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.11.10.tgz", - "integrity": "sha512-FuKiq5xuk44Fqm0000Z9w0hjOdwZRNzgx7xGGxQYepWFZy+OYUMOT/wPI4nLYXCaVltNVpU1W/qmD88wLWDsqQ==", + "version": "5.14.1", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-5.14.1.tgz", + "integrity": "sha512-dfB7HVIgTNCxH22M1+KU6viG5of2ldoA5ly8Ar8xkezKHKXjRvznCdbMbqjYGgO2xjRbwnR+rR8MLUIqF3kKbQ==", "requires": { "@babel/runtime": "^7.9.2", "@types/testing-library__jest-dom": "^5.9.1", @@ -2085,6 +2085,7 @@ "chalk": "^3.0.0", "css": "^3.0.0", "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.5.6", "lodash": "^4.17.15", "redent": "^3.0.0" }, @@ -2159,9 +2160,9 @@ } }, "@testing-library/react": { - "version": "11.2.6", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.6.tgz", - "integrity": "sha512-TXMCg0jT8xmuU8BkKMtp8l7Z50Ykew5WNX8UoIKTaLFwKkP2+1YDhOLA2Ga3wY4x29jyntk7EWfum0kjlYiSjQ==", + "version": "11.2.7", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-11.2.7.tgz", + "integrity": "sha512-tzRNp7pzd5QmbtXNG/mhdcl7Awfu/Iz1RaVHY75zTdOkmHCuzMhRL83gWHSgOAcjS3CCbyfwUHMZgRJb4kAfpA==", "requires": { "@babel/runtime": "^7.12.5", "@testing-library/dom": "^7.28.1" @@ -2181,9 +2182,9 @@ "integrity": "sha512-/+CRPXpBDpo2RK9C68N3b2cOvO0Cf5B9aPijHsoDQTHivnGSObdOF2BRQOYjojWTDy6nQvMjmqRXIxH55VjxxA==" }, "@types/aria-query": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.1.tgz", - "integrity": "sha512-S6oPal772qJZHoRZLFc/XoZW2gFvwXusYUmXPXkgxJLuEk2vOt7jc4Yo6z/vtI0EBkbPBVrJJ0B+prLIKiWqHg==" + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-4.2.2.tgz", + "integrity": "sha512-HnYpAE1Y6kRyKM/XkEuiRQhTHvkzMBurTHnpFLYLBGPIylZNPs9jJcuOOYWxPLJCSEtmZT0Y8rHDokKN7rRTig==" }, "@types/babel__core": { "version": "7.1.14", @@ -2294,9 +2295,9 @@ } }, "@types/jest": { - "version": "26.0.22", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.22.tgz", - "integrity": "sha512-eeWwWjlqxvBxc4oQdkueW5OF/gtfSceKk4OnOAGlUSwS/liBRtZppbJuz1YkgbrbfGOoeBHun9fOvXnjNwrSOw==", + "version": "26.0.24", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-26.0.24.tgz", + "integrity": "sha512-E/X5Vib8BWqZNRlDxj9vYXhsDwPYbPINqKF9BsnSoon4RQ0D9moEuLD8txgyypFLH7J4+Lho9Nr/c8H0Fi+17w==", "requires": { "jest-diff": "^26.0.0", "pretty-format": "^26.0.0" @@ -2318,9 +2319,9 @@ "integrity": "sha512-1z8k4wzFnNjVK/tlxvrWuK5WMt6mydWWP7+zvH5eFep4oj+UkrfiJTRtjCeBXNpwaA/FYqqtb4/QS4ianFpIRA==" }, "@types/node": { - "version": "12.20.7", - "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.7.tgz", - "integrity": "sha512-gWL8VUkg8VRaCAUgG9WmhefMqHmMblxe2rVpMF86nZY/+ZysU+BkAp+3cz03AixWDSSz0ks5WX59yAhv/cDwFA==" + "version": "12.20.16", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.16.tgz", + "integrity": "sha512-6CLxw83vQf6DKqXxMPwl8qpF8I7THFZuIwLt4TnNsumxkp1VsRZWT8txQxncT/Rl2UojTsFzWgDG4FRMwafrlA==" }, "@types/normalize-package-data": { "version": "2.4.0", @@ -2348,9 +2349,9 @@ "integrity": "sha512-1HcDas8SEj4z1Wc696tH56G8OlRaH/sqZOynNNB+HF0WOeXPaxTtbYzJY2oEfiUxjSKjhCKr+MvR7dCHcEelug==" }, "@types/react": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.3.tgz", - "integrity": "sha512-wYOUxIgs2HZZ0ACNiIayItyluADNbONl7kt8lkLjVK8IitMH5QMyAh75Fwhmo37r1m7L2JaFj03sIfxBVDvRAg==", + "version": "17.0.14", + "resolved": "https://registry.npmjs.org/@types/react/-/react-17.0.14.tgz", + "integrity": "sha512-0WwKHUbWuQWOce61UexYuWTGuGY/8JvtUe/dtQ6lR4sZ3UiylHotJeWpf3ArP9+DSGUoLY3wbU59VyMrJps5VQ==", "requires": { "@types/prop-types": "*", "@types/scheduler": "*", @@ -2358,17 +2359,17 @@ } }, "@types/react-dom": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.3.tgz", - "integrity": "sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==", + "version": "17.0.9", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.9.tgz", + "integrity": "sha512-wIvGxLfgpVDSAMH5utdL9Ngm5Owu0VsGmldro3ORLXV8CShrL8awVj06NuEXFQ5xyaYfdca7Sgbk/50Ri1GdPg==", "requires": { "@types/react": "*" } }, "@types/react-redux": { - "version": "7.1.16", - "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.16.tgz", - "integrity": "sha512-f/FKzIrZwZk7YEO9E1yoxIuDNRiDducxkFlkw/GNMGEnK9n4K8wJzlJBghpSuOVDgEUHoDkDF7Gi9lHNQR4siw==", + "version": "7.1.18", + "resolved": "https://registry.npmjs.org/@types/react-redux/-/react-redux-7.1.18.tgz", + "integrity": "sha512-9iwAsPyJ9DLTRH+OFeIrm9cAbIj1i2ANL3sKQFATqnPWRbg+jEFXyZOKHiQK/N86pNRXbb4HRxAxo0SIX1XwzQ==", "requires": { "@types/hoist-non-react-statics": "^3.3.0", "@types/react": "*", @@ -2377,18 +2378,18 @@ } }, "@types/react-slider": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@types/react-slider/-/react-slider-1.3.0.tgz", - "integrity": "sha512-Hr+P8wiqYAjeFTlf+NWPVGWW79npC8V7KkZdbPlMqo+iblcopPzE/z0m8503j2YmfxoKJKaPnrJe0a6spXacYQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@types/react-slider/-/react-slider-1.3.1.tgz", + "integrity": "sha512-4X2yK7RyCIy643YCFL+bc6XNmcnBtt8n88uuyihvcn5G7Lut23eNQU3q3KmwF7MWIfKfsW5NxCjw0SeDZRtgaA==", "dev": true, "requires": { "@types/react": "*" } }, "@types/react-transition-group": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.1.tgz", - "integrity": "sha512-vIo69qKKcYoJ8wKCJjwSgCTM+z3chw3g18dkrDfVX665tMH7tmbDxEAnPdey4gTlwZz5QuHGzd+hul0OVZDqqQ==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@types/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-KibDWL6nshuOJ0fu8ll7QnV/LVTo3PzQ9aCPnRUYPfX7eZohHwLIdNHj7pftanREzHNP4/nJa8oeM73uSiavMQ==", "requires": { "@types/react": "*" } @@ -2402,9 +2403,9 @@ } }, "@types/scheduler": { - "version": "0.16.1", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.1.tgz", - "integrity": "sha512-EaCxbanVeyxDRTQBkdLb3Bvl/HK7PBK6UJjsSixB0iHKoWxE5uu2Q/DgtpOhPIojN0Zl1whvOd7PoHs2P0s5eA==" + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.2.tgz", + "integrity": "sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==" }, "@types/source-list-map": { "version": "0.1.2", @@ -2422,9 +2423,9 @@ "integrity": "sha512-0VBprVqfgFD7Ehb2vd8Lh9TG3jP98gvr8rgehQqzztZNI7o8zS8Ad4jyZneKELphpuE212D8J70LnSNQSyO6bQ==" }, "@types/testing-library__jest-dom": { - "version": "5.9.5", - "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.9.5.tgz", - "integrity": "sha512-ggn3ws+yRbOHog9GxnXiEZ/35Mow6YtPZpd7Z5mKDeZS/o7zx3yAle0ov/wjhVB5QT4N2Dt+GNoGCdqkBGCajQ==", + "version": "5.14.0", + "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.0.tgz", + "integrity": "sha512-l2P2GO+hFF4Liye+fAajT1qBqvZOiL79YMpEvgGs1xTK7hECxBI8Wz4J7ntACJNiJ9r0vXQqYovroXRLPDja6A==", "requires": { "@types/jest": "*" } @@ -5273,9 +5274,9 @@ } }, "dom-accessibility-api": { - "version": "0.5.4", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.4.tgz", - "integrity": "sha512-TvrjBckDy2c6v6RLxPv5QXOnU+SmF9nBII5621Ve5fu6Z/BDrENurBEvlC1f44lKEUVqOpK4w9E5Idc5/EgkLQ==" + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.6.tgz", + "integrity": "sha512-DplGLZd8L1lN64jlT27N9TVSESFR5STaEJvX+thCby7fuCHonfPpAlodYc3vuUYbDuDec5w8AMP7oCM5TWFsqw==" }, "dom-align": { "version": "1.12.2", @@ -7787,9 +7788,9 @@ "integrity": "sha512-aqXhGP7//Gui2+UrEtvxZxSquQVXTpZ7KDxfCcKAF3Vysvw0CViVaW9RZ1j1xlIYqaaaipBoqdqeibkc18PNvA==" }, "immutable": { - "version": "4.0.0-rc.12", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.12.tgz", - "integrity": "sha512-0M2XxkZLx/mi3t8NVwIm1g8nHoEmM9p9UBl/G9k4+hm0kBgOVdMV/B3CY5dQ8qG8qc80NN4gDV4HQv6FTJ5q7A==" + "version": "4.0.0-rc.14", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.0.0-rc.14.tgz", + "integrity": "sha512-pfkvmRKJSoW7JFx0QeYlAmT+kNYvn5j0u7bnpNq4N2RCvHSTlLT208G8jgaquNe+Q8kCPHKOSpxJkyvLDpYq0w==" }, "import-cwd": { "version": "2.1.0", @@ -10710,11 +10711,11 @@ "nitro-renderer": { "version": "file:../nitro-renderer", "requires": { - "@pixi/filter-adjustment": "^3.1.1", + "@pixi/filter-adjustment": "^4.1.3", "events": "^3.3.0", "pako": "^2.0.3", - "pixi.js": "^5.3.3", - "tslib": "^2.0.0", + "pixi.js": "^6.0.4", + "tslib": "^2.3.0", "xml2js": "^0.4.23" }, "dependencies": { @@ -10808,353 +10809,385 @@ } }, "@pixi/accessibility": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/accessibility/-/accessibility-5.3.8.tgz", - "integrity": "sha512-DBkUUPIDfaw1hXFLTOsmZ401JSyu286rS2UB79ClxvVtDfGI7pR+Hgq1PuNeoQSiO9Db32W4grvuxYTulO2jkQ==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/accessibility/-/accessibility-6.0.4.tgz", + "integrity": "sha512-S0Co6M+BIx+Yk3INCwGp5Xif0jIv/uj5JPMbctpMV7fSsE3x0nYvcOOAfBjkGhYcXG7fNOGrYLgs5XQOBIWGtA==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/canvas-renderer": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/app": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/app/-/app-5.3.8.tgz", - "integrity": "sha512-eekP/tIPlERZOiWOCVKgOCc66JoAHDP7yT9DBw2LtCKswvP83iwN0PX5YR/u6Z05kUW5y8t4bigfLqEqc4uChw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/app/-/app-6.0.4.tgz", + "integrity": "sha512-+BiuaQtnOBR5/Q8+nXnHE2tuZyuBnqy/cwbIR1ImPnKAs7UaCcRLf1R0RvnRFu4KMP4ozTd810p0k84TzIguTA==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8" + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4" + } + }, + "@pixi/canvas-renderer": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/canvas-renderer/-/canvas-renderer-6.0.4.tgz", + "integrity": "sha512-z2r1nzYsAp9+gipvlFCj0rd0yfjVq1hTQkyWuMbo5TrePdEo3NLRrCUGo1dHJNbeSERpgGNN05OAiGQbAI+AUg==", + "requires": { + "@pixi/constants": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/settings": "6.0.4", + "@pixi/utils": "6.0.4" + } + }, + "@pixi/compressed-textures": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/compressed-textures/-/compressed-textures-6.0.4.tgz", + "integrity": "sha512-AqQPuuXcNrR28YT69SZhRxRRwzqQcQ/QrlexAR9Fohpe+jfDnvlNaIvQQoXU7HxD7huRiQ/dm3nwsLiKPqVoTg==", + "requires": { + "@pixi/constants": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/loaders": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/constants": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/constants/-/constants-5.3.8.tgz", - "integrity": "sha512-vTkgBgiox2pLj2ZK/X37O6rFjsLic6CYa+rSCCMo8lCwipG/dgizYoAVIsmZy30tFgg1xYzI6qOw3MSVXupp8Q==" + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/constants/-/constants-6.0.4.tgz", + "integrity": "sha512-khwRMfuHVdFk93L+bf0mmCwtSloYlfBfjdseIAbJL+VSpeMG1S2DzCYlMCPdp4mvDLU9LvkH2U2leZGEIx5j7g==" }, "@pixi/core": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/core/-/core-5.3.8.tgz", - "integrity": "sha512-mbl7//UbNaIZJbS8R8g5o6cHAMW7xaJWW/dNazSJ9057Fpq5g3e3E2rreNTEILfC29cxm2sXDmgK5a9agoqJaA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/core/-/core-6.0.4.tgz", + "integrity": "sha512-r1ceyAz0z3usUs0uj4u2986vVT2tQixGNin2o9FNhPFDXbN5EaoKHLtrjGBt1iylK/EUH/nfL5zq0SGa/loW0A==", "requires": { - "@pixi/constants": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/runner": "5.3.8", - "@pixi/settings": "5.3.8", - "@pixi/ticker": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/constants": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/runner": "6.0.4", + "@pixi/settings": "6.0.4", + "@pixi/ticker": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/display": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/display/-/display-5.3.8.tgz", - "integrity": "sha512-ch7g63ox3iow/NEGbrArLfUMJVLVF+FpdFAp72uEweIzlcyzOQV6AcQTHtiRy4+tM6LdlcLSJXJISqGKt2R0Dg==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/display/-/display-6.0.4.tgz", + "integrity": "sha512-v6hjx5Gm5aIlLQ7xrsZ2lstI1cv/MtbWXJOhU8LXckkrHHUvAuJgml3+0pcHw8YLuOlepZngUuiqy/XjceVk8A==", "requires": { - "@pixi/math": "5.3.8", - "@pixi/settings": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/math": "6.0.4", + "@pixi/settings": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/extract": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/extract/-/extract-5.3.8.tgz", - "integrity": "sha512-z09D+5qmGQilbBXhR3xlZCixkTb6+1bSo6jGsbQxpu3xaF0ogh1HB76SJ2Wi1vwba9Q/PMb6RlawdEAg+sRFMg==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/extract/-/extract-6.0.4.tgz", + "integrity": "sha512-xf/pnc5od7YJ8zCVIrv1km7i+P+rxYcSrrBI/hqX+qoVsI5EySKInf2GhCKHz4UjOHdSL5aPDnNYvzssNdIpdQ==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/core": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/filter-adjustment": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@pixi/filter-adjustment/-/filter-adjustment-3.1.1.tgz", - "integrity": "sha512-N+qbkofBn5tiGn2Ubg52AEoPOM69VIO5TEHsBtm5oh2S4m/rb6FnnqPji/FzwK89iLvtYmJdbwWAYi87PWnE3Q==" + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@pixi/filter-adjustment/-/filter-adjustment-4.1.3.tgz", + "integrity": "sha512-W+NhPiZRYKoRToa5+tkU95eOw8gnS5dfIp3ZP+pLv2mdER9RI+4xHxp1uLHMqUYZViTaMdZIIoVOuCgHFPYCbQ==" }, "@pixi/filter-alpha": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/filter-alpha/-/filter-alpha-5.3.8.tgz", - "integrity": "sha512-4vOmuWDLBiMbdQ2S3PmxzrzpPOrlzZVZ8iPEkQrBCYZ4dIuZY7NaV+9tneIK66dDfVI6OA8Ai304LH22nhC81Q==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/filter-alpha/-/filter-alpha-6.0.4.tgz", + "integrity": "sha512-MZEfvNPfH2NfrwgqKhwwzurnbLujphx4KNQmS63MEZTvXuQJy16DEOs459APYF6PmeGAGuDPKd5Onk/VbLRUwQ==", "requires": { - "@pixi/core": "5.3.8" + "@pixi/core": "6.0.4" } }, "@pixi/filter-blur": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/filter-blur/-/filter-blur-5.3.8.tgz", - "integrity": "sha512-biNqbfFIDbvOJJ+NiE9G0XojnuMQqtbcaDIiOScRoY3o3yCMjjcUxUMYrZ4xnTGGtEH23OKGUTZVf53qTQ4wiw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/filter-blur/-/filter-blur-6.0.4.tgz", + "integrity": "sha512-Hb14geh8ZKc8jZ4lfKyeWThLMqIvha6DdRUTfiSdKe3L7Q6qwqsb7LPtIrZHAPEQCyFLWbcOvRMy6ZFy0YkpLA==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/settings": "5.3.8" + "@pixi/core": "6.0.4", + "@pixi/settings": "6.0.4" } }, "@pixi/filter-color-matrix": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/filter-color-matrix/-/filter-color-matrix-5.3.8.tgz", - "integrity": "sha512-0Ag08uPKVoHWQSAIhS27Bs/b50NVMZ+3fUdNg9jgyrRthD/Uc2ljfkIJRa95Mj31YJBS15Giu4BGfefpe1i3zw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/filter-color-matrix/-/filter-color-matrix-6.0.4.tgz", + "integrity": "sha512-31Rf9VBo2gqoxiAbD/Z1i+mu1C7uehecoelYQqCIzLjsWisICDTZZjUkMB5GrGzjeSpSqLfB34tlutBSh/r1wg==", "requires": { - "@pixi/core": "5.3.8" + "@pixi/core": "6.0.4" } }, "@pixi/filter-displacement": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/filter-displacement/-/filter-displacement-5.3.8.tgz", - "integrity": "sha512-OQYBK3oOId8VZV7KRYYdt196EYsG0cjAmQQT7P3/IETLIP6Mba+Bd/GtyxGEIBHcb7R5DebuvN4sVQtNgkRKlw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/filter-displacement/-/filter-displacement-6.0.4.tgz", + "integrity": "sha512-Oyk/WbzxlN46d/uB5NtPLfEW2G6ob5XRP+mPVd8yhK38m9Y9rKlcH4jJoWB2niQ+ewkdRfZhuIB+JRdhc9eevg==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/math": "5.3.8" + "@pixi/core": "6.0.4", + "@pixi/math": "6.0.4" } }, "@pixi/filter-fxaa": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/filter-fxaa/-/filter-fxaa-5.3.8.tgz", - "integrity": "sha512-eOfrp46AEjkAM1U+6k9Ga/5ezEwr1+7yGS3VijZBHntZTYKFhmGGOXrQxxL4KuslrfTV/smAflEr22U+A2H98A==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/filter-fxaa/-/filter-fxaa-6.0.4.tgz", + "integrity": "sha512-cO5XuEIq//Wsk4MjrCYuXff+1/Gfc4bkFkMTO5JKvUaDlZzHNykZd5CeAouD2fz7/6/1z0gdWKbBY9IoameBew==", "requires": { - "@pixi/core": "5.3.8" + "@pixi/core": "6.0.4" } }, "@pixi/filter-noise": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/filter-noise/-/filter-noise-5.3.8.tgz", - "integrity": "sha512-+MOz3GpB9XpH7d0B/HAz8zOp164UMKnE64Q9QI094X4KjXWj24RKZea8xFcOaOy9xKi57qqyo+3pLwqFB8ffsw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/filter-noise/-/filter-noise-6.0.4.tgz", + "integrity": "sha512-Fpex0tpKCwZIsN03zAmN7hAOCocFF/w4XVVIkuNgYR5A90OkK+omR6p/fDtlJtlAjWarsWq0y+c5wvvUMfqsmg==", "requires": { - "@pixi/core": "5.3.8" + "@pixi/core": "6.0.4" } }, "@pixi/graphics": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/graphics/-/graphics-5.3.8.tgz", - "integrity": "sha512-auqwS6ZnDlNoerddLCoMpEzgq0o09WHH7XxwfTK75hJwBaFX1RO/nasfvCx2wAtWZxAYCaABfR8WnWZfrsBSqA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/graphics/-/graphics-6.0.4.tgz", + "integrity": "sha512-CybR+DBkGB5llypPeib2A0J13mnPQwlQDqLRhlhXKkYxXQKXlPk5MWA7ZEg+4wKeqUUlrC+k70e5ZFYLC3AgEQ==", "requires": { - "@pixi/constants": "5.3.8", - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/sprite": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/constants": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/sprite": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/interaction": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/interaction/-/interaction-5.3.8.tgz", - "integrity": "sha512-i9KS9TNVK/PEwyjZH2iqui9xroy0R48u/QL4Q8+VQpwbeDlz+WlPWoW5R7rpUwtHd9H6mLWpGR3sdWOmS7fMsA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/interaction/-/interaction-6.0.4.tgz", + "integrity": "sha512-4+FOKDpiF/+F9r3+y81xTBElcLqI3OpeeI9bkIw9pPHA41riXRQv+m0HWz76bGQK7zDAimAV9K2xff7Wa5nSeg==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/ticker": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/ticker": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/loaders": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/loaders/-/loaders-5.3.8.tgz", - "integrity": "sha512-0M2e/gkBBqJW695wz9DcsYN7IY992FKqb9uOEhFFjCn2bkK9WsR6M/JBvTlTk4LOvEg81b1/J51bkucpXWx1Cg==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/loaders/-/loaders-6.0.4.tgz", + "integrity": "sha512-cw8QSkn8l8P06fINfwCZW+vUdhtOJ5G+T2qQm3HIDgI/J1tAsiRj3ufHop8xkHwYXrUeTf1LTqw+QdlZEVpJfg==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/utils": "5.3.8", + "@pixi/constants": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/utils": "6.0.4", "resource-loader": "^3.0.1" } }, "@pixi/math": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/math/-/math-5.3.8.tgz", - "integrity": "sha512-MZekzC9W391KU2NyzbRHrgYfjPKguzU5cRLbaEw9dgDabLh3/Yzob1KVg8dngIITPbi5yBmoX7zh7ZHEA1NRPQ==" + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/math/-/math-6.0.4.tgz", + "integrity": "sha512-UwZ72CeZ2KsS4IlcEXgNiuD88omPk42Dct74+1G+R2+yPI+XRZq+hGQRTle/BbFYjxh9ccdQVyX9ToGv1XTd6Q==" }, "@pixi/mesh": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/mesh/-/mesh-5.3.8.tgz", - "integrity": "sha512-/CQdTypiLgSZqKx9z89cJlLQ8/FaUrc8M3HjmL8Vy5F320ERCR1YLDc6gOzyohK71wDxkUud5VbNz5woQVSBxw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/mesh/-/mesh-6.0.4.tgz", + "integrity": "sha512-uE1Qs4mXy0QVV3yjxlNeqthkXGS6Hkt5uR1fwrvdqxlQRkX69nRq+GZfInuRYDWqwAsl8eZWs7f+pLRDT+HFbA==", "requires": { - "@pixi/constants": "5.3.8", - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/settings": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/constants": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/settings": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/mesh-extras": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/mesh-extras/-/mesh-extras-5.3.8.tgz", - "integrity": "sha512-+lHcmvslKsmlixiJW87/t5diRy7p+tvqQbXMG4/3Vzv3dBEGq453hMIknlLr2xLGyzBtboCHObzwKfeE4tvHTw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/mesh-extras/-/mesh-extras-6.0.4.tgz", + "integrity": "sha512-2fGM8j2NBwPV71SSmMfke1N1oEQ34+J19rdaAb+p1fXex0FafqtXVO49Q8rPMvungKDplMKElzQoaC1G6JGKqA==", "requires": { - "@pixi/constants": "5.3.8", - "@pixi/core": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/mesh": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/constants": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/mesh": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/mixin-cache-as-bitmap": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/mixin-cache-as-bitmap/-/mixin-cache-as-bitmap-5.3.8.tgz", - "integrity": "sha512-Y4z3yvMldRUU99I+FBOl+j+TCq7CXN2ysNED/vMD2YpfilS2/8dQcAqRNEOBXCdSixd6+QHBuc0+PWR6M7irKg==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/mixin-cache-as-bitmap/-/mixin-cache-as-bitmap-6.0.4.tgz", + "integrity": "sha512-b1G5AWsxnw3CxNyaxCWJ1cWPnRECknJQ9B4D8Dy7u/gI2gABVjqz17nNFYnVpcggLlgMTkjX8+/HWnD/vZQkTg==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/settings": "5.3.8", - "@pixi/sprite": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/canvas-renderer": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/settings": "6.0.4", + "@pixi/sprite": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/mixin-get-child-by-name": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/mixin-get-child-by-name/-/mixin-get-child-by-name-5.3.8.tgz", - "integrity": "sha512-6Z4C2SucwC1w2xa260VxU+uIkP8FhwnZWDfY0rxyxecWxvkM7ULsIU9szoUYUJvLJnpxRi4Xb6rXNPxXyzis9Q==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/mixin-get-child-by-name/-/mixin-get-child-by-name-6.0.4.tgz", + "integrity": "sha512-scUMBHlOmW0hpjltn4UCihJZvz3ysDYIW35ma9p9Lso2D9qKjsZpojQ6mc75FVWz53T0BjUmLW8LHA86Jic6MQ==", "requires": { - "@pixi/display": "5.3.8" + "@pixi/display": "6.0.4" } }, "@pixi/mixin-get-global-position": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/mixin-get-global-position/-/mixin-get-global-position-5.3.8.tgz", - "integrity": "sha512-o2ZKmTxDvoibGBZ8LP3qJZ3cHe7L447qsuHPPLYOPmA5hqG49YchwmKMwV6tn96C8yDECaVn429Hu5hZEI7UlA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/mixin-get-global-position/-/mixin-get-global-position-6.0.4.tgz", + "integrity": "sha512-HzaFTMZEZTr6+WYuT9crTjjBYl7/Y/VDB7pWmjnntEdQsa1m0+by7Mnl67L6OSUPsAgW3MMlWirb5tL2zGFC7g==", "requires": { - "@pixi/display": "5.3.8", - "@pixi/math": "5.3.8" + "@pixi/display": "6.0.4", + "@pixi/math": "6.0.4" } }, "@pixi/particles": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/particles/-/particles-5.3.8.tgz", - "integrity": "sha512-XAehJJ9SsLwlZF1Qkkir0ejPZ0YgCg8MbxzmrxBUbhH1NyHJLFm+K2S7Bp12FdR/hZwTENF7GMGVRH+o86u3hw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/particles/-/particles-6.0.4.tgz", + "integrity": "sha512-/57nd+icuPFMNc+SxeUqGoO8ZXEKu9u8h+UI856XF1Rc1jlXzGanGAbp43Llq2LphYqBI8YVftP0QXhewCVjjA==", "requires": { - "@pixi/constants": "5.3.8", - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/constants": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/polyfill": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/polyfill/-/polyfill-5.3.8.tgz", - "integrity": "sha512-AIXfAjYD7dfP2C+TX3482YterwGE876amqmk6EzMZCI3vvsvDJUGT/Dx6lSOU5zbcUbJ9t3Ybz81xQYpaEhv/Q==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/polyfill/-/polyfill-6.0.4.tgz", + "integrity": "sha512-HM27pSl8iduFqUC4Waa9mt/gRKHi8Pr679it84+U4CwXmJ2lw9DL5dZuyU+QzCp2nPEVGMqx8Ig8c7WLUMvnWA==", "requires": { - "es6-promise-polyfill": "^1.2.0", - "object-assign": "^4.1.1" + "object-assign": "^4.1.1", + "promise-polyfill": "^8.2.0" } }, "@pixi/prepare": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/prepare/-/prepare-5.3.8.tgz", - "integrity": "sha512-DbYxQdziypsdQJaRKwdmODkIy2mQHETEFlVWou0XwVy+WB8VBlSnHZ57cVEY8l6Z0hJ93Vo4K6j5qIRi9MRjJA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/prepare/-/prepare-6.0.4.tgz", + "integrity": "sha512-BrOeKC6eZ+sdiqpefUMGXIt/VDiYDqPDP7XUCRmaI8rGTFT6ZAg/XJQENb9TsVen/4dUp+9/1u7HCFO1TEhaWQ==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8", - "@pixi/graphics": "5.3.8", - "@pixi/settings": "5.3.8", - "@pixi/text": "5.3.8", - "@pixi/ticker": "5.3.8" + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4", + "@pixi/graphics": "6.0.4", + "@pixi/settings": "6.0.4", + "@pixi/text": "6.0.4", + "@pixi/ticker": "6.0.4" } }, "@pixi/runner": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/runner/-/runner-5.3.8.tgz", - "integrity": "sha512-6Y9v9OHd5FFv6s0M4AGHnG3qvLiTBM5T5RnlEqMNMsqH6CWSDq0mNJA5HQD65q5ViK8HM6MYPm2nwwkYq5AICQ==" + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/runner/-/runner-6.0.4.tgz", + "integrity": "sha512-ta6r36r2vC+fPB27URpSacPGQDtbJbdUoeGCJWAEwX+QI4vx4C9NYAcB0bIg8TLXiigCfA6by/RMnJ0dBiemFA==" }, "@pixi/settings": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/settings/-/settings-5.3.8.tgz", - "integrity": "sha512-/NSd9v6+IbG3GjzIoNwy7rgPg6kwwWy54pcaiM3Wv3zjkwhkVySK4m3h892Wa2z5lFvrHEH9zewGJwEpUH/FMA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/settings/-/settings-6.0.4.tgz", + "integrity": "sha512-djiIsmULDwcHWNmEiZKm4zyVopu1NL+fClnbBmtDkGZw7nm37y6dOcdpYawJcxvE4/KLm6pspBiRTnrzdlqW7Q==", "requires": { "ismobilejs": "^1.1.0" } }, "@pixi/sprite": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/sprite/-/sprite-5.3.8.tgz", - "integrity": "sha512-r+WeX5cti3VKu6U+hZeSiY4UC8912FjNU7M5bA/gev9CfUKv3fNwKYshPfzOkTPua8dFwI1U6tplYu5rSPMBmw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/sprite/-/sprite-6.0.4.tgz", + "integrity": "sha512-6yMoHmfFhSRERLM1PUXceq9e6e1UH0YJkLoPVLv6gxMunfk6jPXeO8p9dDS2FQ8ZMSkO/16BKq27HIMKvF6Cvg==", "requires": { - "@pixi/constants": "5.3.8", - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/settings": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/constants": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/settings": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/sprite-animated": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/sprite-animated/-/sprite-animated-5.3.8.tgz", - "integrity": "sha512-zLnzmCJJ++Hyyy1LPh5Lt4icPuy8C+vL59yVj3nAYzqq/G26rFuHELexB0iwKBPE9yQYuaUQhFgOPgW4vFqLAw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/sprite-animated/-/sprite-animated-6.0.4.tgz", + "integrity": "sha512-uzNeJiZqcnuRc7HH/HdWxrkU7S3/D57rEGK+AuoaWEE2e2HlBWILGkf78mtqmeIrEChxe2qkOVkf4y3BZkzJVw==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/sprite": "5.3.8", - "@pixi/ticker": "5.3.8" + "@pixi/core": "6.0.4", + "@pixi/sprite": "6.0.4", + "@pixi/ticker": "6.0.4" } }, "@pixi/sprite-tiling": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/sprite-tiling/-/sprite-tiling-5.3.8.tgz", - "integrity": "sha512-SvCAvajihsaNx/xX4s6waEqPLVkI5W86h31kpoqdPj3zXhoLbpZh6t2TWbcRJmgjM1GvBNy14gWtelBq8UF7Mg==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/sprite-tiling/-/sprite-tiling-6.0.4.tgz", + "integrity": "sha512-4TBsKMeGhwmfsVELorSs+zWWBih37Kd0lPQu0uhcHVV1RKtZxZpkgNoyzKS4d+WInNek5F0E592bYsXkbE6Gag==", "requires": { - "@pixi/constants": "5.3.8", - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/sprite": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/constants": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/sprite": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/spritesheet": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/spritesheet/-/spritesheet-5.3.8.tgz", - "integrity": "sha512-KqTsW2LViI1UjZTycfI0x3m+yZqV8zfIm/CiDAmtujUPAu8sU78jzByc8ke7FaFC6waDsfAKTKu4fBqSu7aH1w==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/spritesheet/-/spritesheet-6.0.4.tgz", + "integrity": "sha512-WgOBoi9KvLkHtfSyKSEzjIq6BkLwC+Ckllh+vWgfjfFDhtm7NdOfxW5WVIoCLfyfv5/NSwEMEEffZrcw4zYA/A==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/loaders": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/core": "6.0.4", + "@pixi/loaders": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/text": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/text/-/text-5.3.8.tgz", - "integrity": "sha512-qarv4kXSrtroJy5dbmF0Vld7L8teeQxsV5N1g1Fjhi4uUCb43ioR9euBHIjju33kOLDYYXXw6L78XIe/cW6nIw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/text/-/text-6.0.4.tgz", + "integrity": "sha512-r9UJg8ivWvvS7nNyBaZBKX5zg5UCU37dIYbKXcHyiXnOvXO22tiQBfkPBrZCueeLXRouC9sHmDFya8rb5TE9HA==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/settings": "5.3.8", - "@pixi/sprite": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/core": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/settings": "6.0.4", + "@pixi/sprite": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/text-bitmap": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/text-bitmap/-/text-bitmap-5.3.8.tgz", - "integrity": "sha512-jJVAc/y7Mo/DLw8n14A1AFmhQe8rw5d+vCg/1k4hw0Oru4l2QU/8AA940kPeuky4Sj0hMLf9UWAS6A3gOo5ZTA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/text-bitmap/-/text-bitmap-6.0.4.tgz", + "integrity": "sha512-Nh2PXixqF0LFJ0xwmTib2HVWdhgsHn+dSYMVIec8LndDFQMTBw+X2XP1iHjVm0xhqOVdZI+Qfb2Trc0j2lINrw==", "requires": { - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8", - "@pixi/loaders": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/mesh": "5.3.8", - "@pixi/settings": "5.3.8", - "@pixi/text": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4", + "@pixi/loaders": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/mesh": "6.0.4", + "@pixi/settings": "6.0.4", + "@pixi/text": "6.0.4", + "@pixi/utils": "6.0.4" } }, "@pixi/ticker": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/ticker/-/ticker-5.3.8.tgz", - "integrity": "sha512-WoVi8btR0X2/fXJgt/oRy2gm32ECnibqUkxl0MOcLuxg7cHDZKFA5PwNK/eIx5hZZ2xM/ztoPtEohWV6LqLryw==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/ticker/-/ticker-6.0.4.tgz", + "integrity": "sha512-PkFfPP5vHlgnApLks0Ia0okmFu6KPqBdIyquDqHJAcBdgljedm32KS6K2EH37xelBOzYHScjZ2SQGiiebVfClw==", "requires": { - "@pixi/settings": "5.3.8" + "@pixi/settings": "6.0.4" } }, "@pixi/utils": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/@pixi/utils/-/utils-5.3.8.tgz", - "integrity": "sha512-LljIFFOFcXLyLzXqIYwcXUqz6NsAUbwxb7Som9Gm3i1usGIqPRX4R08Iaf4L6OKA7417gSrRmbYdT0Hje/0ikA==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/@pixi/utils/-/utils-6.0.4.tgz", + "integrity": "sha512-35JTWsAJ8Va0vvtUSQvyOr3kGedGKVuJnHDO89B8C8tSFtMpJYrR44vp1b1p1vOjNak+ulGehZc8LzlCqymViQ==", "requires": { - "@pixi/constants": "5.3.8", - "@pixi/settings": "5.3.8", - "earcut": "^2.1.5", + "@pixi/constants": "6.0.4", + "@pixi/settings": "6.0.4", + "@types/earcut": "^2.1.0", + "earcut": "^2.2.2", "eventemitter3": "^3.1.0", "url": "^0.11.0" } }, + "@types/earcut": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/@types/earcut/-/earcut-2.1.1.tgz", + "integrity": "sha512-w8oigUCDjElRHRRrMvn/spybSMyX8MTkKA5Dv+tS1IE/TgmNZPqUYtvYBXGY8cieSE66gm+szeK+bnbxC2xHTQ==" + }, "@types/json-schema": { "version": "7.0.7", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.7.tgz", @@ -11505,9 +11538,9 @@ } }, "earcut": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.2.tgz", - "integrity": "sha512-eZoZPPJcUHnfRZ0PjLvx2qBordSiO8ofC3vt+qACLM95u+4DovnbYNpQtJh0DNsWj8RnxrQytD4WA8gj5cRIaQ==" + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-2.2.3.tgz", + "integrity": "sha512-iRDI1QeCQIhMCZk48DRDMVgQSSBDmbzzNhnxIo+pwx3swkfjMh6vh0nWLq1NdvGHLKH6wIrAM3vQWeTj6qeoug==" }, "emoji-regex": { "version": "8.0.0", @@ -11522,11 +11555,6 @@ "ansi-colors": "^4.1.1" } }, - "es6-promise-polyfill": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es6-promise-polyfill/-/es6-promise-polyfill-1.2.0.tgz", - "integrity": "sha1-84kl8jyz4+jObNqP93T867sJDN4=" - }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", @@ -12110,44 +12138,45 @@ "integrity": "sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg==" }, "pixi.js": { - "version": "5.3.8", - "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-5.3.8.tgz", - "integrity": "sha512-kDqkWhuAkc42lD+ldVTaS439q7D7uo9FM/wCP26jUNAFlYAp75IcALEgXuBh6HEjp51enGkRvwX9+fIiA5F9ug==", + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/pixi.js/-/pixi.js-6.0.4.tgz", + "integrity": "sha512-zAlwr5x9xytaflmZiZWl/ZhlSf+lZzeJG+Hexa7Buf7cvEhHPfSITy4NNk0+qnMXKooQidikBmypShDsj2jAdg==", "requires": { - "@pixi/accessibility": "5.3.8", - "@pixi/app": "5.3.8", - "@pixi/constants": "5.3.8", - "@pixi/core": "5.3.8", - "@pixi/display": "5.3.8", - "@pixi/extract": "5.3.8", - "@pixi/filter-alpha": "5.3.8", - "@pixi/filter-blur": "5.3.8", - "@pixi/filter-color-matrix": "5.3.8", - "@pixi/filter-displacement": "5.3.8", - "@pixi/filter-fxaa": "5.3.8", - "@pixi/filter-noise": "5.3.8", - "@pixi/graphics": "5.3.8", - "@pixi/interaction": "5.3.8", - "@pixi/loaders": "5.3.8", - "@pixi/math": "5.3.8", - "@pixi/mesh": "5.3.8", - "@pixi/mesh-extras": "5.3.8", - "@pixi/mixin-cache-as-bitmap": "5.3.8", - "@pixi/mixin-get-child-by-name": "5.3.8", - "@pixi/mixin-get-global-position": "5.3.8", - "@pixi/particles": "5.3.8", - "@pixi/polyfill": "5.3.8", - "@pixi/prepare": "5.3.8", - "@pixi/runner": "5.3.8", - "@pixi/settings": "5.3.8", - "@pixi/sprite": "5.3.8", - "@pixi/sprite-animated": "5.3.8", - "@pixi/sprite-tiling": "5.3.8", - "@pixi/spritesheet": "5.3.8", - "@pixi/text": "5.3.8", - "@pixi/text-bitmap": "5.3.8", - "@pixi/ticker": "5.3.8", - "@pixi/utils": "5.3.8" + "@pixi/accessibility": "6.0.4", + "@pixi/app": "6.0.4", + "@pixi/compressed-textures": "6.0.4", + "@pixi/constants": "6.0.4", + "@pixi/core": "6.0.4", + "@pixi/display": "6.0.4", + "@pixi/extract": "6.0.4", + "@pixi/filter-alpha": "6.0.4", + "@pixi/filter-blur": "6.0.4", + "@pixi/filter-color-matrix": "6.0.4", + "@pixi/filter-displacement": "6.0.4", + "@pixi/filter-fxaa": "6.0.4", + "@pixi/filter-noise": "6.0.4", + "@pixi/graphics": "6.0.4", + "@pixi/interaction": "6.0.4", + "@pixi/loaders": "6.0.4", + "@pixi/math": "6.0.4", + "@pixi/mesh": "6.0.4", + "@pixi/mesh-extras": "6.0.4", + "@pixi/mixin-cache-as-bitmap": "6.0.4", + "@pixi/mixin-get-child-by-name": "6.0.4", + "@pixi/mixin-get-global-position": "6.0.4", + "@pixi/particles": "6.0.4", + "@pixi/polyfill": "6.0.4", + "@pixi/prepare": "6.0.4", + "@pixi/runner": "6.0.4", + "@pixi/settings": "6.0.4", + "@pixi/sprite": "6.0.4", + "@pixi/sprite-animated": "6.0.4", + "@pixi/sprite-tiling": "6.0.4", + "@pixi/spritesheet": "6.0.4", + "@pixi/text": "6.0.4", + "@pixi/text-bitmap": "6.0.4", + "@pixi/ticker": "6.0.4", + "@pixi/utils": "6.0.4" } }, "prelude-ls": { @@ -12160,6 +12189,11 @@ "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==" }, + "promise-polyfill": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/promise-polyfill/-/promise-polyfill-8.2.0.tgz", + "integrity": "sha512-k/TC0mIcPVF6yHhUvwAp7cvL6I2fFV7TzF1DuGPI8mBh4QQazf36xCKEHKTZKRysEoTQoQdKyP25J8MPJp7j5g==" + }, "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", @@ -12378,9 +12412,9 @@ } }, "tslib": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.1.0.tgz", - "integrity": "sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==" + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" }, "tsutils": { "version": "3.21.0", @@ -15031,6 +15065,14 @@ "react-async-script": "^1.1.1" } }, + "react-input-autosize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/react-input-autosize/-/react-input-autosize-3.0.0.tgz", + "integrity": "sha512-nL9uS7jEs/zu8sqwFE5MAPx6pPkNAriACQ2rGLlqmKr2sPGtN7TXTyDdQt4lbNXVx7Uzadb40x8qotIuru6Rhg==", + "requires": { + "prop-types": "^15.5.8" + } + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", @@ -15057,9 +15099,9 @@ } }, "react-redux": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.3.tgz", - "integrity": "sha512-ZhAmQ1lrK+Pyi0ZXNMUZuYxYAZd59wFuVDGUt536kSGdD0ya9Q7BfsE95E3TsFLE3kOSFp5m6G5qbatE+Ic1+w==", + "version": "7.2.4", + "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.4.tgz", + "integrity": "sha512-hOQ5eOSkEJEXdpIKbnRyl04LhaWabkDPV+Ix97wqQX3T3d2NQ8DUblNXXtNMavc7DpswyQM6xfaN4HQDKNY2JA==", "requires": { "@babel/runtime": "^7.12.1", "@types/react-redux": "^7.1.16", @@ -15140,10 +15182,15 @@ "workbox-webpack-plugin": "5.1.4" } }, + "react-slider": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/react-slider/-/react-slider-1.3.1.tgz", + "integrity": "sha512-bD8hHJJUgAHI8g1F6PY6432l+Dmcs2fqzUwDhd+0HWDdvfjwNoXRNC2cL9OWyGTjYlJM92A8nF/w1X4pyHfytQ==" + }, "react-transition-group": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.1.tgz", - "integrity": "sha512-Djqr7OQ2aPUiYurhPalTrVy9ddmFCCzwhqQmtN+J3+3DzLO209Fdr70QrN8Z3DsglWql6iY1lDWAfpFiBtuKGw==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/react-transition-group/-/react-transition-group-4.4.2.tgz", + "integrity": "sha512-/RNYfRAMlZwDSr6z4zNKV6xu53/e2BuaBbGhbyYIXTrmgu/bGHzmqOs7mJSJBHy9Ud+ApHx3QjrkKSp1pxvlFg==", "requires": { "@babel/runtime": "^7.5.5", "dom-helpers": "^5.0.1", @@ -15267,12 +15314,11 @@ } }, "redux": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/redux/-/redux-4.0.5.tgz", - "integrity": "sha512-VSz1uMAH24DM6MF72vcojpYPtrTUu3ByVWfPL1nPfVRb5mZVTve5GnNCUV53QM/BZ66xfWrm0CTWoM+Xlz8V1w==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/redux/-/redux-4.1.0.tgz", + "integrity": "sha512-uI2dQN43zqLWCt6B/BMGRMY6db7TTY4qeHHfGeKb3EOhmOKjU3KdWvNLJyqaHRksv/ErdNH7cFZWg9jXtewy4g==", "requires": { - "loose-envify": "^1.4.0", - "symbol-observable": "^1.2.0" + "@babel/runtime": "^7.9.2" } }, "regenerate": { @@ -17097,11 +17143,6 @@ "util.promisify": "~1.0.0" } }, - "symbol-observable": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-1.2.0.tgz", - "integrity": "sha512-e900nM8RRtGhlV36KGEU9k65K3mPb1WV70OdjfxlG2EAuM1noi/E/BaW/uMhL7bPEssK8QV57vN3esixjUvcXQ==" - }, "symbol-tree": { "version": "3.2.4", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", @@ -17587,9 +17628,9 @@ } }, "typescript": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.4.tgz", - "integrity": "sha512-V+evlYHZnQkaz8TRBuxTA92yZBPotr5H+WhQ7bD3hZUndx5tGOa1fuCgeSjxAzM1RiN5IzvadIXTVefuuwZCRg==" + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz", + "integrity": "sha512-DqQgihaQ9cUrskJo9kIyW/+g0Vxsk8cDtZ52a3NGh0YNTfpUSArXSohyUGnvbPazEPLu398C0UxmKSOrPumUzA==" }, "unbox-primitive": { "version": "1.0.1", @@ -18198,9 +18239,9 @@ } }, "web-vitals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-1.1.1.tgz", - "integrity": "sha512-jYOaqu01Ny1NvMwJ3dBJDUOJ2PGWknZWH4AUnvFOscvbdHMERIKT2TlgiAey5rVyfOePG7so2JcXXZdSnBvioQ==" + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/web-vitals/-/web-vitals-1.1.2.tgz", + "integrity": "sha512-PFMKIY+bRSXlMxVAQ+m2aw9c/ioUYfDgrYot0YUa+/xa0sakubWhSDyxAKwzymvXVdF4CZI71g06W+mqhzu6ig==" }, "webidl-conversions": { "version": "6.1.0", diff --git a/package.json b/package.json index f1be2c6c..6802c1e2 100644 --- a/package.json +++ b/package.json @@ -3,16 +3,16 @@ "version": "0.1.0", "private": true, "dependencies": { - "@testing-library/jest-dom": "^5.11.10", - "@testing-library/react": "^11.2.6", + "@testing-library/jest-dom": "^5.14.1", + "@testing-library/react": "^11.2.7", "@testing-library/user-event": "^12.8.3", - "@types/jest": "^26.0.22", - "@types/node": "^12.20.7", - "@types/react": "^17.0.3", - "@types/react-dom": "^17.0.3", + "@types/jest": "^26.0.24", + "@types/node": "^12.20.16", + "@types/react": "^17.0.14", + "@types/react-dom": "^17.0.9", "animate.css": "^4.1.1", "classnames": "^2.3.1", - "immutable": "^4.0.0-rc.12", + "immutable": "^4.0.0-rc.14", "nitro-renderer": "file:../nitro-renderer", "node-sass": "^5.0.0", "rc-slider": "^9.7.2", @@ -21,12 +21,13 @@ "react-dom": "^17.0.2", "react-draggable": "^4.4.3", "react-google-recaptcha": "^2.1.0", - "react-redux": "^7.2.3", + "react-input-autosize": "^3.0.0", + "react-redux": "^7.2.4", "react-scripts": "4.0.3", - "react-transition-group": "^4.4.1", - "redux": "^4.0.5", - "typescript": "^4.2.4", - "web-vitals": "^1.1.1" + "react-slider": "^1.3.1", + "react-transition-group": "^4.4.2", + "typescript": "^4.3.5", + "web-vitals": "^1.1.2" }, "scripts": { "postinstall": "node ./webpack-patcher.js", @@ -59,7 +60,7 @@ ] }, "devDependencies": { - "@types/react-slider": "^1.3.0", - "@types/react-transition-group": "^4.4.1" + "@types/react-slider": "^1.3.1", + "@types/react-transition-group": "^4.4.2" } } From fef350555312bad795c3c1c6fea30ecc79ab9088 Mon Sep 17 00:00:00 2001 From: Bill Date: Fri, 16 Jul 2021 13:19:25 -0400 Subject: [PATCH 49/72] Remove console.log --- src/views/inventory/InventoryMessageHandler.tsx | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/views/inventory/InventoryMessageHandler.tsx b/src/views/inventory/InventoryMessageHandler.tsx index 36b442a8..febf3af9 100644 --- a/src/views/inventory/InventoryMessageHandler.tsx +++ b/src/views/inventory/InventoryMessageHandler.tsx @@ -298,8 +298,6 @@ export const InventoryMessageHandler: FC = props = { const parser = event.getParser(); - console.log(parser); - for(const category of parser.categories) { const itemIds = parser.getItemsByCategory(category); From da3c98b24d01d7a199de37dd870b6cc236e35fe4 Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 17 Jul 2021 05:30:30 -0400 Subject: [PATCH 50/72] Add stack helper --- src/views/room/RoomView.tsx | 3 +- .../RoomWidgetUpdateCustomStackHeightEvent.ts | 27 +++++ src/views/room/events/index.ts | 1 + ...FurnitureCustomStackHeightWidgetHandler.ts | 61 +++++++++++ src/views/room/handlers/index.ts | 1 + .../FurnitureCustomStackHeightView.tsx | 102 ++++++++++++++---- 6 files changed, 176 insertions(+), 19 deletions(-) create mode 100644 src/views/room/events/RoomWidgetUpdateCustomStackHeightEvent.ts create mode 100644 src/views/room/handlers/FurnitureCustomStackHeightWidgetHandler.ts diff --git a/src/views/room/RoomView.tsx b/src/views/room/RoomView.tsx index 4103324b..0ec62aad 100644 --- a/src/views/room/RoomView.tsx +++ b/src/views/room/RoomView.tsx @@ -7,7 +7,7 @@ import { DispatchTouchEvent } from '../../api/nitro/room/DispatchTouchEvent'; import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine'; import { RoomContextProvider } from './context/RoomContext'; import { RoomWidgetUpdateRoomViewEvent } from './events/RoomWidgetUpdateRoomViewEvent'; -import { FurnitureContextMenuWidgetHandler, IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers'; +import { FurnitureContextMenuWidgetHandler, FurnitureCustomStackHeightWidgetHandler, IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers'; import { RoomColorView } from './RoomColorView'; import { RoomViewProps } from './RoomView.types'; import { RoomWidgetsView } from './widgets/RoomWidgetsView'; @@ -39,6 +39,7 @@ export const RoomView: FC = props => widgetHandlerManager.registerHandler(new RoomWidgetChatInputHandler()); widgetHandlerManager.registerHandler(new RoomWidgetChatHandler()); widgetHandlerManager.registerHandler(new FurnitureContextMenuWidgetHandler()); + widgetHandlerManager.registerHandler(new FurnitureCustomStackHeightWidgetHandler()); setWidgetHandler(widgetHandlerManager); diff --git a/src/views/room/events/RoomWidgetUpdateCustomStackHeightEvent.ts b/src/views/room/events/RoomWidgetUpdateCustomStackHeightEvent.ts new file mode 100644 index 00000000..983b5633 --- /dev/null +++ b/src/views/room/events/RoomWidgetUpdateCustomStackHeightEvent.ts @@ -0,0 +1,27 @@ +import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent'; + +export class RoomWidgetUpdateCustomStackHeightEvent extends RoomWidgetUpdateEvent +{ + public static UPDATE_CUSTOM_STACK_HEIGHT: string = 'RWUCSHE_UPDATE_CUSTOM_STACK_HEIGHT'; + + private _objectId: number; + private _height: number; + + constructor(objectId: number, height: number = 0) + { + super(RoomWidgetUpdateCustomStackHeightEvent.UPDATE_CUSTOM_STACK_HEIGHT); + + this._objectId = objectId; + this._height = height; + } + + public get objectId(): number + { + return this._objectId; + } + + public get height(): number + { + return this._height; + } +} diff --git a/src/views/room/events/index.ts b/src/views/room/events/index.ts index c76fb712..60f8d0c8 100644 --- a/src/views/room/events/index.ts +++ b/src/views/room/events/index.ts @@ -6,6 +6,7 @@ export * from './RoomWidgetRoomObjectUpdateEvent'; export * from './RoomWidgetUpdateBackgroundColorPreviewEvent'; export * from './RoomWidgetUpdateChatEvent'; export * from './RoomWidgetUpdateChatInputContentEvent'; +export * from './RoomWidgetUpdateCustomStackHeightEvent'; export * from './RoomWidgetUpdateDanceStatusEvent'; export * from './RoomWidgetUpdateEvent'; export * from './RoomWidgetUpdateInfostandEvent'; diff --git a/src/views/room/handlers/FurnitureCustomStackHeightWidgetHandler.ts b/src/views/room/handlers/FurnitureCustomStackHeightWidgetHandler.ts new file mode 100644 index 00000000..7ffb8231 --- /dev/null +++ b/src/views/room/handlers/FurnitureCustomStackHeightWidgetHandler.ts @@ -0,0 +1,61 @@ +import { NitroEvent, RoomEngineTriggerWidgetEvent, RoomWidgetEnum } from 'nitro-renderer'; +import { GetRoomEngine } from '../../../api'; +import { RoomWidgetUpdateCustomStackHeightEvent, RoomWidgetUpdateEvent } from '../events'; +import { RoomWidgetMessage } from '../messages'; +import { RoomWidgetHandler } from './RoomWidgetHandler'; + +export class FurnitureCustomStackHeightWidgetHandler extends RoomWidgetHandler +{ + private _lastFurniId: number = -1; + + public processEvent(event: NitroEvent): void + { + switch(event.type) + { + case RoomEngineTriggerWidgetEvent.OPEN_WIDGET: { + const widgetEvent = (event as RoomEngineTriggerWidgetEvent); + + const roomObject = GetRoomEngine().getRoomObject(widgetEvent.roomId, widgetEvent.objectId, widgetEvent.category); + + if(!roomObject) return; + + this._lastFurniId = widgetEvent.objectId; + + this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateCustomStackHeightEvent(this._lastFurniId, roomObject.getLocation().z)); + return; + } + case RoomEngineTriggerWidgetEvent.CLOSE_WIDGET: { + const widgetEvent = (event as RoomEngineTriggerWidgetEvent); + + if(widgetEvent.objectId !== this._lastFurniId) return; + + this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateCustomStackHeightEvent(-1)); + return; + } + } + } + + public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent + { + switch(message.type) + { + } + + return null; + } + + public get type(): string + { + return RoomWidgetEnum.CUSTOM_STACK_HEIGHT; + } + + public get eventTypes(): string[] + { + return []; + } + + public get messageTypes(): string[] + { + return []; + } +} diff --git a/src/views/room/handlers/index.ts b/src/views/room/handlers/index.ts index 5c6464e2..1d7bd389 100644 --- a/src/views/room/handlers/index.ts +++ b/src/views/room/handlers/index.ts @@ -1,4 +1,5 @@ export * from './FurnitureContextMenuWidgetHandler'; +export * from './FurnitureCustomStackHeightWidgetHandler'; export * from './IRoomWidgetHandler'; export * from './IRoomWidgetHandlerManager'; export * from './RoomWidgetAvatarInfoHandler'; diff --git a/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx b/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx index de0fb14c..18debd32 100644 --- a/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx +++ b/src/views/room/widgets/furniture/custom-stack-height/FurnitureCustomStackHeightView.tsx @@ -1,48 +1,114 @@ -import { RoomEngineObjectEvent } from 'nitro-renderer'; -import { FC, useCallback, useState } from 'react'; +import { FurnitureStackHeightComposer, FurnitureStackHeightEvent } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; +import ReactSlider from 'react-slider'; +import { CreateMessageHook, SendMessageHook } from '../../../../../hooks'; import { CreateEventDispatcherHook } from '../../../../../hooks/events'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../layout'; import { LocalizeText } from '../../../../../utils/LocalizeText'; import { useRoomContext } from '../../../context/RoomContext'; -import { RoomWidgetRoomObjectUpdateEvent } from '../../../events'; +import { RoomWidgetUpdateCustomStackHeightEvent } from '../../../events'; + +const MAX_HEIGHT: number = 40; export const FurnitureCustomStackHeightView: FC<{}> = props => { const [ objectId, setObjectId ] = useState(-1); + const [ height, setHeight ] = useState(0); + const [ pendingHeight, setPendingHeight ] = useState(-1); + const { roomSession = null, eventDispatcher = null } = useRoomContext(); const close = useCallback(() => { setObjectId(-1); + setHeight(0); }, []); - const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) => + const updateHeight = useCallback((height: number, fromServer: boolean = false) => + { + if(!height) height = 0; + + height = Math.abs(height); + + if(!fromServer) ((height > MAX_HEIGHT) && (height = MAX_HEIGHT)); + + setHeight(parseFloat(height.toFixed(2))); + + if(!fromServer) setPendingHeight(height * 100); + }, []); + + const onRoomWidgetUpdateCustomStackHeightEvent = useCallback((event: RoomWidgetUpdateCustomStackHeightEvent) => { switch(event.type) { - // case RoomEngineTriggerWidgetEvent.REQUEST_CUSTOM_STACK_HEIGHT: { - // setObjectId(event.objectId); - // return; - // } - case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: { - if(objectId !== event.objectId) return; - - close(); - return; + case RoomWidgetUpdateCustomStackHeightEvent.UPDATE_CUSTOM_STACK_HEIGHT: { + setObjectId(event.objectId); + updateHeight(event.height, true); } } - }, [ objectId, close ]); + }, [ updateHeight ]); - //useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_CUSTOM_STACK_HEIGHT, onRoomEngineObjectEvent); - CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onRoomEngineObjectEvent); + CreateEventDispatcherHook(RoomWidgetUpdateCustomStackHeightEvent.UPDATE_CUSTOM_STACK_HEIGHT, eventDispatcher, onRoomWidgetUpdateCustomStackHeightEvent); + + const onFurnitureStackHeightEvent = useCallback((event: FurnitureStackHeightEvent) => + { + const parser = event.getParser(); + + if(objectId !== parser.furniId) return; + + updateHeight(parser.height, true); + }, [ objectId, updateHeight ]); + + CreateMessageHook(FurnitureStackHeightEvent, onFurnitureStackHeightEvent); + + const sendUpdate = useCallback((height: number) => + { + SendMessageHook(new FurnitureStackHeightComposer(objectId, ~~(height))); + }, [ objectId ]); + + const placeAboveStack = useCallback(() => + { + sendUpdate(-100); + }, [ sendUpdate ]); + + const placeAtFloor = useCallback(() => + { + sendUpdate(0); + }, [ sendUpdate ]); + + useEffect(() => + { + if((objectId === -1) || (pendingHeight === -1)) return; + + const timeout = setTimeout(() => sendUpdate(~~(pendingHeight)), 10); + + return () => clearTimeout(timeout); + }, [ objectId, pendingHeight, sendUpdate ]); if(objectId === -1) return null; return ( - + - custom stack height +
    + + updateHeight(event) } + renderThumb={ (props, state) =>
    { state.valueNow }
    } /> +
    +
    + updateHeight(parseFloat(event.target.value)) } /> +
    +
    + + +
    ); From 3b18493a4105761d8c8a75f52b76560d20dfb32a Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 17 Jul 2021 12:34:49 -0400 Subject: [PATCH 51/72] Add catalog purchase animation --- .../CatalogRoomPreviewerView.tsx | 55 +++++++++++++++++++ .../default/CatalogLayoutDefaultView.tsx | 4 +- .../CatalogLayoutGuildCustomFurniView.tsx | 4 +- .../page/layout/pets/CatalogLayoutPetView.tsx | 6 +- .../spaces-new/CatalogLayoutSpacesView.tsx | 4 +- .../trophies/CatalogLayoutTrophiesView.tsx | 4 +- .../CatalogLayoutSearchResultView.tsx | 4 +- .../room-previewer/RoomPreviewerView.tsx | 4 +- 8 files changed, 70 insertions(+), 15 deletions(-) create mode 100644 src/views/catalog/views/catalog-room-previewer/CatalogRoomPreviewerView.tsx diff --git a/src/views/catalog/views/catalog-room-previewer/CatalogRoomPreviewerView.tsx b/src/views/catalog/views/catalog-room-previewer/CatalogRoomPreviewerView.tsx new file mode 100644 index 00000000..94fc5ca8 --- /dev/null +++ b/src/views/catalog/views/catalog-room-previewer/CatalogRoomPreviewerView.tsx @@ -0,0 +1,55 @@ +import { NitroToolbarAnimateIconEvent, TextureUtils, ToolbarIconEnum } from 'nitro-renderer'; +import { FC, useCallback, useRef } from 'react'; +import { GetRoomEngine } from '../../../../api'; +import { CatalogEvent } from '../../../../events'; +import { useUiEvent } from '../../../../hooks'; +import { RoomPreviewerView } from '../../../shared/room-previewer/RoomPreviewerView'; +import { RoomPreviewerViewProps } from '../../../shared/room-previewer/RoomPreviewerView.types'; + +export const CatalogRoomPreviewerView: FC = props => +{ + const { roomPreviewer = null } = props; + const elementRef = useRef(null); + + const animatePurchase = useCallback(() => + { + if(!elementRef) return; + + const renderTexture = roomPreviewer.getRoomObjectCurrentImage(); + + if(!renderTexture) return; + + const image = TextureUtils.generateImage(renderTexture); + + if(!image) return; + + const bounds = elementRef.current.getBoundingClientRect(); + + const x = (bounds.x + (bounds.width / 2)); + const y = (bounds.y + (bounds.height / 2)); + + const event = new NitroToolbarAnimateIconEvent(image, x, y); + + event.iconName = ToolbarIconEnum.INVENTORY; + + GetRoomEngine().events.dispatchEvent(event); + }, [ roomPreviewer ]); + + const onCatalogEvent = useCallback((event: CatalogEvent) => + { + switch(event.type) + { + case CatalogEvent.PURCHASE_SUCCESS: + animatePurchase(); + return; + } + }, [ animatePurchase ]); + + useUiEvent(CatalogEvent.PURCHASE_SUCCESS, onCatalogEvent); + + return ( +
    + +
    + ); +} diff --git a/src/views/catalog/views/page/layout/default/CatalogLayoutDefaultView.tsx b/src/views/catalog/views/page/layout/default/CatalogLayoutDefaultView.tsx index 076a0ee2..db599364 100644 --- a/src/views/catalog/views/page/layout/default/CatalogLayoutDefaultView.tsx +++ b/src/views/catalog/views/page/layout/default/CatalogLayoutDefaultView.tsx @@ -1,8 +1,8 @@ import { FC } from 'react'; import { LimitedEditionCompletePlateView } from '../../../../../shared/limited-edition/complete-plate/LimitedEditionCompletePlateView'; -import { RoomPreviewerView } from '../../../../../shared/room-previewer/RoomPreviewerView'; import { GetCatalogPageImage, GetCatalogPageText, GetOfferName } from '../../../../common/CatalogUtilities'; import { useCatalogContext } from '../../../../context/CatalogContext'; +import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; import { CatalogLayoutDefaultViewProps } from './CatalogLayoutDefaultView.types'; @@ -29,7 +29,7 @@ export const CatalogLayoutDefaultView: FC = props
    } { product &&
    - + { product.uniqueLimitedItem && }
    { GetOfferName(activeOffer) }
    diff --git a/src/views/catalog/views/page/layout/guild-custom-furni/CatalogLayoutGuildCustomFurniView.tsx b/src/views/catalog/views/page/layout/guild-custom-furni/CatalogLayoutGuildCustomFurniView.tsx index 0057dfa0..5cefaaf0 100644 --- a/src/views/catalog/views/page/layout/guild-custom-furni/CatalogLayoutGuildCustomFurniView.tsx +++ b/src/views/catalog/views/page/layout/guild-custom-furni/CatalogLayoutGuildCustomFurniView.tsx @@ -2,9 +2,9 @@ import { CatalogGroupsComposer } from 'nitro-renderer'; import { FC, useEffect } from 'react'; import { SendMessageHook } from '../../../../../../hooks/messages'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; -import { RoomPreviewerView } from '../../../../../shared/room-previewer/RoomPreviewerView'; import { GetOfferName } from '../../../../common/CatalogUtilities'; import { useCatalogContext } from '../../../../context/CatalogContext'; +import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; import { CatalogLayoutGuildCustomFurniViewProps } from './CatalogLayoutGuildCustomFurniView.types'; @@ -30,7 +30,7 @@ export const CatalogLayouGuildCustomFurniView: FC { product &&
    - +
    { GetOfferName(activeOffer) }
    { groups.length === 0 &&
    { LocalizeText('catalog.guild_selector.members_only') } diff --git a/src/views/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx b/src/views/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx index 0651cca6..38388178 100644 --- a/src/views/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx +++ b/src/views/catalog/views/page/layout/pets/CatalogLayoutPetView.tsx @@ -4,10 +4,10 @@ import { GetProductDataForLocalization } from '../../../../../../api/nitro/sessi import { SendMessageHook } from '../../../../../../hooks/messages/message-event'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { PetImageView } from '../../../../../shared/pet-image/PetImageView'; -import { RoomPreviewerView } from '../../../../../shared/room-previewer/RoomPreviewerView'; import { GetCatalogPageImage, GetCatalogPageText, GetPetAvailableColors, GetPetIndexFromLocalization } from '../../../../common/CatalogUtilities'; import { useCatalogContext } from '../../../../context/CatalogContext'; import { CatalogActions } from '../../../../reducers/CatalogReducer'; +import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView'; import { CatalogLayoutPetViewProps } from './CatalogLayoutPetView.types'; import { CatalogLayoutPetPurchaseView } from './purchase/CatalogLayoutPetPurchaseView'; @@ -169,12 +169,12 @@ export const CatalogLayoutPetView: FC = props =>
    } { (petIndex >= 0) &&
    - + { (petIndex > -1 && petIndex <= 7) && } - +
    { petBreedName }
    } diff --git a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx b/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx index 54ca82e5..148d3c85 100644 --- a/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx +++ b/src/views/catalog/views/page/layout/spaces-new/CatalogLayoutSpacesView.tsx @@ -2,10 +2,10 @@ import { CatalogPageOfferData, IFurnitureData } from 'nitro-renderer'; import { FC, useEffect, useState } from 'react'; import { GetSessionDataManager } from '../../../../../../api'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; -import { RoomPreviewerView } from '../../../../../shared/room-previewer/RoomPreviewerView'; import { GetCatalogPageImage, GetCatalogPageText, GetOfferName } from '../../../../common/CatalogUtilities'; import { ProductTypeEnum } from '../../../../common/ProductTypeEnum'; import { useCatalogContext } from '../../../../context/CatalogContext'; +import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; import { CatalogLayoutSpacesViewProps } from './CatalogLayoutSpacesView.types'; @@ -88,7 +88,7 @@ export const CatalogLayoutSpacesView: FC = props =
    } { product &&
    - +
    { GetOfferName(activeOffer) }
    } diff --git a/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx b/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx index fb68497c..471001a1 100644 --- a/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx +++ b/src/views/catalog/views/page/layout/trophies/CatalogLayoutTrophiesView.tsx @@ -1,7 +1,7 @@ import { FC, useState } from 'react'; -import { RoomPreviewerView } from '../../../../../shared/room-previewer/RoomPreviewerView'; import { GetOfferName } from '../../../../common/CatalogUtilities'; import { useCatalogContext } from '../../../../context/CatalogContext'; +import { CatalogRoomPreviewerView } from '../../../catalog-room-previewer/CatalogRoomPreviewerView'; import { CatalogPageOffersView } from '../../offers/CatalogPageOffersView'; import { CatalogPurchaseView } from '../../purchase/CatalogPurchaseView'; import { CatalogLayoutTrophiesViewProps } from './CatalogLayoutTrophiesView.types'; @@ -25,7 +25,7 @@ export const CatalogLayoutTrophiesView: FC = pro
    { product &&
    - +
    { GetOfferName(activeOffer) }
    } diff --git a/src/views/catalog/views/page/search-result/CatalogLayoutSearchResultView.tsx b/src/views/catalog/views/page/search-result/CatalogLayoutSearchResultView.tsx index d5e147f2..a234f840 100644 --- a/src/views/catalog/views/page/search-result/CatalogLayoutSearchResultView.tsx +++ b/src/views/catalog/views/page/search-result/CatalogLayoutSearchResultView.tsx @@ -1,8 +1,8 @@ import { FC } from 'react'; import { LimitedEditionCompletePlateView } from '../../../../shared/limited-edition/complete-plate/LimitedEditionCompletePlateView'; -import { RoomPreviewerView } from '../../../../shared/room-previewer/RoomPreviewerView'; import { GetOfferName } from '../../../common/CatalogUtilities'; import { useCatalogContext } from '../../../context/CatalogContext'; +import { CatalogRoomPreviewerView } from '../../catalog-room-previewer/CatalogRoomPreviewerView'; import { CatalogPurchaseView } from '../purchase/CatalogPurchaseView'; import { CatalogLayoutSearchResultViewProps } from './CatalogLayoutSearchResultView.types'; import { CatalogSearchResultOffersView } from './offers/CatalogSearchResultOffersView'; @@ -22,7 +22,7 @@ export const CatalogLayoutSearchResultView: FC { product &&
    - + { product.uniqueLimitedItem && }
    { GetOfferName(activeOffer) }
    diff --git a/src/views/shared/room-previewer/RoomPreviewerView.tsx b/src/views/shared/room-previewer/RoomPreviewerView.tsx index cc4a3016..b2e972a4 100644 --- a/src/views/shared/room-previewer/RoomPreviewerView.tsx +++ b/src/views/shared/room-previewer/RoomPreviewerView.tsx @@ -1,5 +1,5 @@ import { ColorConverter, IRoomRenderingCanvas, Nitro, TextureUtils } from 'nitro-renderer'; -import { createRef, FC, useCallback, useEffect, useState } from 'react'; +import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { RoomPreviewerViewProps } from './RoomPreviewerView.types'; export const RoomPreviewerView: FC = props => @@ -8,7 +8,7 @@ export const RoomPreviewerView: FC = props => const [ renderingCanvas, setRenderingCanvas ] = useState(null); - const elementRef = createRef(); + const elementRef = useRef(); const update = useCallback((time: number) => { From 1f5f09cb0a4aa18c4885bf61b7c1ca70637f1418 Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 17 Jul 2021 13:11:12 -0400 Subject: [PATCH 52/72] Chat updates --- .../handlers/RoomWidgetChatInputHandler.ts | 6 +++ .../room/widgets/chat/ChatWidgetView.tsx | 14 ++++- .../chat/message/ChatWidgetMessageView.scss | 5 ++ .../chat/message/ChatWidgetMessageView.tsx | 52 ++++--------------- .../message/ChatWidgetMessageView.types.ts | 1 + .../widgets/chat/utils/ChatBubbleMessage.ts | 3 ++ 6 files changed, 36 insertions(+), 45 deletions(-) diff --git a/src/views/room/handlers/RoomWidgetChatInputHandler.ts b/src/views/room/handlers/RoomWidgetChatInputHandler.ts index be32fea5..31b4e797 100644 --- a/src/views/room/handlers/RoomWidgetChatInputHandler.ts +++ b/src/views/room/handlers/RoomWidgetChatInputHandler.ts @@ -176,6 +176,12 @@ export class RoomWidgetChatInputHandler extends RoomWidgetHandler break; } + case RoomWidgetChatSelectAvatarMessage.MESSAGE_SELECT_AVATAR: { + const selectedEvent = (message as RoomWidgetChatSelectAvatarMessage); + + GetRoomEngine().setSelectedAvatar(selectedEvent.roomId, selectedEvent.objectId); + break; + } } return null; diff --git a/src/views/room/widgets/chat/ChatWidgetView.tsx b/src/views/room/widgets/chat/ChatWidgetView.tsx index 18c5a781..d0408b4f 100644 --- a/src/views/room/widgets/chat/ChatWidgetView.tsx +++ b/src/views/room/widgets/chat/ChatWidgetView.tsx @@ -3,13 +3,14 @@ import { FC, useCallback, useEffect, useRef, useState } from 'react'; import { CreateEventDispatcherHook, useRoomEngineEvent } from '../../../../hooks/events'; import { useRoomContext } from '../../context/RoomContext'; import { RoomWidgetUpdateChatEvent } from '../../events'; +import { RoomWidgetChatSelectAvatarMessage, RoomWidgetRoomObjectMessage } from '../../messages'; import { ChatWidgetMessageView } from './message/ChatWidgetMessageView'; import { ChatBubbleMessage } from './utils/ChatBubbleMessage'; export const ChatWidgetView: FC<{}> = props => { const [ chatMessages, setChatMessages ] = useState([]); - const { roomSession = null, eventDispatcher = null } = useRoomContext(); + const { roomSession = null, eventDispatcher = null, widgetHandler = null } = useRoomContext(); const elementRef = useRef(); const removeHiddenChats = useCallback(() => @@ -63,6 +64,9 @@ export const ChatWidgetView: FC<{}> = props => const onRoomWidgetUpdateChatEvent = useCallback((event: RoomWidgetUpdateChatEvent) => { const chatMessage = new ChatBubbleMessage( + event.userId, + event.userCategory, + event.roomId, event.text, event.userName, new NitroPoint(event.userX, event.userY), @@ -92,6 +96,12 @@ export const ChatWidgetView: FC<{}> = props => useRoomEngineEvent(RoomDragEvent.ROOM_DRAG, onRoomDragEvent); + const onChatClicked = useCallback((chat: ChatBubbleMessage) => + { + widgetHandler.processWidgetMessage(new RoomWidgetRoomObjectMessage(RoomWidgetRoomObjectMessage.GET_OBJECT_INFO, chat.senderId, chat.senderCategory)); + widgetHandler.processWidgetMessage(new RoomWidgetChatSelectAvatarMessage(RoomWidgetChatSelectAvatarMessage.MESSAGE_SELECT_AVATAR, chat.senderId, chat.username, chat.roomId)); + }, [ widgetHandler ]); + useEffect(() => { const interval = setInterval(() => moveAllChatsUp(15), 4500); @@ -106,7 +116,7 @@ export const ChatWidgetView: FC<{}> = props =>
    { chatMessages.map(chat => { - return + return })}
    ); diff --git a/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss b/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss index d5880584..e2bbbbbf 100644 --- a/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss +++ b/src/views/room/widgets/chat/message/ChatWidgetMessageView.scss @@ -41,6 +41,11 @@ // -webkit-animation-name: bounceIn; // animation-name: bounceIn; + &:hover, + &:active { + pointer-events: none; + } + .user-container-bg { position: absolute; top: -1px; diff --git a/src/views/room/widgets/chat/message/ChatWidgetMessageView.tsx b/src/views/room/widgets/chat/message/ChatWidgetMessageView.tsx index 2649b842..c1b3a158 100644 --- a/src/views/room/widgets/chat/message/ChatWidgetMessageView.tsx +++ b/src/views/room/widgets/chat/message/ChatWidgetMessageView.tsx @@ -1,49 +1,20 @@ import { FC, MouseEvent, useCallback, useEffect, useRef, useState } from 'react'; +import { useRoomContext } from '../../../context/RoomContext'; import { ChatWidgetMessageViewProps } from './ChatWidgetMessageView.types'; export const ChatWidgetMessageView: FC = props => { - const { chat = null, makeRoom = null } = props; + const { chat = null, makeRoom = null, onChatClicked = null } = props; const [ isVisible, setIsVisible ] = useState(false); - const [ messageParts, setMessageParts ] = useState<{text: string, className?: string, style?: any, onClick?: () => void}[]>(null); + const { widgetHandler = null } = useRoomContext(); const elementRef = useRef(); - const onClick = useCallback((event: MouseEvent) => + const onMouseDown = useCallback((event: MouseEvent) => { + if(event.shiftKey) return; - }, []); - - // useEffect(() => - // { - // if(messageParts) return; - - // const userNameMention = '@' + GetSessionDataManager().userName; - - // const matches = [...chat.text.matchAll(new RegExp(userNameMention + '\\b', 'gi'))]; - - // if(matches.length > 0) - // { - // const prevText = chat.text.substr(0, matches[0].index); - // const postText = chat.text.substring(matches[0].index + userNameMention.length, chat.text.length); - - // setMessageParts( - // [ - // { text: prevText }, - // { text: userNameMention, className: 'chat-mention', onClick: () => {alert('I clicked in the mention')}}, - // { text: postText } - // ] - // ); - // } - // else - // { - // setMessageParts( - // [ - // { text: chat.text } - // ] - // ); - // } - - // }, [ chat ]); + onChatClicked(chat); + }, [ chat, onChatClicked ]); useEffect(() => { @@ -89,20 +60,15 @@ export const ChatWidgetMessageView: FC = props => }, [ chat.visible ]); return ( -
    +
    { (chat.styleId === 0) &&
    } -
    +
    { (chat.imageUrl && (chat.imageUrl !== '')) &&
    }
    { chat.text } - {/* { - messageParts && messageParts.map((part, index) => - { - return { part.text } - }) */}
    diff --git a/src/views/room/widgets/chat/message/ChatWidgetMessageView.types.ts b/src/views/room/widgets/chat/message/ChatWidgetMessageView.types.ts index faff1ef9..330b2886 100644 --- a/src/views/room/widgets/chat/message/ChatWidgetMessageView.types.ts +++ b/src/views/room/widgets/chat/message/ChatWidgetMessageView.types.ts @@ -4,4 +4,5 @@ export interface ChatWidgetMessageViewProps { chat: ChatBubbleMessage; makeRoom: (chat: ChatBubbleMessage) => void; + onChatClicked: (chat: ChatBubbleMessage) => void; } diff --git a/src/views/room/widgets/chat/utils/ChatBubbleMessage.ts b/src/views/room/widgets/chat/utils/ChatBubbleMessage.ts index 153422d8..e05307f9 100644 --- a/src/views/room/widgets/chat/utils/ChatBubbleMessage.ts +++ b/src/views/room/widgets/chat/utils/ChatBubbleMessage.ts @@ -14,6 +14,9 @@ export class ChatBubbleMessage private _left: number = 0; constructor( + public senderId: number = -1, + public senderCategory: number = -1, + public roomId: number = -1, public text: string = '', public username: string = '', public location: INitroPoint = null, From 9000756ae5f28f7bd2176b7508d23b9e011d4ce6 Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 17 Jul 2021 13:11:25 -0400 Subject: [PATCH 53/72] Inventory add seed rarity level --- .../views/furniture/InventoryFurnitureView.scss | 2 +- .../inventory/views/furniture/InventoryFurnitureView.tsx | 9 +++++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/views/inventory/views/furniture/InventoryFurnitureView.scss b/src/views/inventory/views/furniture/InventoryFurnitureView.scss index f56fa741..089af5ef 100644 --- a/src/views/inventory/views/furniture/InventoryFurnitureView.scss +++ b/src/views/inventory/views/furniture/InventoryFurnitureView.scss @@ -1,4 +1,4 @@ -.limited-edition-info-container { +.stuffdata-extra-container { position: absolute; top: 5px; right: 15px; diff --git a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx index 01450fe4..b298cbec 100644 --- a/src/views/inventory/views/furniture/InventoryFurnitureView.tsx +++ b/src/views/inventory/views/furniture/InventoryFurnitureView.tsx @@ -4,6 +4,7 @@ import { GetRoomEngine, GetSessionDataManager } from '../../../../api'; import { SendMessageHook } from '../../../../hooks/messages'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { LimitedEditionCompactPlateView } from '../../../shared/limited-edition/compact-plate/LimitedEditionCompactPlateView'; +import { RarityLevelView } from '../../../shared/rarity-level/RarityLevelView'; import { RoomPreviewerView } from '../../../shared/room-previewer/RoomPreviewerView'; import { FurniCategory } from '../../common/FurniCategory'; import { attemptItemPlacement } from '../../common/FurnitureUtilities'; @@ -123,10 +124,14 @@ export const InventoryFurnitureView: FC = props =>
    - { groupItem &&groupItem.stuffData.isUnique && -
    + { groupItem && groupItem.stuffData.isUnique && +
    } + { (groupItem && groupItem.stuffData.rarityLevel > -1) && +
    + +
    } { groupItem &&

    { groupItem.name }

    From 58d78ebb58db62fd812dbdeba19b32a73648a0a2 Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 17 Jul 2021 13:11:47 -0400 Subject: [PATCH 54/72] Catalog add gift configuration --- src/views/catalog/CatalogMessageHandler.tsx | 17 ++++++- src/views/catalog/CatalogView.tsx | 3 +- .../common/GiftWrappingConfiguration.ts | 51 +++++++++++++++++++ src/views/catalog/reducers/CatalogReducer.tsx | 14 ++++- 4 files changed, 81 insertions(+), 4 deletions(-) create mode 100644 src/views/catalog/common/GiftWrappingConfiguration.ts diff --git a/src/views/catalog/CatalogMessageHandler.tsx b/src/views/catalog/CatalogMessageHandler.tsx index 54b73d18..bcc13b40 100644 --- a/src/views/catalog/CatalogMessageHandler.tsx +++ b/src/views/catalog/CatalogMessageHandler.tsx @@ -1,4 +1,4 @@ -import { CatalogApproveNameResultEvent, CatalogClubEvent, CatalogGroupsEvent, CatalogPageEvent, CatalogPagesEvent, CatalogPurchaseEvent, CatalogPurchaseFailedEvent, CatalogPurchaseUnavailableEvent, CatalogSearchEvent, CatalogSoldOutEvent, CatalogUpdatedEvent, SellablePetPalettesEvent, UserSubscriptionEvent } from 'nitro-renderer'; +import { CatalogApproveNameResultEvent, CatalogClubEvent, CatalogGiftConfigurationEvent, CatalogGroupsEvent, CatalogPageEvent, CatalogPagesEvent, CatalogPurchaseEvent, CatalogPurchaseFailedEvent, CatalogPurchaseUnavailableEvent, CatalogSearchEvent, CatalogSoldOutEvent, CatalogUpdatedEvent, SellablePetPalettesEvent, UserSubscriptionEvent } from 'nitro-renderer'; import { FC, useCallback } from 'react'; import { CatalogNameResultEvent, CatalogPurchaseFailureEvent } from '../../events'; import { CatalogPurchasedEvent } from '../../events/catalog/CatalogPurchasedEvent'; @@ -145,6 +145,20 @@ export const CatalogMessageHandler: FC = props => }); }, [ dispatchCatalogState ]); + const onCatalogGiftConfigurationEvent = useCallback((event: CatalogGiftConfigurationEvent) => + { + const parser = event.getParser(); + + console.log(parser); + + dispatchCatalogState({ + type: CatalogActions.SET_GIFT_CONFIGURATION, + payload: { + giftConfiguration: parser + } + }); + }, [ dispatchCatalogState ]); + CreateMessageHook(CatalogPagesEvent, onCatalogPagesEvent); CreateMessageHook(CatalogPageEvent, onCatalogPageEvent); CreateMessageHook(CatalogPurchaseEvent, onCatalogPurchaseEvent); @@ -158,6 +172,7 @@ export const CatalogMessageHandler: FC = props => CreateMessageHook(CatalogClubEvent, onCatalogClubEvent); CreateMessageHook(UserSubscriptionEvent, onUserSubscriptionEvent); CreateMessageHook(CatalogUpdatedEvent, onCatalogUpdatedEvent); + CreateMessageHook(CatalogGiftConfigurationEvent, onCatalogGiftConfigurationEvent); return null; } diff --git a/src/views/catalog/CatalogView.tsx b/src/views/catalog/CatalogView.tsx index 4ee80c6a..8f6c6ff5 100644 --- a/src/views/catalog/CatalogView.tsx +++ b/src/views/catalog/CatalogView.tsx @@ -1,4 +1,4 @@ -import { CatalogModeComposer, ICatalogPageData, RoomPreviewer } from 'nitro-renderer'; +import { CatalogModeComposer, CatalogRequestGiftConfigurationComposer, ICatalogPageData, RoomPreviewer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; import { GetRoomEngine } from '../../api'; import { GetCatalogPageComposer } from '../../api/catalog/GetCatalogPageComposer'; @@ -49,6 +49,7 @@ export const CatalogView: FC = props => if(!catalogState.root) { SendMessageHook(new CatalogModeComposer(CatalogMode.MODE_NORMAL)); + SendMessageHook(new CatalogRequestGiftConfigurationComposer()); } }, [ isVisible, catalogState.root ]); diff --git a/src/views/catalog/common/GiftWrappingConfiguration.ts b/src/views/catalog/common/GiftWrappingConfiguration.ts new file mode 100644 index 00000000..f54d6850 --- /dev/null +++ b/src/views/catalog/common/GiftWrappingConfiguration.ts @@ -0,0 +1,51 @@ +import { CatalogGiftConfigurationParser } from 'nitro-renderer'; + +export class GiftWrappingConfiguration +{ + private _isEnabled: boolean = false; + private _price: number = null; + private _stuffTypes: number[] = null; + private _boxTypes: number[] = null; + private _ribbonTypes: number[] = null; + private _defaultStuffTypes: number[] = null; + + constructor(parser: CatalogGiftConfigurationParser) + { + this._isEnabled = parser.isEnabled; + this._price = parser.price; + this._boxTypes = parser.boxTypes; + this._ribbonTypes = parser.ribbonTypes; + this._stuffTypes = parser.giftWrappers; + this._defaultStuffTypes = parser.giftFurnis; + } + + public get isEnabled(): boolean + { + return this._isEnabled; + } + + public get price(): number + { + return this._price; + } + + public get stuffTypes(): number[] + { + return this._stuffTypes; + } + + public get boxTypes(): number[] + { + return this._boxTypes; + } + + public get ribbonTypes(): number[] + { + return this._ribbonTypes; + } + + public get defaultStuffTypes(): number[] + { + return this._defaultStuffTypes; + } +} diff --git a/src/views/catalog/reducers/CatalogReducer.tsx b/src/views/catalog/reducers/CatalogReducer.tsx index 6d68951a..0d70095e 100644 --- a/src/views/catalog/reducers/CatalogReducer.tsx +++ b/src/views/catalog/reducers/CatalogReducer.tsx @@ -1,7 +1,8 @@ -import { CatalogClubOfferData, CatalogGroupData, CatalogPageOfferData, ICatalogPageData, ICatalogPageParser } from 'nitro-renderer'; +import { CatalogClubOfferData, CatalogGiftConfigurationParser, CatalogGroupData, CatalogPageOfferData, ICatalogPageData, ICatalogPageParser } from 'nitro-renderer'; import { Reducer } from 'react'; import { CatalogPetPalette } from '../common/CatalogPetPalette'; import { ICatalogOffers, ICatalogSearchResult, SetOffersToNodes } from '../common/CatalogUtilities'; +import { GiftWrappingConfiguration } from '../common/GiftWrappingConfiguration'; import { SubscriptionInfo } from '../common/SubscriptionInfo'; export interface ICatalogState @@ -17,6 +18,7 @@ export interface ICatalogState petPalettes: CatalogPetPalette[]; clubOffers: CatalogClubOfferData[]; subscriptionInfo: SubscriptionInfo; + giftConfiguration: GiftWrappingConfiguration; } export interface ICatalogAction @@ -34,6 +36,7 @@ export interface ICatalogAction petPalette?: CatalogPetPalette; clubOffers?: CatalogClubOfferData[]; subscriptionInfo?: SubscriptionInfo; + giftConfiguration?: CatalogGiftConfigurationParser; } } @@ -50,6 +53,7 @@ export class CatalogActions public static SET_PET_PALETTE: string = 'CA_SET_PET_PALETTE'; public static SET_SEARCH_RESULT: string = 'CA_SET_SEARCH_RESULT'; public static SET_SUBSCRIPTION_INFO: string = 'CA_SET_SUBSCRIPTION_INFO'; + public static SET_GIFT_CONFIGURATION: string = 'CA_SET_GIFT_CONFIGURATION'; } export const initialCatalog: ICatalogState = { @@ -63,7 +67,8 @@ export const initialCatalog: ICatalogState = { groups: [], petPalettes: [], clubOffers: null, - subscriptionInfo: new SubscriptionInfo() + subscriptionInfo: new SubscriptionInfo(), + giftConfiguration: null } export const CatalogReducer: Reducer = (state, action) => @@ -158,6 +163,11 @@ export const CatalogReducer: Reducer = (state, ac case CatalogActions.RESET_STATE: { return { ...initialCatalog }; } + case CatalogActions.SET_GIFT_CONFIGURATION: { + const giftConfiguration = new GiftWrappingConfiguration((action.payload.giftConfiguration || null)); + + return { ...state, giftConfiguration }; + } default: return state; } From 9ef6750474758258b583f09e0e72785e3221d452 Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 17 Jul 2021 23:47:19 -0400 Subject: [PATCH 55/72] Start avatar editor --- src/views/avatar-editor/AvatarEditorView.tsx | 53 +- .../avatar-editor/common/AvatarEditor.ts | 289 +++++++++++ .../common/AvatarEditorGridColorItem.ts | 52 ++ .../common/AvatarEditorGridPartItem.ts | 320 ++++++++++++ src/views/avatar-editor/common/BodyModel.ts | 80 +++ .../avatar-editor/common/CategoryBaseModel.ts | 248 +++++++++ .../avatar-editor/common/CategoryData.ts | 487 ++++++++++++++++++ src/views/avatar-editor/common/HeadModel.ts | 23 + .../common/IAvatarEditorCategoryModel.ts | 19 + src/views/avatar-editor/common/LegModel.ts | 21 + src/views/avatar-editor/common/TorsoModel.ts | 22 + .../AvatarEditorFigureSetItemView.tsx | 16 + .../AvatarEditorFigureSetItemView.types.ts | 7 + .../figure-set/AvatarEditorFigureSetView.tsx | 28 + .../AvatarEditorFigureSetView.types.ts | 8 + .../views/model/AvatarEditorModelView.tsx | 60 +++ .../model/AvatarEditorModelView.types.ts | 8 + 17 files changed, 1732 insertions(+), 9 deletions(-) create mode 100644 src/views/avatar-editor/common/AvatarEditor.ts create mode 100644 src/views/avatar-editor/common/AvatarEditorGridColorItem.ts create mode 100644 src/views/avatar-editor/common/AvatarEditorGridPartItem.ts create mode 100644 src/views/avatar-editor/common/BodyModel.ts create mode 100644 src/views/avatar-editor/common/CategoryBaseModel.ts create mode 100644 src/views/avatar-editor/common/CategoryData.ts create mode 100644 src/views/avatar-editor/common/HeadModel.ts create mode 100644 src/views/avatar-editor/common/IAvatarEditorCategoryModel.ts create mode 100644 src/views/avatar-editor/common/LegModel.ts create mode 100644 src/views/avatar-editor/common/TorsoModel.ts create mode 100644 src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx create mode 100644 src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.types.ts create mode 100644 src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx create mode 100644 src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts create mode 100644 src/views/avatar-editor/views/model/AvatarEditorModelView.tsx create mode 100644 src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts diff --git a/src/views/avatar-editor/AvatarEditorView.tsx b/src/views/avatar-editor/AvatarEditorView.tsx index 0e19abaf..8fe50d8c 100644 --- a/src/views/avatar-editor/AvatarEditorView.tsx +++ b/src/views/avatar-editor/AvatarEditorView.tsx @@ -1,16 +1,28 @@ +import { AvatarEditorFigureCategory } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; import { AvatarEditorEvent } from '../../events/avatar-editor'; import { useUiEvent } from '../../hooks/events/ui/ui-event'; -import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsView, NitroCardView } from '../../layout'; +import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout'; import { LocalizeText } from '../../utils/LocalizeText'; import { AvatarEditorViewProps } from './AvatarEditorView.types'; +import { AvatarEditor } from './common/AvatarEditor'; +import { BodyModel } from './common/BodyModel'; +import { HeadModel } from './common/HeadModel'; +import { IAvatarEditorCategoryModel } from './common/IAvatarEditorCategoryModel'; +import { LegModel } from './common/LegModel'; +import { TorsoModel } from './common/TorsoModel'; import { AvatarEditorContextProvider } from './context/AvatarEditorContext'; import { AvatarEditorReducer, initialAvatarEditor } from './reducers/AvatarEditorReducer'; +import { AvatarEditorModelView } from './views/model/AvatarEditorModelView'; export const AvatarEditorView: FC = props => { const [ isVisible, setIsVisible ] = useState(false); const [ avatarEditorState, dispatchAvatarEditorState ] = useReducer(AvatarEditorReducer, initialAvatarEditor); + const [ avatarEditor, setAvatarEditor ] = useState(null); + const [ categories, setCategories ] = useState>(null); + const [ activeCategory, setActiveCategory ] = useState(null); + const [ isInitalized, setIsInitalized ] = useState(false); const onAvatarEditorEvent = useCallback((event: AvatarEditorEvent) => { @@ -32,10 +44,30 @@ export const AvatarEditorView: FC = props => useUiEvent(AvatarEditorEvent.HIDE_EDITOR, onAvatarEditorEvent); useUiEvent(AvatarEditorEvent.TOGGLE_EDITOR, onAvatarEditorEvent); + const selectCategory = useCallback((name: string) => + { + setActiveCategory(categories.get(name)); + }, [ categories ]); + useEffect(() => { - if(!isVisible) return; - }, [ isVisible ]); + if(!isVisible || isInitalized) return; + + const newEditor = new AvatarEditor(); + + setAvatarEditor(newEditor); + + const categories = new Map(); + + categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel(newEditor)); + categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel(newEditor)); + categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel(newEditor)); + categories.set(AvatarEditorFigureCategory.LEGS, new LegModel(newEditor)); + + setCategories(categories); + setActiveCategory(categories.get(AvatarEditorFigureCategory.GENERIC)); + setIsInitalized(true); + }, [ isVisible, isInitalized ]); return ( @@ -43,14 +75,17 @@ export const AvatarEditorView: FC = props => setIsVisible(false) } /> + { categories && Array.from(categories.keys()).map(category => + { + return ( + selectCategory(category) }> + { LocalizeText(`avatareditor.category.${ category }`) } + + ); + })} -
    -
    -
    -
    -
    -
    + { activeCategory && }
    }
    diff --git a/src/views/avatar-editor/common/AvatarEditor.ts b/src/views/avatar-editor/common/AvatarEditor.ts new file mode 100644 index 00000000..4bd882b6 --- /dev/null +++ b/src/views/avatar-editor/common/AvatarEditor.ts @@ -0,0 +1,289 @@ +import { FigureData, IPalette, IPartColor, ISetType, IStructureData } from 'nitro-renderer'; +import { GetAvatarRenderManager, GetConfiguration, GetSessionDataManager } from '../../../api'; +import { AvatarEditorGridColorItem } from './AvatarEditorGridColorItem'; +import { AvatarEditorGridPartItem } from './AvatarEditorGridPartItem'; +import { CategoryBaseModel } from './CategoryBaseModel'; +import { CategoryData } from './CategoryData'; + +const MAX_PALETTES: number = 2; +const DEFAULT_MALE_FIGURE: string = 'hr-100.hd-180-7.ch-215-66.lg-270-79.sh-305-62.ha-1002-70.wa-2007'; +const DEFAULT_FEMALE_FIGURE: string = 'hr-515-33.hd-600-1.ch-635-70.lg-716-66-62.sh-735-68'; + +export class AvatarEditor +{ + private _figureStructureData: IStructureData; + private _figures: Map; + private _gender: string; + + constructor() + { + this._figureStructureData = GetAvatarRenderManager().structureData; + this._figures = new Map(); + this._gender = FigureData.MALE; + + const maleFigure = new FigureData(); + const femaleFigure = new FigureData(); + + maleFigure.loadAvatarData(DEFAULT_MALE_FIGURE, FigureData.MALE); + femaleFigure.loadAvatarData(DEFAULT_FEMALE_FIGURE, FigureData.FEMALE); + + this._figures.set(FigureData.MALE, maleFigure); + this._figures.set(FigureData.FEMALE, femaleFigure); + } + + public getSetType(setType: string): ISetType + { + if(!this._figureStructureData) return null; + + return this._figureStructureData.getSetType(setType); + } + + public getPalette(paletteId: number): IPalette + { + if(!this._figureStructureData) return null; + + return this._figureStructureData.getPalette(paletteId); + } + + public createCategory(model: CategoryBaseModel, name: string): CategoryData + { + if(!model || !name) return null; + + const partItems: AvatarEditorGridPartItem[] = []; + const colorItems: AvatarEditorGridColorItem[][] = []; + + let i = 0; + + while(i < MAX_PALETTES) + { + colorItems.push([]); + + i++; + } + + const setType = this.getSetType(name); + + if(!setType) return null; + + const palette = this.getPalette(setType.paletteID); + + if(!palette) return null; + + let colorIds = this.figureData.getColourIds(name); + + if(!colorIds) colorIds = []; + + const partColors: IPartColor[] = new Array(colorIds.length); + const clubItemsDimmed = this.clubItemsDimmed; + + for(const partColor of palette.colors.values()) + { + if(partColor.isSelectable && (clubItemsDimmed || (this.clubMemberLevel >= partColor.clubLevel))) + { + let i = 0; + + while(i < MAX_PALETTES) + { + const isDisabled = (this.clubMemberLevel < partColor.clubLevel); + const colorItem = new AvatarEditorGridColorItem(partColor, isDisabled); + + colorItems[i].push(colorItem); + + i++; + } + + if(name !== FigureData.FACE) + { + let i = 0; + + while(i < colorIds.length) + { + if(partColor.id === colorIds[i]) partColors[i] = partColor; + + i++; + } + } + } + } + + let mandatorySetIds: string[] = []; + + if(clubItemsDimmed) + { + mandatorySetIds = GetAvatarRenderManager().getMandatoryAvatarPartSetIds(this._gender, 2); + } + else + { + mandatorySetIds = GetAvatarRenderManager().getMandatoryAvatarPartSetIds(this._gender, this.clubMemberLevel); + } + + const isntMandatorySet = (mandatorySetIds.indexOf(name) === -1); + + if(isntMandatorySet) + { + const partItem = new AvatarEditorGridPartItem(null, null, false); + + partItem.isClear = true; + + partItems.push(partItem); + } + + const usesColors = (name !== FigureData.FACE); + const partSets = setType.partSets; + const totalPartSets = partSets.length; + + i = (totalPartSets - 1); + + while(i >= 0) + { + const partSet = partSets.getWithIndex(i); + + let isValidGender = false; + + if(partSet.gender === FigureData.UNISEX) + { + isValidGender = true; + } + else + { + if(partSet.gender === this._gender) + { + isValidGender = true; + } + } + + if(partSet.isSelectable && isValidGender && (clubItemsDimmed || (this.clubMemberLevel >= partSet.clubLevel))) + { + const isDisabled = (this.clubMemberLevel < partSet.clubLevel); + + let isValid = true; + + if(partSet.isSellable) + { + //isValid = (this._inventoryService && this._inventoryService.hasFigureSetId(partSet.id)); + } + + if(isValid) + { + partItems.push(new AvatarEditorGridPartItem(partSet, partColors, usesColors, isDisabled)); + } + } + + i--; + } + + partItems.sort(this.clubItemsFirst ? this.clubSorter : this.noobSorter); + + // if(this._forceSellableClothingVisibility || Nitro.instance.getConfiguration("avatareditor.support.sellablefurni", false)) + // { + // _local_31 = (this._manager.windowManager.assets.getAssetByName("camera_zoom_in") as BitmapDataAsset); + // _local_32 = (_local_31.content as BitmapData).clone(); + // _local_33 = (AvatarEditorView._Str_6802.clone() as IWindowContainer); + // _local_33.name = AvatarEditorGridView.GET_MORE; + // _local_7 = new AvatarEditorGridPartItem(_local_33, k, null, null, false); + // _local_7._Str_3093 = _local_32; + // _local_3.push(_local_7); + // } + + i = 0; + + while(i < MAX_PALETTES) + { + colorItems[i].sort(this.colorSorter); + + i++; + } + + return new CategoryData(name, partItems, colorItems); + } + + private clubSorter(a: AvatarEditorGridPartItem, b: AvatarEditorGridPartItem): number + { + const clubLevelA = (!a.partSet ? 9999999999 : a.partSet.clubLevel); + const clubLevelB = (!b.partSet ? 9999999999 : b.partSet.clubLevel); + const isSellableA = (!a.partSet ? false : a.partSet.isSellable); + const isSellableB = (!b.partSet ? false : b.partSet.isSellable); + + if(isSellableA && !isSellableB) return 1; + + if(isSellableB && !isSellableA) return -1; + + if(clubLevelA > clubLevelB) return -1; + + if(clubLevelA < clubLevelB) return 1; + + if(a.partSet.id > b.partSet.id) return -1; + + if(a.partSet.id < b.partSet.id) return 1; + + return 0; + } + + private noobSorter(a: AvatarEditorGridPartItem, b: AvatarEditorGridPartItem): number + { + const clubLevelA = (!a.partSet ? -1 : a.partSet.clubLevel); + const clubLevelB = (!b.partSet ? -1 : b.partSet.clubLevel); + const isSellableA = (!a.partSet ? false : a.partSet.isSellable); + const isSellableB = (!b.partSet ? false : b.partSet.isSellable); + + if(isSellableA && !isSellableB) return 1; + + if(isSellableB && !isSellableA) return -1; + + if(clubLevelA < clubLevelB) return -1; + + if(clubLevelA > clubLevelB) return 1; + + if(a.partSet.id < b.partSet.id) return -1; + + if(a.partSet.id > b.partSet.id) return 1; + + return 0; + } + + private colorSorter(a: AvatarEditorGridColorItem, b: AvatarEditorGridColorItem): number + { + const clubLevelA = (!a.partColor ? -1 : a.partColor.clubLevel); + const clubLevelB = (!b.partColor ? -1 : b.partColor.clubLevel); + + if(clubLevelA < clubLevelB) return -1; + + if(clubLevelA > clubLevelB) return 1; + + if(a.partColor.index < b.partColor.index) return -1; + + if(a.partColor.index > b.partColor.index) return 1; + + return 0; + } + + public get clubMemberLevel(): number + { + return GetSessionDataManager().clubLevel; + } + + private get clubItemsFirst(): boolean + { + return GetConfiguration('avatareditor.show.clubitems.first', true); + } + + private get clubItemsDimmed(): boolean + { + return GetConfiguration('avatareditor.show.clubitems.dimmed', true); + } + + public get figureData(): FigureData + { + return this._figures.get(this._gender); + } + + public get gender(): string + { + return this._gender; + } + + public set gender(gender: string) + { + this._gender = gender; + } +} diff --git a/src/views/avatar-editor/common/AvatarEditorGridColorItem.ts b/src/views/avatar-editor/common/AvatarEditorGridColorItem.ts new file mode 100644 index 00000000..b6e99efd --- /dev/null +++ b/src/views/avatar-editor/common/AvatarEditorGridColorItem.ts @@ -0,0 +1,52 @@ +import { ColorConverter, IPartColor } from 'nitro-renderer'; + +export class AvatarEditorGridColorItem +{ + private _partColor: IPartColor; + private _isDisabled: boolean; + private _isHC: boolean; + private _isSelected: boolean; + + constructor(partColor: IPartColor, isDisabled: boolean = false) + { + this._partColor = partColor; + this._isDisabled = isDisabled; + this._isHC = (this._partColor.clubLevel > 0); + this._isSelected = false; + } + + public dispose(): void + { + this._partColor = null; + } + + public get partColor(): IPartColor + { + return this._partColor; + } + + public get color(): string + { + return ColorConverter.int2rgb(this._partColor.rgb); + } + + public get isDisabled(): boolean + { + return this._isDisabled; + } + + public get isHC(): boolean + { + return this._isHC; + } + + public get isSelected(): boolean + { + return this._isSelected; + } + + public set isSelected(flag: boolean) + { + this._isSelected = flag; + } +} diff --git a/src/views/avatar-editor/common/AvatarEditorGridPartItem.ts b/src/views/avatar-editor/common/AvatarEditorGridPartItem.ts new file mode 100644 index 00000000..f22b3718 --- /dev/null +++ b/src/views/avatar-editor/common/AvatarEditorGridPartItem.ts @@ -0,0 +1,320 @@ +import { AvatarFigurePartType, FigureData, IAvatarImageListener, IAvatarRenderManager, IFigurePart, IFigurePartSet, IGraphicAsset, IPartColor, NitroContainer, NitroSprite, TextureUtils } from 'nitro-renderer'; +import { GetAvatarRenderManager } from '../../../api'; + +export class AvatarEditorGridPartItem implements IAvatarImageListener +{ + private static THUMB_DIRECTIONS: number[] = [2, 6, 0, 4, 3, 1]; + private static DRAW_ORDER: string[] = [ + AvatarFigurePartType.LEFT_HAND_ITEM, + AvatarFigurePartType.LEFT_HAND, + AvatarFigurePartType.LEFT_SLEEVE, + AvatarFigurePartType.LEFT_COAT_SLEEVE, + AvatarFigurePartType.BODY, + AvatarFigurePartType.SHOES, + AvatarFigurePartType.LEGS, + AvatarFigurePartType.CHEST, + AvatarFigurePartType.CHEST_ACCESSORY, + AvatarFigurePartType.COAT_CHEST, + AvatarFigurePartType.CHEST_PRINT, + AvatarFigurePartType.WAIST_ACCESSORY, + AvatarFigurePartType.RIGHT_HAND, + AvatarFigurePartType.RIGHT_SLEEVE, + AvatarFigurePartType.RIGHT_COAT_SLEEVE, + AvatarFigurePartType.HEAD, + AvatarFigurePartType.FACE, + AvatarFigurePartType.EYES, + AvatarFigurePartType.HAIR, + AvatarFigurePartType.HAIR_BIG, + AvatarFigurePartType.FACE_ACCESSORY, + AvatarFigurePartType.EYE_ACCESSORY, + AvatarFigurePartType.HEAD_ACCESSORY, + AvatarFigurePartType.HEAD_ACCESSORY_EXTRA, + AvatarFigurePartType.RIGHT_HAND_ITEM, + ]; + + private _renderManager: IAvatarRenderManager; + private _partSet: IFigurePartSet; + private _partColors: IPartColor[]; + private _useColors: boolean; + private _isDisabled: boolean; + private _thumbContainer: NitroContainer; + private _imageUrl: string; + private _maxColorIndex: number; + private _isValidFigure: boolean; + private _isHC: boolean; + private _isSellable: boolean; + private _isClear: boolean; + private _isSelected: boolean; + private _disposed: boolean; + private _isInitalized: boolean; + + constructor(partSet: IFigurePartSet, partColors: IPartColor[], useColors: boolean = true, isDisabled: boolean = false) + { + this._renderManager = GetAvatarRenderManager(); + this._partSet = partSet; + this._partColors = partColors; + this._useColors = useColors; + this._isDisabled = isDisabled; + this._thumbContainer = null; + this._imageUrl = null; + this._maxColorIndex = 0; + this._isValidFigure = false; + this._isHC = false; + this._isSellable = false; + this._isClear = false; + this._isSelected = false; + this._disposed = false; + this._isInitalized = false; + + if(partSet) + { + const colors = partSet.parts; + + for(const color of colors) this._maxColorIndex = Math.max(this._maxColorIndex, color.colorLayerIndex); + } + } + + public init(): void + { + if(this._isInitalized) return; + + this._isInitalized = true; + + this.update(); + } + + public dispose(): void + { + if(this._disposed) return; + + this._renderManager = null; + this._partSet = null; + this._partColors = null; + this._imageUrl = null; + this._disposed = true; + this._isInitalized = false; + + if(this._thumbContainer) + { + this._thumbContainer.destroy(); + + this._thumbContainer = null; + } + } + + public update(): void + { + this.updateThumbVisualization(); + } + + private analyzeFigure(): boolean + { + if(!this._renderManager || !this._partSet || !this._partSet.parts || !this._partSet.parts.length) return false; + + const figureContainer = this._renderManager.createFigureContainer(((this.partSet.type + '-') + this.partSet.id)); + + if(!this._renderManager.isFigureContainerReady(figureContainer)) + { + this._renderManager.downloadAvatarFigure(figureContainer, this); + + return false; + } + + this._isValidFigure = true; + + return true; + } + + private renderThumb(): NitroContainer + { + if(!this._renderManager || !this._partSet) return null; + + if(!this._isValidFigure) + { + if(!this.analyzeFigure()) return null; + } + + const parts = this._partSet.parts.concat().sort(this.sortByDrawOrder); + const container = new NitroContainer(); + + for(const part of parts) + { + if(!part) continue; + + let asset: IGraphicAsset = null; + let direction = 0; + let hasAsset = false; + + while(!hasAsset && (direction < AvatarEditorGridPartItem.THUMB_DIRECTIONS.length)) + { + const assetName = ((((((((((FigureData.SCALE + '_') + FigureData.STD) + '_') + part.type) + '_') + part.id) + '_') + AvatarEditorGridPartItem.THUMB_DIRECTIONS[direction]) + '_') + FigureData.DEFAULT_FRAME); + + asset = this._renderManager.getAssetByName(assetName); + + if(asset && asset.texture) + { + hasAsset = true; + } + else + { + direction++; + } + } + + if(!hasAsset) continue; + + const x = asset.offsetX; + const y = asset.offsetY; + let partColor: IPartColor = null; + + if(this._useColors && (part.colorLayerIndex > 0)) + { + const color = this._partColors[(part.colorLayerIndex - 1)]; + + if(color) partColor = color; + } + + const sprite = new NitroSprite(asset.texture); + + sprite.position.set(x, y); + + if(partColor) sprite.tint = partColor.rgb; + + container.addChild(sprite); + } + + return container; + } + + private updateThumbVisualization(): void + { + if(!this._isInitalized) return; + + let container = this._thumbContainer; + + if(!container) container = this.renderThumb(); + + if(!container) return; + + if(this._partSet) + { + this._isHC = (this._partSet.clubLevel > 0); + this._isSellable = this._partSet.isSellable; + } + else + { + this._isHC = false; + this._isSellable = false; + } + + if(this._isDisabled) this.setAlpha(container, 0.2); + + this._imageUrl = TextureUtils.generateImageUrl(container); + } + + private setAlpha(container: NitroContainer, alpha: number): NitroContainer + { + container.alpha = alpha; + + return container; + } + + private sortByDrawOrder(a: IFigurePart, b: IFigurePart): number + { + const indexA = AvatarEditorGridPartItem.DRAW_ORDER.indexOf(a.type); + const indexB = AvatarEditorGridPartItem.DRAW_ORDER.indexOf(b.type); + + if(indexA < indexB) return -1; + + if(indexA > indexB) return 1; + + if(a.index < b.index) return -1; + + if(a.index > b.index) return 1; + + return 0; + } + + public resetFigure(figure: string): void + { + if(!this.analyzeFigure()) return; + + this.update(); + } + + public get disposed(): boolean + { + return this._disposed; + } + + public get id(): number + { + if(!this._partSet) return -1; + + return this._partSet.id; + } + + public get partSet(): IFigurePartSet + { + return this._partSet; + } + + public set colors(partColors: IPartColor[]) + { + this._partColors = partColors; + + this.update(); + } + + public get isDisabledForWearing(): boolean + { + return this._isDisabled; + } + + public set iconImage(k: NitroContainer) + { + this._thumbContainer = k; + + this.update(); + } + + public get imageUrl(): string + { + return this._imageUrl; + } + + public get colorLayerCount(): number + { + return this._maxColorIndex; + } + + public get isHC(): boolean + { + return this._isHC; + } + + public get isSellable(): boolean + { + return this._isSellable; + } + + public get isClear(): boolean + { + return this._isClear; + } + + public set isClear(flag: boolean) + { + this._isClear = flag; + } + + public get isSelected(): boolean + { + return this._isSelected; + } + + public set isSelected(flag: boolean) + { + this._isSelected = flag; + } +} diff --git a/src/views/avatar-editor/common/BodyModel.ts b/src/views/avatar-editor/common/BodyModel.ts new file mode 100644 index 00000000..b1419c10 --- /dev/null +++ b/src/views/avatar-editor/common/BodyModel.ts @@ -0,0 +1,80 @@ +import { AvatarEditorFigureCategory, AvatarScaleType, AvatarSetType, FigureData, IAvatarImageListener } from 'nitro-renderer'; +import { GetAvatarRenderManager } from '../../../api'; +import { CategoryBaseModel } from './CategoryBaseModel'; + +export class BodyModel extends CategoryBaseModel implements IAvatarImageListener +{ + private _imageCallBackHandled: boolean = false; + + public init(): void + { + super.init(); + + this.addCategory(FigureData.FACE); + + this._isInitalized = true; + } + + public selectColor(category: string, colorIndex: number, paletteId: number): void + { + super.selectColor(category, colorIndex, paletteId); + + this.updateSelectionsFromFigure(FigureData.FACE); + } + + protected updateSelectionsFromFigure(name: string): void + { + if(!this._categories || !this._editor || !this._editor.figureData) return; + + const category = this._categories.get(name); + + if(!category) return; + + const setId = this._editor.figureData.getPartSetId(name); + + let colorIds = this._editor.figureData.getColourIds(name); + + if(!colorIds) colorIds = []; + + category.selectPartId(setId); + category.selectColorIds(colorIds); + + for(const part of category.parts) + { + const figure = this._editor.figureData.getFigureStringWithFace(part.id); + const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, null, this); + + const sprite = avatarImage.getImageAsSprite(AvatarSetType.HEAD); + + if(sprite) + { + sprite.y = 10; + + part.iconImage = sprite; + + setTimeout(() => avatarImage.dispose(), 0); + } + } + + // if (this._Str_2271) this._Str_2271._Str_5614(k, _local_4.length); + } + + public resetFigure(figure: string): void + { + if(this._imageCallBackHandled) return; + + this._imageCallBackHandled = true; + + this.updateSelectionsFromFigure(FigureData.FACE); + } + + public get canSetGender(): boolean + { + return true; + } + + public get name(): string + { + return AvatarEditorFigureCategory.GENERIC; + } +} diff --git a/src/views/avatar-editor/common/CategoryBaseModel.ts b/src/views/avatar-editor/common/CategoryBaseModel.ts new file mode 100644 index 00000000..d7ea50a2 --- /dev/null +++ b/src/views/avatar-editor/common/CategoryBaseModel.ts @@ -0,0 +1,248 @@ +import { AvatarEditor } from './AvatarEditor'; +import { CategoryData } from './CategoryData'; +import { IAvatarEditorCategoryModel } from './IAvatarEditorCategoryModel'; + +export class CategoryBaseModel implements IAvatarEditorCategoryModel +{ + protected _editor: AvatarEditor; + protected _categories: Map; + protected _isInitalized: boolean; + protected _maxPaletteCount: number; + private _disposed: boolean; + + constructor(editor: AvatarEditor) + { + this._editor = editor; + this._isInitalized = false; + this._maxPaletteCount = 0; + } + + public dispose(): void + { + this._categories = null; + this._disposed = true; + } + + public get disposed(): boolean + { + return this._disposed; + } + + public init(): void + { + if(!this._categories) this._categories = new Map(); + } + + public reset(): void + { + this._isInitalized = false; + + if(this._categories) + { + for(const category of this._categories.values()) (category && category.dispose()); + } + + this._categories = new Map(); + } + + protected addCategory(name: string): void + { + let existing = this._categories.get(name); + + if(existing) return; + + existing = this._editor.createCategory(this, name); + + if(!existing) return; + + this._categories.set(name, existing); + + this.updateSelectionsFromFigure(name); + } + + protected updateSelectionsFromFigure(figure: string): void + { + const category = this._categories.get(figure); + + if(!category) return; + + const setId = this._editor.figureData.getPartSetId(figure); + + let colorIds = this._editor.figureData.getColourIds(figure); + + if(!colorIds) colorIds = []; + + category.selectPartId(setId); + category.selectColorIds(colorIds); + } + + public hasClubSelectionsOverLevel(level: number): boolean + { + if(!this._categories) return false; + + for(const category of this._categories.values()) + { + if(!category) continue; + + if(category.hasClubSelectionsOverLevel(level)) return true; + } + + return false; + } + + public hasInvalidSelectedItems(ownedItems: number[]): boolean + { + if(!this._categories) return false; + + for(const category of this._categories.values()) + { + if(category.hasInvalidSelectedItems(ownedItems)) return true; + } + + return false; + } + + public stripClubItemsOverLevel(level: number): boolean + { + if(!this._categories) return false; + + let didStrip = false; + + for(const [ name, category ] of this._categories.entries()) + { + let isValid = false; + + if(category.stripClubItemsOverLevel(level)) isValid = true; + + if(category.stripClubColorsOverLevel(level)) isValid = true; + + if(isValid) + { + const partItem = category.getCurrentPart(); + + if(partItem && this._editor && this._editor.figureData) + { + this._editor.figureData.savePartData(name, partItem.id, category.getSelectedColorIds(), true); + } + + didStrip = true; + } + } + + return didStrip; + } + + public stripInvalidSellableItems(): boolean + { + if(!this._categories) return false; + + let didStrip = false; + + for(const [ name, category ] of this._categories.entries()) + { + const isValid = false; + + // if(category._Str_8360(this._Str_2278.manager.inventory)) _local_6 = true; + + if(isValid) + { + const partItem = category.getCurrentPart(); + + if(partItem && this._editor && this._editor.figureData) + { + this._editor.figureData.savePartData(name, partItem.id, category.getSelectedColorIds(), true); + } + + didStrip = true; + } + } + + return didStrip; + } + + public selectPart(category: string, partIndex: number): void + { + const categoryData = this._categories.get(category); + + if(!categoryData) return; + + const selectedPartIndex = categoryData.selectedPartIndex; + + categoryData.selectPartIndex(partIndex); + + const partItem = categoryData.getCurrentPart(); + + if(!partItem) return; + + if(partItem.isDisabledForWearing) + { + categoryData.selectPartIndex(selectedPartIndex); + + // open hc window + + return; + } + + this._maxPaletteCount = partItem.colorLayerCount; + + this._editor.figureData.savePartData(category, partItem.id, categoryData.getSelectedColorIds(), true); + } + + public selectColor(category: string, colorIndex: number, paletteId: number): void + { + const categoryData = this._categories.get(category); + + if(!categoryData) return; + + const paletteIndex = categoryData.getCurrentColorIndex(paletteId); + + categoryData.selectColorIndex(colorIndex, paletteId); + + const colorItem = categoryData.getSelectedColor(paletteId); + + if(colorItem.isDisabled) + { + categoryData.selectColorIndex(paletteIndex, paletteId); + + // open hc window + + return; + } + + this._editor.figureData.savePartSetColourId(category, categoryData.getSelectedColorIds(), true); + } + + public getCategoryData(category: string): CategoryData + { + if(!this._isInitalized) this.init(); + + if(!this._categories) return null; + + return this._categories.get(category); + } + + public get categories(): Map + { + return this._categories; + } + + public get canSetGender(): boolean + { + return false; + } + + public get maxPaletteCount(): number + { + return this._maxPaletteCount; + } + + public set maxPaletteCount(count: number) + { + this._maxPaletteCount = count; + } + + public get name(): string + { + return null; + } +} diff --git a/src/views/avatar-editor/common/CategoryData.ts b/src/views/avatar-editor/common/CategoryData.ts new file mode 100644 index 00000000..54ffaa89 --- /dev/null +++ b/src/views/avatar-editor/common/CategoryData.ts @@ -0,0 +1,487 @@ +import { IPartColor } from 'nitro-renderer'; +import { AvatarEditorGridColorItem } from './AvatarEditorGridColorItem'; +import { AvatarEditorGridPartItem } from './AvatarEditorGridPartItem'; + +export class CategoryData +{ + private _name: string; + private _parts: AvatarEditorGridPartItem[]; + private _palettes: AvatarEditorGridColorItem[][]; + private _selectedPartIndex: number = -1; + private _paletteIndexes: number[]; + + constructor(name: string, partItems: AvatarEditorGridPartItem[], colorItems: AvatarEditorGridColorItem[][]) + { + this._name = name; + this._parts = partItems; + this._palettes = colorItems; + this._selectedPartIndex = -1; + } + + private static defaultColorId(palettes: AvatarEditorGridColorItem[], clubLevel: number): number + { + if(!palettes || !palettes.length) return -1; + + let i = 0; + + while(i < palettes.length) + { + const colorItem = palettes[i]; + + if(colorItem.partColor && (colorItem.partColor.clubLevel <= clubLevel)) + { + return colorItem.partColor.id; + } + + i++; + } + + return -1; + } + + public init(): void + { + for(const part of this._parts) + { + if(!part) continue; + + part.init(); + } + } + + public dispose(): void + { + if(this._parts) + { + for(const part of this._parts) part.dispose(); + + this._parts = null; + } + + if(this._palettes) + { + for(const palette of this._palettes) for(const colorItem of palette) colorItem.dispose(); + + this._palettes = null; + } + + this._selectedPartIndex = -1; + this._paletteIndexes = null; + } + + public selectPartId(partId: number): void + { + if(!this._parts) return; + + let i = 0; + + while(i < this._parts.length) + { + const partItem = this._parts[i]; + + if(partItem.id === partId) + { + this.selectPartIndex(i); + + return; + } + + i++; + } + } + + public selectColorIds(colorIds: number[]): void + { + if(!colorIds || !this._palettes) return; + + this._paletteIndexes = new Array(colorIds.length); + + let i = 0; + + while(i < this._palettes.length) + { + const palette = this.getPalette(i); + + if(palette) + { + let colorId = 0; + + if(colorIds.length > i) + { + colorId = colorIds[i]; + } + else + { + const colorItem = palette[0]; + + if(colorItem && colorItem.partColor) colorId = colorItem.partColor.id; + } + + let j = 0; + + while(j < palette.length) + { + const colorItem = palette[j]; + + if(colorItem.partColor.id === colorId) + { + this._paletteIndexes[i] = j; + + colorItem.isSelected = true; + } + else + { + colorItem.isSelected = false; + } + + j++; + } + } + + i++; + } + + this.updatePartColors(); + } + + public selectPartIndex(partIndex: number): AvatarEditorGridPartItem + { + if(!this._parts) return null; + + if((this._selectedPartIndex >= 0) && (this._parts.length > this._selectedPartIndex)) + { + const partItem = this._parts[this._selectedPartIndex]; + + if(partItem) partItem.isSelected = false; + } + + if(this._parts.length > partIndex) + { + const partItem = this._parts[partIndex]; + + if(partItem) + { + partItem.isSelected = true; + + this._selectedPartIndex = partIndex; + + return partItem; + } + } + + return null; + } + + public selectColorIndex(colorIndex: number, paletteId: number): AvatarEditorGridColorItem + { + const palette = this.getPalette(paletteId); + + if(!palette) return null; + + if(palette.length <= colorIndex) return null; + + this.deselectColorIndex(this._paletteIndexes[paletteId], paletteId); + + this._paletteIndexes[paletteId] = colorIndex; + + const colorItem = palette[colorIndex]; + + if(!colorItem) return null; + + colorItem.isSelected = true; + + this.updatePartColors(); + + return colorItem; + } + + public getCurrentColorIndex(k: number): number + { + return this._paletteIndexes[k]; + } + + private deselectColorIndex(colorIndex: number, paletteIndex: number): void + { + const palette = this.getPalette(paletteIndex); + + if(!palette) return; + + if(palette.length <= colorIndex) return; + + const colorItem = palette[colorIndex]; + + if(!colorItem) return; + + colorItem.isSelected = false; + } + + public getSelectedColorIds(): number[] + { + if(!this._paletteIndexes || !this._paletteIndexes.length) return null; + + if(!this._palettes || !this._palettes.length) return null; + + const palette = this._palettes[0]; + + if(!palette || (!palette.length)) return null; + + const colorItem = palette[0]; + + if(!colorItem || !colorItem.partColor) return null; + + const colorId = colorItem.partColor.id; + const colorIds: number[] = []; + + let i = 0; + + while(i < this._paletteIndexes.length) + { + const paletteSet = this._palettes[i]; + + if(!((!(paletteSet)) || (paletteSet.length <= i))) + { + if(paletteSet.length > this._paletteIndexes[i]) + { + const color = paletteSet[this._paletteIndexes[i]]; + + if(color && color.partColor) + { + colorIds.push(color.partColor.id); + } + else + { + colorIds.push(colorId); + } + } + else + { + colorIds.push(colorId); + } + } + + i++; + } + + const partItem = this.getCurrentPart(); + + if(!partItem) return null; + + return colorIds.slice(0, Math.max(partItem.colorLayerCount, 1)); + } + + private getSelectedColors(): IPartColor[] + { + const partColors: IPartColor[] = []; + + let i = 0; + + while(i < this._paletteIndexes.length) + { + const colorItem = this.getSelectedColor(i); + + if(colorItem) + { + partColors.push(colorItem.partColor); + } + else + { + partColors.push(null); + } + + i++; + } + + return partColors; + } + + public getSelectedColor(paletteId: number): AvatarEditorGridColorItem + { + const palette = this.getPalette(paletteId); + + if(!palette || (palette.length <= this._paletteIndexes[paletteId])) return null; + + return palette[this._paletteIndexes[paletteId]]; + } + + public getSelectedColorId(paletteId: number): number + { + const colorItem = this.getSelectedColor(paletteId); + + if(colorItem && (colorItem.partColor)) return colorItem.partColor.id; + + return 0; + } + + public getPalette(paletteId: number): AvatarEditorGridColorItem[] + { + if(!this._paletteIndexes || !this._palettes || (this._palettes.length <= paletteId)) + { + return null; + } + + return this._palettes[paletteId]; + } + + public getCurrentPart(): AvatarEditorGridPartItem + { + return this._parts[this._selectedPartIndex] as AvatarEditorGridPartItem; + } + + private updatePartColors(): void + { + const partColors = this.getSelectedColors(); + + for(const partItem of this._parts) + { + if(partItem) partItem.colors = partColors; + } + } + + public hasClubSelectionsOverLevel(level: number): boolean + { + let hasInvalidSelections = false; + + const partColors = this.getSelectedColors(); + + if(partColors) + { + let i = 0; + + while(i < partColors.length) + { + const partColor = partColors[i]; + + if(partColor && (partColor.clubLevel > level)) hasInvalidSelections = true; + + i++; + } + } + + const partItem = this.getCurrentPart(); + + if(partItem && partItem.partSet) + { + const partSet = partItem.partSet; + + if(partSet && (partSet.clubLevel > level)) hasInvalidSelections = true; + } + + return hasInvalidSelections; + } + + public hasInvalidSelectedItems(ownedItems: number[]): boolean + { + const part = this.getCurrentPart(); + + if(!part) return false; + + const partSet = part.partSet; + + if(!partSet || !partSet.isSellable) return; + + return (ownedItems.indexOf(partSet.id) > -1); + } + + public stripClubItemsOverLevel(level: number): boolean + { + const partItem = this.getCurrentPart(); + + if(partItem && partItem.partSet) + { + const partSet = partItem.partSet; + + if(partSet.clubLevel > level) + { + const newPartItem = this.selectPartIndex(0); + + if(newPartItem && !newPartItem.partSet) this.selectPartIndex(1); + + return true; + } + } + + return false; + } + + public stripClubColorsOverLevel(level: number): boolean + { + const colorIds: number[] = []; + const partColors = this.getSelectedColors(); + const colorItems = this.getPalette(0); + + let didStrip = false; + + const colorId = CategoryData.defaultColorId(colorItems, level); + + if(colorId === -1) return false; + + let i = 0; + + while(i < partColors.length) + { + const partColor = partColors[i]; + + if(!partColor) + { + colorIds.push(colorId); + + didStrip = true; + } + else + { + if(partColor.clubLevel > level) + { + colorIds.push(colorId); + + didStrip = true; + } + else + { + colorIds.push(partColor.id); + } + } + + i++; + } + + if(didStrip) this.selectColorIds(colorIds); + + return didStrip; + } + + // public stripInvalidSellableItems(k:IHabboInventory): boolean + // { + // var _local_3:IFigurePartSet; + // var _local_4:AvatarEditorGridPartItem; + // var _local_2:AvatarEditorGridPartItem = this._Str_6315(); + // if (((_local_2) && (_local_2.partSet))) + // { + // _local_3 = _local_2.partSet; + // if (((_local_3.isSellable) && (!(k._Str_14439(_local_3.id))))) + // { + // _local_4 = this._Str_8066(0); + // if (((!(_local_4 == null)) && (_local_4.partSet == null))) + // { + // this._Str_8066(1); + // } + // return true; + // } + // } + // return false; + // } + + public get name(): string + { + return this._name; + } + + public get parts(): AvatarEditorGridPartItem[] + { + return this._parts; + } + + public get selectedPartIndex(): number + { + return this._selectedPartIndex; + } +} diff --git a/src/views/avatar-editor/common/HeadModel.ts b/src/views/avatar-editor/common/HeadModel.ts new file mode 100644 index 00000000..1635b79a --- /dev/null +++ b/src/views/avatar-editor/common/HeadModel.ts @@ -0,0 +1,23 @@ +import { AvatarEditorFigureCategory, FigureData } from 'nitro-renderer'; +import { CategoryBaseModel } from './CategoryBaseModel'; + +export class HeadModel extends CategoryBaseModel +{ + public init(): void + { + super.init(); + + this.addCategory(FigureData.HAIR); + this.addCategory(FigureData.HAT); + this.addCategory(FigureData.HEAD_ACCESSORIES); + this.addCategory(FigureData.EYE_ACCESSORIES); + this.addCategory(FigureData.FACE_ACCESSORIES); + + this._isInitalized = true; + } + + public get name(): string + { + return AvatarEditorFigureCategory.HEAD; + } +} diff --git a/src/views/avatar-editor/common/IAvatarEditorCategoryModel.ts b/src/views/avatar-editor/common/IAvatarEditorCategoryModel.ts new file mode 100644 index 00000000..9f6d64e7 --- /dev/null +++ b/src/views/avatar-editor/common/IAvatarEditorCategoryModel.ts @@ -0,0 +1,19 @@ +import { CategoryData } from './CategoryData'; + +export interface IAvatarEditorCategoryModel +{ + init(): void; + dispose(): void; + reset(): void; + getCategoryData(category: string): CategoryData; + selectPart(category: string, partIndex: number): void; + selectColor(category: string, colorIndex: number, paletteId: number): void; + hasClubSelectionsOverLevel(level: number): boolean; + hasInvalidSelectedItems(ownedItems: number[]): boolean; + stripClubItemsOverLevel(level: number): boolean; + stripInvalidSellableItems(): boolean; + categories: Map; + canSetGender: boolean; + maxPaletteCount: number; + name: string; +} diff --git a/src/views/avatar-editor/common/LegModel.ts b/src/views/avatar-editor/common/LegModel.ts new file mode 100644 index 00000000..73b7bafe --- /dev/null +++ b/src/views/avatar-editor/common/LegModel.ts @@ -0,0 +1,21 @@ +import { AvatarEditorFigureCategory, FigureData } from 'nitro-renderer'; +import { CategoryBaseModel } from './CategoryBaseModel'; + +export class LegModel extends CategoryBaseModel +{ + public init(): void + { + super.init(); + + this.addCategory(FigureData.TROUSERS); + this.addCategory(FigureData.SHOES); + this.addCategory(FigureData.TROUSER_ACCESSORIES); + + this._isInitalized = true; + } + + public get name(): string + { + return AvatarEditorFigureCategory.LEGS; + } +} diff --git a/src/views/avatar-editor/common/TorsoModel.ts b/src/views/avatar-editor/common/TorsoModel.ts new file mode 100644 index 00000000..089ca366 --- /dev/null +++ b/src/views/avatar-editor/common/TorsoModel.ts @@ -0,0 +1,22 @@ +import { AvatarEditorFigureCategory, FigureData } from 'nitro-renderer'; +import { CategoryBaseModel } from './CategoryBaseModel'; + +export class TorsoModel extends CategoryBaseModel +{ + public init(): void + { + super.init(); + + this.addCategory(FigureData.SHIRT); + this.addCategory(FigureData.CHEST_PRINTS); + this.addCategory(FigureData.JACKET); + this.addCategory(FigureData.CHEST_ACCESSORIES); + + this._isInitalized = true; + } + + public get name(): string + { + return AvatarEditorFigureCategory.TORSO; + } +} diff --git a/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx b/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx new file mode 100644 index 00000000..fcb268cc --- /dev/null +++ b/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx @@ -0,0 +1,16 @@ +import { FC, useEffect, useState } from 'react'; +import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView'; +import { AvatarEditorFigureSetItemViewProps } from './AvatarEditorFigureSetItemView.types'; + +export const AvatarEditorFigureSetItemView: FC = props => +{ + const { partItem = null, onClick = null } = props; + const [ imageUrl, setImageUrl ] = useState(null); + + useEffect(() => + { + setImageUrl(partItem.imageUrl); + }, [ partItem.imageUrl ]); + + return onClick(partItem) } /> +} diff --git a/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.types.ts b/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.types.ts new file mode 100644 index 00000000..92172e9d --- /dev/null +++ b/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.types.ts @@ -0,0 +1,7 @@ +import { AvatarEditorGridPartItem } from '../../common/AvatarEditorGridPartItem'; + +export interface AvatarEditorFigureSetItemViewProps +{ + partItem: AvatarEditorGridPartItem; + onClick: (item: AvatarEditorGridPartItem) => void; +} diff --git a/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx new file mode 100644 index 00000000..e16afae6 --- /dev/null +++ b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx @@ -0,0 +1,28 @@ +import { FC, useCallback } from 'react'; +import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; +import { AvatarEditorGridPartItem } from '../../common/AvatarEditorGridPartItem'; +import { AvatarEditorFigureSetItemView } from '../figure-set-item/AvatarEditorFigureSetItemView'; +import { AvatarEditorFigureSetViewProps } from './AvatarEditorFigureSetView.types'; + +export const AvatarEditorFigureSetView: FC = props => +{ + const { model = null, category = null } = props; + + const selectPart = useCallback((part: AvatarEditorGridPartItem) => + { + const index = category.parts.indexOf(part); + + if(index === -1) return; + + model.selectPart(category.name, index); + }, [ model, category ]); + + return ( + + { (category.parts.length > 0) && category.parts.map((item, index) => + { + return ; + }) } + + ) +} diff --git a/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts new file mode 100644 index 00000000..b44992be --- /dev/null +++ b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts @@ -0,0 +1,8 @@ +import { CategoryData } from '../../common/CategoryData'; +import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel'; + +export interface AvatarEditorFigureSetViewProps +{ + model: IAvatarEditorCategoryModel; + category: CategoryData; +} diff --git a/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx b/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx new file mode 100644 index 00000000..4dfc58d0 --- /dev/null +++ b/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx @@ -0,0 +1,60 @@ +import { FC, useCallback, useEffect, useState } from 'react'; +import { CategoryData } from '../../common/CategoryData'; +import { AvatarEditorFigureSetView } from '../figure-set/AvatarEditorFigureSetView'; +import { AvatarEditorModelViewProps } from './AvatarEditorModelView.types'; + +export const AvatarEditorModelView: FC = props => +{ + const { model = null, editor = null } = props; + const [ activeCategory, setActiveCategory ] = useState(null); + + const selectGender = useCallback((gender: string) => + { + editor.gender = gender; + }, [ editor ]); + + const selectCategory = useCallback((name: string) => + { + const category = model.categories.get(name); + + if(!category) return; + + category.init(); + + setActiveCategory(category); + + for(const part of category.parts) + { + if(!part || !part.isSelected) continue; + + model.maxPaletteCount = part.colorLayerCount; + + break; + } + }, [ model ]); + + useEffect(() => + { + model.init(); + + for(const name of model.categories.keys()) + { + selectCategory(name); + + break; + } + }, [ model, selectCategory ]); + + if(!activeCategory) return null; + + return ( +
    +
    +
    + +
    +
    +
    +
    + ); +} diff --git a/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts b/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts new file mode 100644 index 00000000..322e9a86 --- /dev/null +++ b/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts @@ -0,0 +1,8 @@ +import { AvatarEditor } from '../../common/AvatarEditor'; +import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel'; + +export interface AvatarEditorModelViewProps +{ + model: IAvatarEditorCategoryModel; + editor: AvatarEditor; +} From 1c2800bfe32da8856f01504f3b1e961965083622 Mon Sep 17 00:00:00 2001 From: Bill Date: Sat, 17 Jul 2021 23:47:46 -0400 Subject: [PATCH 56/72] Start catalog gift button --- .../views/page/purchase/CatalogPurchaseView.tsx | 3 ++- .../CatalogPurchaseGiftButtonView.tsx | 12 ++++++++++++ .../CatalogPurchaseGiftButtonView.types.ts | 12 ++++++++++++ 3 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 src/views/catalog/views/page/purchase/purchase-gift-button/CatalogPurchaseGiftButtonView.tsx create mode 100644 src/views/catalog/views/page/purchase/purchase-gift-button/CatalogPurchaseGiftButtonView.types.ts diff --git a/src/views/catalog/views/page/purchase/CatalogPurchaseView.tsx b/src/views/catalog/views/page/purchase/CatalogPurchaseView.tsx index 06b90343..e2275968 100644 --- a/src/views/catalog/views/page/purchase/CatalogPurchaseView.tsx +++ b/src/views/catalog/views/page/purchase/CatalogPurchaseView.tsx @@ -3,6 +3,7 @@ import { LocalizeText } from '../../../../../utils/LocalizeText'; import { CurrencyIcon } from '../../../../shared/currency-icon/CurrencyIcon'; import { CatalogPurchaseViewProps } from './CatalogPurchaseView.types'; import { CatalogPurchaseButtonView } from './purchase-button/CatalogPurchaseButtonView'; +import { CatalogPurchaseGiftButtonView } from './purchase-gift-button/CatalogPurchaseGiftButtonView'; export const CatalogPurchaseView: FC = props => { @@ -70,7 +71,7 @@ export const CatalogPurchaseView: FC = props =>
    - { offer.giftable && } + { offer.giftable && }
    ); diff --git a/src/views/catalog/views/page/purchase/purchase-gift-button/CatalogPurchaseGiftButtonView.tsx b/src/views/catalog/views/page/purchase/purchase-gift-button/CatalogPurchaseGiftButtonView.tsx new file mode 100644 index 00000000..1874d530 --- /dev/null +++ b/src/views/catalog/views/page/purchase/purchase-gift-button/CatalogPurchaseGiftButtonView.tsx @@ -0,0 +1,12 @@ +import { FC } from 'react'; +import { LocalizeText } from '../../../../../../utils/LocalizeText'; +import { CatalogPurchaseGiftButtonViewProps } from './CatalogPurchaseGiftButtonView.types'; + +export const CatalogPurchaseGiftButtonView: FC = props => +{ + const { className = '', offer = null, pageId = -1, extra = null, quantity = 1, isPurchaseAllowed = true, beforePurchase = null } = props; + + return ( + + ); +} diff --git a/src/views/catalog/views/page/purchase/purchase-gift-button/CatalogPurchaseGiftButtonView.types.ts b/src/views/catalog/views/page/purchase/purchase-gift-button/CatalogPurchaseGiftButtonView.types.ts new file mode 100644 index 00000000..8f04c0ac --- /dev/null +++ b/src/views/catalog/views/page/purchase/purchase-gift-button/CatalogPurchaseGiftButtonView.types.ts @@ -0,0 +1,12 @@ +import { CatalogPageOfferData } from 'nitro-renderer'; + +export interface CatalogPurchaseGiftButtonViewProps +{ + className?: string; + offer: CatalogPageOfferData; + pageId: number; + extra?: string; + quantity?: number; + isPurchaseAllowed?: boolean; + beforePurchase?: () => void; +} From df167ba1d855f185bd5ec87250149d320c8a5dc6 Mon Sep 17 00:00:00 2001 From: Bill Date: Mon, 19 Jul 2021 13:26:54 -0400 Subject: [PATCH 57/72] Avatar editor works --- src/assets/images/avatareditor/ca-icon.png | Bin 171 -> 259 bytes .../images/avatareditor/ca-selected-icon.png | Bin 242 -> 335 bytes src/assets/images/avatareditor/cc-icon.png | Bin 281 -> 282 bytes .../images/avatareditor/cc-selected-icon.png | Bin 265 -> 338 bytes src/assets/images/avatareditor/ch-icon.png | Bin 154 -> 228 bytes .../images/avatareditor/ch-selected-icon.png | Bin 171 -> 260 bytes src/assets/images/avatareditor/cp-icon.png | Bin 234 -> 252 bytes .../images/avatareditor/cp-selected-icon.png | Bin 199 -> 280 bytes src/assets/images/avatareditor/ea-icon.png | Bin 155 -> 251 bytes .../images/avatareditor/ea-selected-icon.png | Bin 227 -> 298 bytes src/assets/images/avatareditor/fa-icon.png | Bin 140 -> 234 bytes .../images/avatareditor/fa-selected-icon.png | Bin 195 -> 286 bytes src/assets/images/avatareditor/ha-icon.png | Bin 156 -> 241 bytes .../images/avatareditor/ha-selected-icon.png | Bin 220 -> 285 bytes src/assets/images/avatareditor/he-icon.png | Bin 173 -> 267 bytes .../images/avatareditor/he-selected-icon.png | Bin 248 -> 338 bytes src/assets/images/avatareditor/hr-icon.png | Bin 173 -> 257 bytes .../images/avatareditor/hr-selected-icon.png | Bin 238 -> 348 bytes src/assets/images/icons/loading-icon.png | Bin 181 -> 222 bytes src/assets/styles/bootstrap/_variables.scss | 2 + src/assets/styles/icons.scss | 929 +++++++++--------- src/layout/card/grid/NitroCardGridView.scss | 11 + src/layout/card/grid/NitroCardGridView.tsx | 15 +- .../card/grid/NitroCardGridView.types.ts | 7 + .../grid/context/NitroCardGridContext.tsx | 13 + .../context/NitroCardGridContext.types.ts | 11 + src/layout/card/grid/context/index.ts | 2 + .../card/grid/item/NitroCardGridItemView.scss | 42 +- .../card/grid/item/NitroCardGridItemView.tsx | 7 +- .../grid/item/NitroCardGridItemView.types.ts | 1 + src/views/avatar-editor/AvatarEditorView.scss | 49 +- src/views/avatar-editor/AvatarEditorView.tsx | 103 +- .../avatar-editor/common/AvatarEditor.ts | 33 +- .../common/AvatarEditorGridColorItem.ts | 13 + .../common/AvatarEditorGridPartItem.ts | 28 +- src/views/avatar-editor/common/BodyModel.ts | 5 +- .../avatar-editor/common/CategoryBaseModel.ts | 6 +- .../avatar-editor/common/CategoryData.ts | 4 +- src/views/avatar-editor/common/FigureData.ts | 271 +++++ src/views/avatar-editor/common/HeadModel.ts | 3 +- src/views/avatar-editor/common/LegModel.ts | 3 +- src/views/avatar-editor/common/TorsoModel.ts | 3 +- .../AvatarEditorFigurePreviewView.tsx | 28 + .../AvatarEditorFigurePreviewView.types.ts | 6 + .../AvatarEditorFigureSetItemView.tsx | 25 +- .../figure-set/AvatarEditorFigureSetView.tsx | 17 +- .../AvatarEditorFigureSetView.types.ts | 2 + .../views/model/AvatarEditorModelView.tsx | 73 +- .../model/AvatarEditorModelView.types.ts | 1 + .../AvatarEditorPaletteSetItem.tsx | 26 + .../AvatarEditorPaletteSetItem.types.ts | 7 + .../AvatarEditorPaletteSetView.tsx | 29 + .../AvatarEditorPaletteSetView.types.ts | 11 + .../PurchasableClothingConfirmView.tsx | 3 +- .../shared/avatar-image/AvatarImage.scss | 1 + src/views/toolbar/ToolbarView.tsx | 15 +- 56 files changed, 1255 insertions(+), 550 deletions(-) create mode 100644 src/layout/card/grid/context/NitroCardGridContext.tsx create mode 100644 src/layout/card/grid/context/NitroCardGridContext.types.ts create mode 100644 src/layout/card/grid/context/index.ts create mode 100644 src/views/avatar-editor/common/FigureData.ts create mode 100644 src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx create mode 100644 src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts create mode 100644 src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx create mode 100644 src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts create mode 100644 src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx create mode 100644 src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts diff --git a/src/assets/images/avatareditor/ca-icon.png b/src/assets/images/avatareditor/ca-icon.png index 14de95e26f2463661578fb82fc04ffb8f74b791c..c9803b950578cac2d62297c3454c19d713d8d3c7 100644 GIT binary patch literal 259 zcmeAS@N?(olHy`uVBq!ia0vp^k|4~%3?x6Bmj(hU#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6;R0X`wFt5>fEGQAZu5`h#`NswRge}<>q4ZMIn&H|6fVg?4j!ywFfJby(B zP_V+&#W6%9cxivM&;bRGBVYbaUzZ}j;r#qGEiW$#6-^2?(eU5WF z=e}LiFSy#}Q{B<&8e+XdhqzbXe^;Zro#VK=y~;z$35G^TvP-AE|1Ngu!j#@iZ#~zo yU2=cTt7)OftPg8F%Mapy_2BZ>_Fv}{&M})8G2XU!yUq=C1B0ilpUXO@geCx?xL;)e literal 171 zcmV;c095}+Nk%w1VHp4!0CxZYA^8LW00031EC2ui02u%o0D$@V`Tqd_2!a3u2pkBY zpuvL%2P!03P#^$@5CbG!DDh!Mga;j3WO$Jx!-owchV-Z~q{W6CNtUcAQKL$VCQrWf zcrxS6g$N_wB7`D?eh4inFTGlsJ(B9jS68QLIZL ZYTYSw>`<{rk2VFXmg-N96G;XH06UwrK05#a diff --git a/src/assets/images/avatareditor/ca-selected-icon.png b/src/assets/images/avatareditor/ca-selected-icon.png index 3f5cda18cf1d8dc82c9fe91c4cabf19c1c9b8644..b118c3ed606a0dcc4f80f16b734481d1f9648bf5 100644 GIT binary patch delta 319 zcmeywc%Es3WIZzj1H)(Y(m)`^SRCZ;#IWw1%u67LCEd~2k%3`jKlh(RRv=#@z$e7D z)QW#eiTI-f%Ksnu2X;BZzqy>)hU0a^L(Y$6|Im407jg!2!PpdggsS5W@{VjC1-t@7$ zjpi(i zubuxZA8#zW^pjCbIeg;IxD!$Nru)>tyP8z->4dg@TyW<5y?D8uTz_Zv9%}}=oWax8 K&t;ucLK6U5QHHYs delta 225 zcmV<703QF(0`dWn8Gi-<006}4g<}8!0J%v-K~zYI(b3-FVa`6Dn`Kzp7CnTBd+g67dC*026}v@9jFQd$g<-k?4067@nnSC#=x; b?up0-YC9%8wSEWh00000NkvXXu0mjf=(J~_ diff --git a/src/assets/images/avatareditor/cc-icon.png b/src/assets/images/avatareditor/cc-icon.png index 5099b67204c375f7d05f9c05b0451c7614941837..4a8844e49c173bce47e93ac4fdc082b9a02db93b 100644 GIT binary patch delta 266 zcmbQqG>d71WIZzj14HT#cOc2YSRCZ;#IWw1%u67LCEd~2k%3`jKlh(RRv@1(z$e6Y z_3G6?rnh27B9LM#3Gxg6&+v4+ffta+S>O>_%)r2R7=#&*=dVZs3if-tIEGmGPwfxn zJD|Yh^!4BLxJ<^mE9LjOr0z+}OP*vXQ~y0ivFjj*QZ`HVu?VSzKiB!vuWx77OUkj` z*Q~j_R<+;GOzz3i^kefD-cX9D_kI$pfA-&5{o2p-Uf675tIDta{OpnKrQgr~@ywgF zZi3Y8y(_~`-BS(?zFq!Z{p%8|g!AdupM{Sz@*SN1k!8j6KMa4qF>S0rcjgn&Z492S LelF{nof4V=4+Clh delta 265 zcmV+k0rviy0+|Ak8Gi-<002^Ew=w_#0N_bPK~zYI)mG6C10e`gQ QK#wqZy85}Sb4q9e0QFyi`2YX_ delta 248 zcmVbf>5E`bVU&CcX2{j7VI0l8HDo;4AyM`%Gx>(ez0%5T>2Z5yN7>l^5BvG;Yajh^ zmXMc0Y$caMb5{FhIk)!g-Ww9i|bM*~1`Iez)84fpnol+q2e&Nwrd*x=v*0000wb?FL>z9%q3^WHAE+-(e7DJf6QI z1t=Kl>Ealo5&X7~k?(*42lLba^W{V~SQz|1pm)n*^&_EV$rU_h0pd>j-2u&e-)(vP zNUl+1c3;|ef%UGYAEzee**{vhYQ6ZE<@M9e+aKobv|r+@T_0t6sc)AOzgZ4b(3$x= R{ehM+c)I$ztaD0e0su4!N%{Z) literal 154 zcmZ?wbhEHblx2`$C}&_${K>+|00cT90wmV(pW#0ca1=5ya)?MQNI2NY!70TvK|t|v zBe$|#%MF18&RwFqYI{63EOKd<7QvtYXYby9AtTu4%PmiZLn^zX1eC2N zny$Rfa7$GxKl@yvo`u)qpgb%0<)^Z(7kr+`+!65I%;K%5wT{!z6$;XmHyLdYn;E!v xs$;9E8Ef?C=eN?=-+lD{+WeZ0`5St7Ficv=@`S(Y+I*nJ44$rjF6*2UngCQATr>ax literal 171 zcmeAS@N?(olHy`uVBq!ia0vp^azHG>!3HGXX8P_2QbnFFjv*eMZznnO9Z=w4Ir!th z{$*ib$D|dmy_(f7HyU?%xFnp=T6ERIDtd17-d*LAjMpE``#HT^x+0Wcxh=osu=j$M z;YS`!4GVq)$fu*)50$R^|L9Sb%Kv-ZSYQ0!f1lDO;W-ajNS%G}E0G|-o z)vH$nncj*Si9m{}B*-uLKf}}Q23|lOXMsm#F#`kNVGw3Kp1&dmC|Ky};uxY4yta>< zuR(#w`Qg9mWq);?BTWLOHJ17}8ZKlsObOh&^t4#$%!7WRg2vVVId>lLxTW!c_i3Zw zS~XdJJRM17vE{^uiN3+{;vy>a$an^Niuyad(Yk#Ki%A$Ycq zx&)zFjT9ZFp^QztPML^NI!iqf1$*gCkKFH#%uJ27Zr%4P`1UjU*SOWV2ZM+NS%G|^0G|-o z`Sa&5Tei%xL;K)wqnYPLfWoc{iU~l9tt7}V_&*3RY~H_QKTw3Tz$3Dlfr0NZ2s0kf zUy%Y7to3wp4ABT)J0Xy-L4n6v^vS>a@NKc%51jepTzhfZyGDuaj%G<`XY^0&YPIY! zD)V-}I#s7lnD$m^uB&++`OU3K1uuAk7GWpALd%gW75(;z)gQu&X%Q~k7 G#wGxLTxY5P delta 182 zcmV;n07?It0>=T68Gi-<008Z2O}_vD0FFsSK~zYI?Ulh2zz_^X!}$MSPA^TT!swFV zQ16Ij#R`F$sX}cq)E17$CNQuyj&3Fs*TSvjmWm7Uq$WlZ_V9>D$D}AM!Yf4uj@UYX zwh5=(?B3(nH@rJuDn?tygX~tn#b<1y$gMq|S$Xs2f`WkgPcP5^*G^me7(shx?c?L| kI#7=_=CAa4yapn=0N-I4I!*5a2><{907*qoM6N<$g8DC2eENn{1`*#dk*TvxAN4P<&NW+VbBrjj7P;QtIyw;Ol?d7K3vk;M!Qe1}1p@p%4< z6rf;%r;B5VMsR7LHy?u{kJItr@l_3%`rYm?V)g2|ZzR9bE{5xkV7rX@dY?&sNwHeW zSN4QiJ*xQj|&KtsII?S=#xz@NXRLSDxzI>gztmzv^kx13es6AH78|{>K_<6k* o^!+p0h3^gHS)UcX!YUeGT0cbaar>mdKI;Vst0AOQM?*IS* literal 155 zcmZ?wbhEHbRAvxhC}&_${K>+|00cT90wmV(pW#0ca1=2xa>!^HG&nZ12+O(5*zoWG z11rB(OvHsm=MDygsE~-lwImR2HTlYc&WK>f!vXcy^Y)_q`<= zg^OJ}Y(0Z`JU^>A%@j8^`Vw(zMbHwBg>E4lUzhqW6ke#;TXFgMxiyBJVzLqf4Aua1 Ck2U}R diff --git a/src/assets/images/avatareditor/ea-selected-icon.png b/src/assets/images/avatareditor/ea-selected-icon.png index 56c804c6200be332ba41be5f733be24fd4a98fda..e7678c4a6e23d14dce0ebe95250d35b4a9d2878a 100644 GIT binary patch delta 282 zcmaFNxQc0lWIZzj1HI_+Q(22yM#L4LtN!T0wMe=gS;`o)(NvD^$kv%@#D$~7T!(Y9+<@26hp|J$-6*2iO? z(t$H7`iGJ@3;G;R$8`K=aQG0Oru7dg`$;#b=6wJ6Kq|Ig}zPWydWVT ZD}0*uL$uyhZJ^^AJYD@<);T3K0RUFRZ8HD> delta 210 zcmV;@04@Kj0^95-(;N5*7BlHyDArU;CF7M>hgbye2A@=KnnjxLF{%oNn{1`*#dk*TvxAN4N|U{kqD%iN`m}?|1&(@Zr}yvaTa()7BevL9R^{>I6wS1U2bcM<}RJzH-BHSlk)88@eo+xZ`JbACQvcx@2m8x z>hj+b1??}UvYcGIY07rVBwe;SGc!LOx$d{SCG}YHh98TgE6YD#o0^k#=Ka~ch-a*q X?lT^D)k}>9TE*b$>gTe~DWM4fpL|kq literal 140 zcmZ?wbhEHblx7fNC}&_${K>+|00cT90wmV(pW#0ca3nJ@vT!ggNI2NY!K$Q^5wP%Z z8xOCW&5Z!XgB`+}VMl%#B)T@r>&l(^@iEDxL&3i&MAItEYc=P|P42d*KYl z2}=4K*?5v-COi^-n7ZO~A+wPJdrmj=#gpeOT{J=sxep5;`X)R@?au9O_pD>n>t4oR z+Zv^OPBDE^nTGw-V=K6WeQH;FT3l@Z`g}=RPv7lpac528Gi-<004Y~Mt}eS0E$UOK~zYI?Uc<9fG`My3-SG58IvX30rvyN zg9pEZONecQGQ`XPpgjNxp4g-&o4RLsD-o2fcVE+u!7Av)(&u_9z%%vHtz^yYlOIt+ zDDDjFdS_9ge=ns|Uq}R{b$&poe-YKO147|DI}zO)<<7F(q$?Cw<_|;Ro>5_CvSIAH gYJ7e`xUCQ11|LTiHQKRo&W#< diff --git a/src/assets/images/avatareditor/ha-icon.png b/src/assets/images/avatareditor/ha-icon.png index 06d6328b47536d07ad005cf2d01ec803feb27f1d..f0a819181a29792921dad2a3f95d3c8ff3d10ee4 100644 GIT binary patch literal 241 zcmeAS@N?(olHy`uVBq!ia0vp^l0YoR!3-ps5|6h4DaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheYymzYuB%tC1~R=BGZKLmQ%R6t@PCG<+YP*cJkA1-$YKTtzQZ8Qcszea z3Q#c3)5S4FBY18er|(%y z{=_9$w%KyEub0!G5_Va3d5?Ed=dBWH?j1)iL|EQ>YM3Q*n0sTPNV)N)-v4J4t3UFb euC6ot?y~2F5aTSBDtA7hjSQZyelF{r5}E*2KvHM` literal 156 zcmZ?wbhEHblw=TNC}&_${K>+|00cT90wmV(pW#0ca1=8za>#fDBrq_rb8CfE7&shm z;Z~N?c@d!G+`(cPHD^b_V%L5S^SBa^pp;`>it=49GdCo9O%RSPn!-8h*@0=sn#aym z7^@tgYghk>$4W%`$U?jBPiIa}S#o)~U$v4;W>J>ws!;z!XSz&Zd#;yV*d_bgM1jE? E0Bi6!)&Kwi diff --git a/src/assets/images/avatareditor/ha-selected-icon.png b/src/assets/images/avatareditor/ha-selected-icon.png index 0d0d663844f911d6ebfe5b85e0f2d98ca7efd9ad..4c81ece52017e6bc405c53de21fe9909f3681724 100644 GIT binary patch delta 269 zcmcb^IG1UHWIZzj0|Qgy@fIM(SRCZ;#IWw1%u67LCEd~2k%3`jKlh(RRv@20z$e7j z$xQSAqeItrbS@}P1B&fbUGER1SWANZg8u^n!|!c;!9W4d0*}aI1_r*vAk26?e?GTD_M^4_x$mE+lPEP}n-L zE8uQ)^<>+_-)G)@ENs=Cs5~!i=j$55zN9Ecbq}#jv4|8Uzj7lQCHs3t3ZND~H# z!g2O0vBuRqvvN|B7Rbt4$=;_NVtW!zFf+a(QSlrgS)|32XGFDYwu+RnsDKj?uafQX z{s}v4%Wv&ps7Byw>xL<-%CSoqeGfO1Q=-$S!vBPXh%Sc=FeLpD0u}%O002ovPDHLk FV1nEuRYU*) diff --git a/src/assets/images/avatareditor/he-icon.png b/src/assets/images/avatareditor/he-icon.png index 5cc990dfce0c79cfffc39a745ec4153d92762a07..7cf6dc4c73ce9016b79aef9c886bbf842859c3b8 100644 GIT binary patch literal 267 zcmeAS@N?(olHy`uVBq!ia0vp^@<1%j!3-ofKU^XUq!^2X+?^QKos)S9vjzBsxUOEk8p!lk%t!=MOeH~n!T%YaZa44(@;D1TB8wRq_zr_Gpyr+tv%qUoUrjoH&hw1Q2zL$r9Zej3r^>bP0 Hl+XkKr9@%l literal 173 zcmZ?wbhEHblxL7;C}&_${K>+|00cT90wmV(pW#0caI`Qma>#HfG#qT^5EP0zaY5m5 zJ1e(biv+`>qa70BVS79RAGkHiTbg}Y5xB&yRY<+fWap Xl5}yE?Cxnx!#0U5Eo+q!V6X-Ny2(OK diff --git a/src/assets/images/avatareditor/he-selected-icon.png b/src/assets/images/avatareditor/he-selected-icon.png index e231488a613c87a6140d6833cfcde5ddc4e63806..32633559b9cba03803a5ac7f0b9d669bd521393f 100644 GIT binary patch delta 322 zcmeytc!_C(WIZzj1HNS%G}%0G|-o zEEl<%X~vEn+86tM4*oWpd0yn<*0%pQHvr{}xZD$g6lY10U+{k@UQz2)!fjFyYr$DK`=oD*xiS-$)ExxiwDx_9S3=TteWw3X&yT5| z?(?Xt&b52)6+d+Fo=3tVNK#bUi|49E_Pl>hAfoK!4CgZ)CScQ)2fzv?A=dP$5O8iO zA4*tDK!o#BMGqd)OkFL=0&_SexQ2!@$LrF>^;hjz@Th}#Y__|k!FS!8;*oQ20_M2Y h!=laaE$AyEdH}2wAWT(2=7svjzBsxUOEk8p!lk%t!=MOeH~n!T%YaZa44(@;D1TB8wRq_zr_G- x=A1mb%3EuL{k@dTcOIu%uNZE!IDFVpzlM`3y6(@BdY}s!JYD@<);T3K0RY~WTu}f3 literal 173 zcmZ?wbhEHblx2`)C}&_${K>+|00cT90wmV(pW#0caI`Qma>!^HG#qSZ<(E=9G2wwz z8^0`D#)}Dyjy4KwrtPUHRCeoAV5|_4oV57(L{;fLmzkTA4o=ds_v@KC;o0d9snBOj zI)hWr^k|53sm|Q2c4)qszmreYm&ZYK17fXey-Hu5UJLE8z+epk^+H1p diff --git a/src/assets/images/avatareditor/hr-selected-icon.png b/src/assets/images/avatareditor/hr-selected-icon.png index 65c03c05697ec2532f71e200800f4ec20eb2c30e..c694b82a5097b6f2ff485fe696db74429cb2b0e0 100644 GIT binary patch delta 332 zcmaFIc!z0%WIZzj1H-R7SG9o@V{wqX6T`Z5GB1G~mUKs7M+SzC{oH>NS%G~10G|+7 zAl=s177`M2blX}W`%i$yJRrqd666>B9|#zJZ{rIF3UC&9L>4nJ@ErzW#^d=bQh=3D>t-LW37x7!*n?pnO*+>Mhwr3*v1icS7tvp%=# z;34^}9gFt1ZlA`P`=f0(-{Jm4K(b>RhEo5BRS>U9+&}!>;xu z2WRDjejiR5cAoli<>?-k-)3qzcd&p7(8A5T-G@yGywoCbB-tg delta 221 zcmV<303!d~0`38j8Gi-<007MbB^dw!0JTX(K~zYI)s^cGfFKBkvGxA1Osi!pxf^yl zf7%kyCor)fA{dea%Ko+1iDrdooyNOP;8UkzM8u1OW&&By7CHh*yruFE)fqZ6%M0W6 zOnW8XM@jRZa&+T4KHQc%93mTwF@;PoZ6a}oa2Hsi-WjSHx>kYEWGeL)9Wf!brWtLb;&z-<>}4djZM< XLYg8xGa7)p00000NkvXXu0mjf-jZOF diff --git a/src/assets/images/icons/loading-icon.png b/src/assets/images/icons/loading-icon.png index 50d132b3e4e950ee4f6ab1622d9ebcb51fc157b2..e3d64d0bd0ee67afa9495f18681ad747c1abcfbe 100644 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^fa|ZZ?xYpO#pFVvW$ZPMP(Ey~FOM?7@|Nm#Weu@{UmVvXtBeIx*f$uN~ zGak=hkpdL-_jGX#(FpGC@A1W6X46^#_=zopr0597~LjV8( diff --git a/src/assets/styles/bootstrap/_variables.scss b/src/assets/styles/bootstrap/_variables.scss index 4298f5a2..1d1de900 100644 --- a/src/assets/styles/bootstrap/_variables.scss +++ b/src/assets/styles/bootstrap/_variables.scss @@ -78,6 +78,8 @@ $mirage: #131e25 !default; $aztec: #0d171d !default; $cello-light: #21516e !default; $cello-dark: #1e465e !default; +$pale-sky: #677181 !default; +$oslo-gray: #8F9297 !default; $success: $green !default; $info: $cyan !default; diff --git a/src/assets/styles/icons.scss b/src/assets/styles/icons.scss index 65b58de7..a56cfd12 100644 --- a/src/assets/styles/icons.scss +++ b/src/assets/styles/icons.scss @@ -2,502 +2,499 @@ line-height: 0 !important; } -i { - - &.icon { - display: inline-block; - outline: 0; - background-color: transparent; - background-repeat: no-repeat; - background-position: center; - background-size: contain; - - &.icon-nitro-light { - background-image: url('../images/nitro/nitro-n-light.svg'); - } - - &.icon-nitro-dark { - background-image: url('../images/nitro/nitro-n-dark.svg'); - } - - &.icon-nitro-light, - &.icon-nitro-dark { - width: 100%; - height: 40px; - } - - &.icon-catalog { - background-image: url('../images/toolbar/icons/catalog.png'); - width: 37px; - height: 36px; - } - - &.icon-rooms { - background-image: url('../images/toolbar/icons/rooms.png'); - width: 44px; - height: 30px; - } - - &.icon-house { - background-image: url('../images/toolbar/icons/house.png'); - height: 30px; - width: 32px; - } - - &.icon-inventory { - background-image: url('../images/toolbar/icons/inventory.png'); - height: 41px; - width: 44px; - } - - &.icon-modtools { - background-image: url('../images/toolbar/icons/modtools.png'); - height: 34px; - width: 29px; - } - - &.icon-friendall { - background-image: url('../images/toolbar/icons/friend_all.png'); - height: 33px; - width: 32px; - } - - &.icon-friendsearch { - background-image: url('../images/toolbar/icons/friend_search.png'); - height: 33px; - width: 29px; - } - - &.icon-sendmessage { - background-image: url('../images/toolbar/icons/sendmessage.png'); - width: 20px; - height: 21px; - } - - &.icon-me-talents { - background-image: url('../images/toolbar/icons/me-menu/talents.png'); - width: 32px; - height: 30px; - } - - &.icon-me-helper-tool { - background-image: url('../images/toolbar/icons/me-menu/helper-tool.png'); - width: 32px; - height: 30px; - } - - &.icon-me-profile { - background-image: url('../images/toolbar/icons/me-menu/profile.png'); - width: 32px; - height: 30px; - } - - &.icon-me-forums { - background-image: url('../images/toolbar/icons/me-menu/forums.png'); - width: 32px; - height: 30px; - } - - &.icon-me-rooms { - background-image: url('../images/toolbar/icons/me-menu/my-rooms.png'); - width: 30px; - height: 30px; - } - - &.icon-me-achievements { - background-image: url('../images/toolbar/icons/me-menu/achievements.png'); - width: 31px; - height: 30px; - } - - &.icon-me-clothing { - background-image: url('../images/toolbar/icons/me-menu/clothing.png'); - width: 27px; - height: 30px; - } - - &.icon-me-settings { - background-image: url('../images/toolbar/icons/me-menu/cog.png'); - width: 28px; - height: 34px; - } - - &.icon-joinroom { - background-image: url('../images/toolbar/icons/joinroom.png'); - width: 21px; - height: 21px; - } - - &.icon-habbo { - background-image: url('../images/toolbar/icons/habbo.png'); - width: 28px; - height: 28px; - } - - &.icon-camera { - background-image: url('../images/toolbar/icons/camera.png'); - width: 38px; - height: 45px; - } - - &.icon-message { - background-image: url('../images/toolbar/icons/message.png'); - width: 36px; - height: 32px; - - &.is-unseen { - background-image: url('../images/toolbar/icons/message_unsee.gif'); - } - } - - &.icon-wired-trigger { - background-image: url('../images/wired/icon_trigger.png'); - width: 13px; - height: 14px; - } - - &.icon-wired-condition { - background-image: url('../images/wired/icon_condition.png'); - width: 13px; - height: 14px; - } +.icon { + display: inline-block; + outline: 0; + background-color: transparent; + background-repeat: no-repeat; + background-position: center; + + &.icon-nitro-light { + background-image: url('../images/nitro/nitro-n-light.svg'); + } + + &.icon-nitro-dark { + background-image: url('../images/nitro/nitro-n-dark.svg'); + } + + &.icon-nitro-light, + &.icon-nitro-dark { + width: 100%; + height: 40px; + } + + &.icon-catalog { + background-image: url('../images/toolbar/icons/catalog.png'); + width: 37px; + height: 36px; + } + + &.icon-rooms { + background-image: url('../images/toolbar/icons/rooms.png'); + width: 44px; + height: 30px; + } + + &.icon-house { + background-image: url('../images/toolbar/icons/house.png'); + height: 30px; + width: 32px; + } + + &.icon-inventory { + background-image: url('../images/toolbar/icons/inventory.png'); + height: 41px; + width: 44px; + } + + &.icon-modtools { + background-image: url('../images/toolbar/icons/modtools.png'); + height: 34px; + width: 29px; + } + + &.icon-friendall { + background-image: url('../images/toolbar/icons/friend_all.png'); + height: 33px; + width: 32px; + } + + &.icon-friendsearch { + background-image: url('../images/toolbar/icons/friend_search.png'); + height: 33px; + width: 29px; + } + + &.icon-sendmessage { + background-image: url('../images/toolbar/icons/sendmessage.png'); + width: 20px; + height: 21px; + } + + &.icon-me-talents { + background-image: url('../images/toolbar/icons/me-menu/talents.png'); + width: 32px; + height: 30px; + } + + &.icon-me-helper-tool { + background-image: url('../images/toolbar/icons/me-menu/helper-tool.png'); + width: 32px; + height: 30px; + } + + &.icon-me-profile { + background-image: url('../images/toolbar/icons/me-menu/profile.png'); + width: 32px; + height: 30px; + } + + &.icon-me-forums { + background-image: url('../images/toolbar/icons/me-menu/forums.png'); + width: 32px; + height: 30px; + } + + &.icon-me-rooms { + background-image: url('../images/toolbar/icons/me-menu/my-rooms.png'); + width: 30px; + height: 30px; + } + + &.icon-me-achievements { + background-image: url('../images/toolbar/icons/me-menu/achievements.png'); + width: 31px; + height: 30px; + } + + &.icon-me-clothing { + background-image: url('../images/toolbar/icons/me-menu/clothing.png'); + width: 27px; + height: 30px; + } + + &.icon-me-settings { + background-image: url('../images/toolbar/icons/me-menu/cog.png'); + width: 28px; + height: 34px; + } + + &.icon-joinroom { + background-image: url('../images/toolbar/icons/joinroom.png'); + width: 21px; + height: 21px; + } + + &.icon-habbo { + background-image: url('../images/toolbar/icons/habbo.png'); + width: 28px; + height: 28px; + } + + &.icon-camera { + background-image: url('../images/toolbar/icons/camera.png'); + width: 38px; + height: 45px; + } + + &.icon-message { + background-image: url('../images/toolbar/icons/message.png'); + width: 36px; + height: 32px; + + &.is-unseen { + background-image: url('../images/toolbar/icons/message_unsee.gif'); + } + } + + &.icon-wired-trigger { + background-image: url('../images/wired/icon_trigger.png'); + width: 13px; + height: 14px; + } + + &.icon-wired-condition { + background-image: url('../images/wired/icon_condition.png'); + width: 13px; + height: 14px; + } + + &.icon-wired-action { + background-image: url('../images/wired/icon_action.png'); + width: 13px; + height: 14px; + } + + &.arrow-left-icon { + background-image: url('../images/avatareditor/arrow-left-icon.png'); + width: 28px; + height: 21px; + } + + &.arrow-right-icon { + background-image: url('../images/avatareditor/arrow-right-icon.png'); + width: 28px; + height: 21px; + } + + &.clear-icon { + background-image: url('../images/avatareditor/clear-icon.png'); + width: 16px; + height: 16px; + } + + &.ca-icon { + background-image: url('../images/avatareditor/ca-icon.png'); + width: 30px; + height: 24px; + background + + &.selected { + background-image: url('../images/avatareditor/ca-selected-icon.png'); + } + } - &.icon-wired-action { - background-image: url('../images/wired/icon_action.png'); - width: 13px; - height: 14px; - } + &.cc-icon { + background-image: url('../images/avatareditor/cc-icon.png'); + width: 31px; + height: 29px; + + &.selected { + background-image: url('../images/avatareditor/cc-selected-icon.png'); + } + } + + &.ch-icon { + background-image: url('../images/avatareditor/ch-icon.png'); + width: 29px; + height: 24px; - &.arrow-left-icon { - background-image: url('../images/avatareditor/arrow-left-icon.png'); - width: 28px; - height: 21px; + &.selected { + background-image: url('../images/avatareditor/ch-selected-icon.png'); } + } - &.arrow-right-icon { - background-image: url('../images/avatareditor/arrow-right-icon.png'); - width: 28px; - height: 21px; - } + &.cp-icon { + background-image: url('../images/avatareditor/cp-icon.png'); + width: 25px; + height: 25px; - &.clear-icon { - background-image: url('../images/avatareditor/clear-icon.png'); - width: 16px; - height: 16px; + &.selected { + background-image: url('../images/avatareditor/cp-selected-icon.png'); } + } - &.ca-icon { - background-image: url('../images/avatareditor/ca-icon.png'); - width: 30px; - height: 24px; + &.ea-icon { + background-image: url('../images/avatareditor/ea-icon.png'); + width: 35px; + height: 16px; - &.selected { - background-image: url('../images/avatareditor/ca-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/ea-selected-icon.png'); } + } - &.cc-icon { - background-image: url('../images/avatareditor/cc-icon.png'); - width: 31px; - height: 29px; + &.fa-icon { + background-image: url('../images/avatareditor/fa-icon.png'); + width: 27px; + height: 20px; - &.selected { - background-image: url('../images/avatareditor/cc-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/fa-selected-icon.png'); } + } - &.ch-icon { - background-image: url('../images/avatareditor/ch-icon.png'); - width: 29px; - height: 24px; + &.female-icon { + background-image: url('../images/avatareditor/female-icon.png'); + width: 18px; + height: 27px; - &.selected { - background-image: url('../images/avatareditor/ch-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/female-selected-icon.png'); } + } - &.cp-icon { - background-image: url('../images/avatareditor/cp-icon.png'); - width: 25px; - height: 25px; + &.ha-icon { + background-image: url('../images/avatareditor/ha-icon.png'); + width: 25px; + height: 22px; - &.selected { - background-image: url('../images/avatareditor/cp-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/ha-selected-icon.png'); } + } - &.ea-icon { - background-image: url('../images/avatareditor/ea-icon.png'); - width: 35px; - height: 16px; + &.he-icon { + background-image: url('../images/avatareditor/he-icon.png'); + width: 31px; + height: 27px; - &.selected { - background-image: url('../images/avatareditor/ea-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/he-selected-icon.png'); } + } - &.fa-icon { - background-image: url('../images/avatareditor/fa-icon.png'); - width: 27px; - height: 20px; + &.hr-icon { + background-image: url('../images/avatareditor/hr-icon.png'); + width: 29px; + height: 25px; - &.selected { - background-image: url('../images/avatareditor/fa-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/hr-selected-icon.png'); } + } - &.female-icon { - background-image: url('../images/avatareditor/female-icon.png'); - width: 18px; - height: 27px; + &.lg-icon { + background-image: url('../images/avatareditor/lg-icon.png'); + width: 19px; + height: 20px; - &.selected { - background-image: url('../images/avatareditor/female-selected-icon.png'); - } + &.selected { + background-image: url('../images/avatareditor/lg-selected-icon.png'); } + } - &.ha-icon { - background-image: url('../images/avatareditor/ha-icon.png'); - width: 25px; - height: 22px; + &.loading-icon { + background-image: url('../images/icons/loading-icon.png'); + width: 17px; + height: 21px; + } - &.selected { - background-image: url('../images/avatareditor/ha-selected-icon.png'); - } + &.male-icon { + background-image: url('../images/avatareditor/male-icon.png'); + width: 21px; + height: 21px; + + &.selected { + background-image: url('../images/avatareditor/male-selected-icon.png'); } - - &.he-icon { - background-image: url('../images/avatareditor/he-icon.png'); - width: 31px; - height: 27px; - - &.selected { - background-image: url('../images/avatareditor/he-selected-icon.png'); - } - } - - &.hr-icon { - background-image: url('../images/avatareditor/hr-icon.png'); - width: 29px; - height: 25px; - - &.selected { - background-image: url('../images/avatareditor/hr-selected-icon.png'); - } - } - - &.lg-icon { - background-image: url('../images/avatareditor/lg-icon.png'); - width: 19px; - height: 20px; - - &.selected { - background-image: url('../images/avatareditor/lg-selected-icon.png'); - } - } - - &.loading-icon { - background-image: url('../images/avatareditor/loading-icon.png'); - width: 21px; - height: 25px; - } - - &.male-icon { - background-image: url('../images/avatareditor/male-icon.png'); - width: 21px; - height: 21px; - - &.selected { - background-image: url('../images/avatareditor/male-selected-icon.png'); - } - } - - &.sh-icon { - background-image: url('../images/avatareditor/sh-icon.png'); - width: 37px; - height: 10px; - - &.selected { - background-image: url('../images/avatareditor/sh-selected-icon.png'); - } - } - - &.wa-icon { - background-image: url('../images/avatareditor/wa-icon.png'); - width: 36px; - height: 18px; - - &.selected { - background-image: url('../images/avatareditor/wa-selected-icon.png'); - } - } - - &.chatstyles-icon { - background-image: url('../images/chat/styles-icon.png'); - width: 17px; - height: 19px; - } - - &.pencil-icon { - background-image: url('../images/infostand/pencil-icon.png'); - width: 17px; - height: 18px; - } - - &.trade-locked-icon { - background-image: url('../images/inventory/trading/locked-icon.png'); - width: 29px; - height: 43px; - } - - &.trade-unlocked-icon { - background-image: url('../images/inventory/trading/unlocked-icon.png'); - width: 29px; - height: 43px; - } - - &.modtool-room-icon { - background-image: url('../images/modtool/room.png'); - width: 20px; - height: 15px; - } - - &.modtool-chatlog-icon { - background-image: url('../images/modtool/chatlog.gif'); - width: 20px; - height: 15px; - } - - &.modtool-user-icon{ - background-image: url('../images/modtool/user.gif'); - width: 20px; - height: 15px; - } - - &.modtool-reports-icon { - background-image: url('../images/modtool/reports.png'); - width: 20px; - height: 15px; - } - - &.modtool-wrench-icon { - background-image: url('../images/modtool/wrench.gif'); - width: 20px; - height: 15px; - } - - &.modtool-key-icon { - background-image: url('../images/modtool/key.gif'); - width: 20px; - height: 15px; - } - - &.icon-catalogue-hc_small { - background-image: url('../images/catalog/hc_small.png'); - height: 17px; - width: 31px; - } - - &.icon-catalogue-hc_big { - background: url('../images/catalog/hc_big.png'); - width: 68px; - height: 40px; - } - - &.icon-sign-exclamation { - background: url('../images/icons/sign-exclamation.png'); - width: 7px; - height: 17px; - } - - &.icon-sign-heart { - background: url('../images/icons/sign-heart.png'); - width: 15px; - height: 13px; - } - - &.icon-sign-red { - background: url('../images/icons/sign-red.png'); - width: 11px; - height: 19px; - } - - &.icon-sign-yellow { - background: url('../images/icons/sign-yellow.png'); - width: 11px; - height: 19px; - } - - &.icon-sign-skull { - background: url('../images/icons/sign-skull.png'); - width: 12px; - height: 12px; - } - - &.icon-sign-smile { - background: url('../images/icons/sign-smile.png'); - width: 7px; - height: 14px; - } - - &.icon-sign-soccer { - background: url('../images/icons/sign-soccer.png'); - width: 20px; - height: 20px; - } - - &.icon-camera-colormatrix { - background: url('../images/icons/camera-colormatrix.png'); - width: 32px; - height: 14px; - } - - &.icon-camera-composite { - background: url('../images/icons/camera-composite.png'); - width: 32px; - height: 14px; - } - - &.icon-user-profile { - background: url('../images/icons/user-profile.png'); - width: 13px; - height: 11px; - - &:hover { - background: url('../images/icons/user-profile-hover.png'); - } - } - - &.icon-fb-profile { - background: url('../images/toolbar/icons/friend-bar/profile.png'); - width: 21px; - height: 21px; - } - - &.icon-fb-chat { - background: url('../images/toolbar/icons/friend-bar/chat.png'); - width: 20px; - height: 21px; - } - - &.icon-fb-visit { - background: url('../images/toolbar/icons/friend-bar/visit.png'); - width: 21px; - height: 21px; - } - - &.spin { - animation: rotating 1s linear infinite; - } - - @keyframes rotating { - from { - transform: rotate(0); - } - - to { - transform: rotate(360deg); - } + } + + &.sh-icon { + background-image: url('../images/avatareditor/sh-icon.png'); + width: 37px; + height: 10px; + + &.selected { + background-image: url('../images/avatareditor/sh-selected-icon.png'); + } + } + + &.wa-icon { + background-image: url('../images/avatareditor/wa-icon.png'); + width: 36px; + height: 18px; + + &.selected { + background-image: url('../images/avatareditor/wa-selected-icon.png'); + } + } + + &.chatstyles-icon { + background-image: url('../images/chat/styles-icon.png'); + width: 17px; + height: 19px; + } + + &.pencil-icon { + background-image: url('../images/infostand/pencil-icon.png'); + width: 17px; + height: 18px; + } + + &.trade-locked-icon { + background-image: url('../images/inventory/trading/locked-icon.png'); + width: 29px; + height: 43px; + } + + &.trade-unlocked-icon { + background-image: url('../images/inventory/trading/unlocked-icon.png'); + width: 29px; + height: 43px; + } + + &.modtool-room-icon { + background-image: url('../images/modtool/room.png'); + width: 20px; + height: 15px; + } + + &.modtool-chatlog-icon { + background-image: url('../images/modtool/chatlog.gif'); + width: 20px; + height: 15px; + } + + &.modtool-user-icon{ + background-image: url('../images/modtool/user.gif'); + width: 20px; + height: 15px; + } + + &.modtool-reports-icon { + background-image: url('../images/modtool/reports.png'); + width: 20px; + height: 15px; + } + + &.modtool-wrench-icon { + background-image: url('../images/modtool/wrench.gif'); + width: 20px; + height: 15px; + } + + &.modtool-key-icon { + background-image: url('../images/modtool/key.gif'); + width: 20px; + height: 15px; + } + + &.icon-catalogue-hc_small { + background-image: url('../images/catalog/hc_small.png'); + height: 17px; + width: 31px; + } + + &.icon-catalogue-hc_big { + background: url('../images/catalog/hc_big.png'); + width: 68px; + height: 40px; + } + + &.icon-sign-exclamation { + background: url('../images/icons/sign-exclamation.png'); + width: 7px; + height: 17px; + } + + &.icon-sign-heart { + background: url('../images/icons/sign-heart.png'); + width: 15px; + height: 13px; + } + + &.icon-sign-red { + background: url('../images/icons/sign-red.png'); + width: 11px; + height: 19px; + } + + &.icon-sign-yellow { + background: url('../images/icons/sign-yellow.png'); + width: 11px; + height: 19px; + } + + &.icon-sign-skull { + background: url('../images/icons/sign-skull.png'); + width: 12px; + height: 12px; + } + + &.icon-sign-smile { + background: url('../images/icons/sign-smile.png'); + width: 7px; + height: 14px; + } + + &.icon-sign-soccer { + background: url('../images/icons/sign-soccer.png'); + width: 20px; + height: 20px; + } + + &.icon-camera-colormatrix { + background: url('../images/icons/camera-colormatrix.png'); + width: 32px; + height: 14px; + } + + &.icon-camera-composite { + background: url('../images/icons/camera-composite.png'); + width: 32px; + height: 14px; + } + + &.icon-user-profile { + background: url('../images/icons/user-profile.png'); + width: 13px; + height: 11px; + + &:hover { + background: url('../images/icons/user-profile-hover.png'); + } + } + + &.icon-fb-profile { + background: url('../images/toolbar/icons/friend-bar/profile.png'); + width: 21px; + height: 21px; + } + + &.icon-fb-chat { + background: url('../images/toolbar/icons/friend-bar/chat.png'); + width: 20px; + height: 21px; + } + + &.icon-fb-visit { + background: url('../images/toolbar/icons/friend-bar/visit.png'); + width: 21px; + height: 21px; + } + + &.spin { + animation: rotating 1s linear infinite; + } + + @keyframes rotating { + from { + transform: rotate(0); + } + + to { + transform: rotate(360deg); } } } diff --git a/src/layout/card/grid/NitroCardGridView.scss b/src/layout/card/grid/NitroCardGridView.scss index 44a1ee42..e424066a 100644 --- a/src/layout/card/grid/NitroCardGridView.scss +++ b/src/layout/card/grid/NitroCardGridView.scss @@ -10,6 +10,17 @@ } } } + + .row-cols-4 { + + .col { + padding-right: 0.25rem; + + &:nth-child(4n+4) { + padding-right: 0; + } + } + } .row-cols-5 { diff --git a/src/layout/card/grid/NitroCardGridView.tsx b/src/layout/card/grid/NitroCardGridView.tsx index 25b9fe47..4726910c 100644 --- a/src/layout/card/grid/NitroCardGridView.tsx +++ b/src/layout/card/grid/NitroCardGridView.tsx @@ -1,15 +1,18 @@ import { FC } from 'react'; -import { NitroCardGridViewProps } from './NitroCardGridView.types'; +import { NitroCardGridContextProvider } from './context/NitroCardGridContext'; +import { NitroCardGridThemes, NitroCardGridViewProps } from './NitroCardGridView.types'; export const NitroCardGridView: FC = props => { - const { columns = 5, children = null } = props; + const { columns = 5, theme = NitroCardGridThemes.THEME_DEFAULT, children = null } = props; return ( -
    -
    - { children } + +
    +
    + { children } +
    -
    + ); } diff --git a/src/layout/card/grid/NitroCardGridView.types.ts b/src/layout/card/grid/NitroCardGridView.types.ts index b24763d1..58c052ac 100644 --- a/src/layout/card/grid/NitroCardGridView.types.ts +++ b/src/layout/card/grid/NitroCardGridView.types.ts @@ -1,4 +1,11 @@ export interface NitroCardGridViewProps { columns?: number; + theme?: string; +} + +export class NitroCardGridThemes +{ + public static THEME_DEFAULT: string = 'theme-default'; + public static THEME_SHADOWED: string = 'theme-shadowed'; } diff --git a/src/layout/card/grid/context/NitroCardGridContext.tsx b/src/layout/card/grid/context/NitroCardGridContext.tsx new file mode 100644 index 00000000..18661b76 --- /dev/null +++ b/src/layout/card/grid/context/NitroCardGridContext.tsx @@ -0,0 +1,13 @@ +import { createContext, FC, useContext } from 'react'; +import { INitroCardGridContext, NitroCardGridContextProps } from './NitroCardGridContext.types'; + +const NitroCardGridContext = createContext({ + theme: null +}); + +export const NitroCardGridContextProvider: FC = props => +{ + return { props.children } +} + +export const useNitroCardGridContext = () => useContext(NitroCardGridContext); diff --git a/src/layout/card/grid/context/NitroCardGridContext.types.ts b/src/layout/card/grid/context/NitroCardGridContext.types.ts new file mode 100644 index 00000000..a0f97c95 --- /dev/null +++ b/src/layout/card/grid/context/NitroCardGridContext.types.ts @@ -0,0 +1,11 @@ +import { ProviderProps } from 'react'; + +export interface INitroCardGridContext +{ + theme: string; +} + +export interface NitroCardGridContextProps extends ProviderProps +{ + +} diff --git a/src/layout/card/grid/context/index.ts b/src/layout/card/grid/context/index.ts new file mode 100644 index 00000000..9e3f79e8 --- /dev/null +++ b/src/layout/card/grid/context/index.ts @@ -0,0 +1,2 @@ +export * from './NitroCardGridContext'; +export * from './NitroCardGridContext.types'; diff --git a/src/layout/card/grid/item/NitroCardGridItemView.scss b/src/layout/card/grid/item/NitroCardGridItemView.scss index 2ff2f0fd..19f6c716 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.scss +++ b/src/layout/card/grid/item/NitroCardGridItemView.scss @@ -1,15 +1,49 @@ .grid-item-container { - height: 48px; - max-height: 48px; + height: 50px; + max-height: 50px; .grid-item { + position: relative; width: 100%; height: 100%; - border-color: $grid-border-color !important; - background-color: $grid-bg-color; background-position: center; background-repeat: no-repeat; overflow: hidden; + + &.theme-default { + border-radius: $border-radius; + border-color: $grid-border-color !important; + background-color: $grid-bg-color; + border: nth(map-values($border-widths), 2) solid; + } + + &.theme-shadowed { + border-radius: $border-radius; + background-color: $light; + + &::after { + position: absolute; + content: ''; + top: 0; + bottom: 0; + left: 0; + right: 0; + border-radius: $border-radius; + border-bottom: 2px solid white; + border-right: 2px solid white; + box-shadow: -2px -2px rgba(0, 0, 0, .4), inset 3px 3px rgba(0, 0, 0, .2); + } + + &.active { + border: nth(map-values($border-widths), 2) solid; + border-color: $oslo-gray !important; + background-color: #F5F5F5; + + &:after { + content: unset; + } + } + } &.active { border-color: $grid-active-border-color !important; diff --git a/src/layout/card/grid/item/NitroCardGridItemView.tsx b/src/layout/card/grid/item/NitroCardGridItemView.tsx index 985a24bd..445851e1 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.tsx +++ b/src/layout/card/grid/item/NitroCardGridItemView.tsx @@ -1,16 +1,19 @@ import { FC } from 'react'; import { LimitedEditionStyledNumberView } from '../../../../views/shared/limited-edition/styled-number/LimitedEditionStyledNumberView'; +import { useNitroCardGridContext } from '../context'; +import { NitroCardGridThemes } from '../NitroCardGridView.types'; import { NitroCardGridItemViewProps } from './NitroCardGridItemView.types'; export const NitroCardGridItemView: FC = props => { - const { itemImage = null, itemActive = false, itemCount = 1, itemUnique = false, itemUniqueNumber = 0, itemUnseen = false, className = '', style = {}, children = null, ...rest } = props; + const { itemImage = undefined, itemColor = undefined, itemActive = false, itemCount = 1, itemUnique = false, itemUniqueNumber = 0, itemUnseen = false, className = '', style = {}, children = null, ...rest } = props; + const { theme = NitroCardGridThemes.THEME_DEFAULT } = useNitroCardGridContext(); const imageUrl = `url(${ itemImage })`; return (
    -
    +
    { (itemCount > 1) && { itemCount } } { itemUnique && diff --git a/src/layout/card/grid/item/NitroCardGridItemView.types.ts b/src/layout/card/grid/item/NitroCardGridItemView.types.ts index da6295c3..52e0242c 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.types.ts +++ b/src/layout/card/grid/item/NitroCardGridItemView.types.ts @@ -3,6 +3,7 @@ import { DetailsHTMLAttributes } from 'react'; export interface NitroCardGridItemViewProps extends DetailsHTMLAttributes { itemImage?: string; + itemColor?: string; itemActive?: boolean; itemCount?: number; itemUnique?: boolean; diff --git a/src/views/avatar-editor/AvatarEditorView.scss b/src/views/avatar-editor/AvatarEditorView.scss index ecc8cf0c..d94a3cdc 100644 --- a/src/views/avatar-editor/AvatarEditorView.scss +++ b/src/views/avatar-editor/AvatarEditorView.scss @@ -1,8 +1,51 @@ .nitro-avatar-editor { - width: 550px; + width: 600px; .content-area { - height: 300px; - max-height: 300px; + height: 330px; + max-height: 330px; + } + + .figure-preview-container { + position: relative; + height: 100%; + background-color: $pale-sky; + overflow: hidden; + z-index: 1; + + .avatar-image { + margin: 45px auto 0; + z-index: 2; + } + + .arrow-container { + position: absolute; + width: 100%; + margin: 0 auto; + display: flex; + justify-content: center; + bottom: 12px; + z-index: 3; + + .icon { + cursor: pointer; + } + + .arrow-left-icon { + margin-right: 10px; + } + } + + &:after { + position: absolute; + content: ''; + top: 75%; + bottom: 0; + left: 0; + right: 0; + border-radius: 50%; + background-color: red; + transform: scale(2); + } } } diff --git a/src/views/avatar-editor/AvatarEditorView.tsx b/src/views/avatar-editor/AvatarEditorView.tsx index 8fe50d8c..b8d5a07d 100644 --- a/src/views/avatar-editor/AvatarEditorView.tsx +++ b/src/views/avatar-editor/AvatarEditorView.tsx @@ -1,5 +1,6 @@ import { AvatarEditorFigureCategory } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; +import { GetSessionDataManager } from '../../api'; import { AvatarEditorEvent } from '../../events/avatar-editor'; import { useUiEvent } from '../../hooks/events/ui/ui-event'; import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout'; @@ -7,6 +8,7 @@ import { LocalizeText } from '../../utils/LocalizeText'; import { AvatarEditorViewProps } from './AvatarEditorView.types'; import { AvatarEditor } from './common/AvatarEditor'; import { BodyModel } from './common/BodyModel'; +import { FigureData } from './common/FigureData'; import { HeadModel } from './common/HeadModel'; import { IAvatarEditorCategoryModel } from './common/IAvatarEditorCategoryModel'; import { LegModel } from './common/LegModel'; @@ -24,6 +26,79 @@ export const AvatarEditorView: FC = props => const [ activeCategory, setActiveCategory ] = useState(null); const [ isInitalized, setIsInitalized ] = useState(false); + const selectCategory = useCallback((name: string) => + { + setActiveCategory(categories.get(name)); + }, [ categories ]); + + const resetCategories = useCallback((editor: AvatarEditor) => + { + const categories = new Map(); + + categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel(editor)); + categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel(editor)); + categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel(editor)); + categories.set(AvatarEditorFigureCategory.LEGS, new LegModel(editor)); + + setCategories(categories); + setActiveCategory(categories.get(AvatarEditorFigureCategory.GENERIC)); + }, []); + + const selectGender = useCallback((gender: string) => + { + if(gender === avatarEditor.gender) return; + + avatarEditor.gender = gender; + + resetCategories(avatarEditor); + }, [ avatarEditor, resetCategories ]); + + const loadAvatarInEditor = useCallback((figure: string, gender: string, reset: boolean = true) => + { + if(!avatarEditor) return; + + switch(gender) + { + case FigureData.MALE: + case 'm': + case 'M': + gender = FigureData.MALE; + break; + case FigureData.FEMALE: + case 'f': + case 'F': + gender = FigureData.FEMALE; + break; + default: + gender = FigureData.MALE; + } + + let update = false; + + if(gender !== avatarEditor.gender) + { + avatarEditor.gender = gender; + + update = true; + } + + const figureData = avatarEditor.figureData; + + if(!figureData) return; + + if(figure !== figureData.getFigureString()) + { + update = true; + } + + figureData.loadAvatarData(figure, gender); + + if(update) + { + resetCategories(avatarEditor); + } + }, [ avatarEditor, resetCategories ]); + const onAvatarEditorEvent = useCallback((event: AvatarEditorEvent) => { switch(event.type) @@ -35,7 +110,7 @@ export const AvatarEditorView: FC = props => setIsVisible(false); return; case AvatarEditorEvent.TOGGLE_EDITOR: - setIsVisible(value => !value); + setIsVisible(prevValue => !prevValue); return; } }, []); @@ -44,11 +119,6 @@ export const AvatarEditorView: FC = props => useUiEvent(AvatarEditorEvent.HIDE_EDITOR, onAvatarEditorEvent); useUiEvent(AvatarEditorEvent.TOGGLE_EDITOR, onAvatarEditorEvent); - const selectCategory = useCallback((name: string) => - { - setActiveCategory(categories.get(name)); - }, [ categories ]); - useEffect(() => { if(!isVisible || isInitalized) return; @@ -56,26 +126,23 @@ export const AvatarEditorView: FC = props => const newEditor = new AvatarEditor(); setAvatarEditor(newEditor); - - const categories = new Map(); - - categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel(newEditor)); - categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel(newEditor)); - categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel(newEditor)); - categories.set(AvatarEditorFigureCategory.LEGS, new LegModel(newEditor)); - - setCategories(categories); - setActiveCategory(categories.get(AvatarEditorFigureCategory.GENERIC)); setIsInitalized(true); }, [ isVisible, isInitalized ]); + useEffect(() => + { + if(!isVisible || !avatarEditor) return; + + loadAvatarInEditor(GetSessionDataManager().figure, GetSessionDataManager().gender); + }, [ isVisible, avatarEditor, loadAvatarInEditor ]); + return ( { isVisible && setIsVisible(false) } /> - { categories && Array.from(categories.keys()).map(category => + { categories && (categories.size > 0) && Array.from(categories.keys()).map(category => { return ( selectCategory(category) }> @@ -85,7 +152,7 @@ export const AvatarEditorView: FC = props => })} - { activeCategory && } + { activeCategory && } } diff --git a/src/views/avatar-editor/common/AvatarEditor.ts b/src/views/avatar-editor/common/AvatarEditor.ts index 4bd882b6..3ba88477 100644 --- a/src/views/avatar-editor/common/AvatarEditor.ts +++ b/src/views/avatar-editor/common/AvatarEditor.ts @@ -1,9 +1,10 @@ -import { FigureData, IPalette, IPartColor, ISetType, IStructureData } from 'nitro-renderer'; +import { IPalette, IPartColor, ISetType, IStructureData } from 'nitro-renderer'; import { GetAvatarRenderManager, GetConfiguration, GetSessionDataManager } from '../../../api'; import { AvatarEditorGridColorItem } from './AvatarEditorGridColorItem'; import { AvatarEditorGridPartItem } from './AvatarEditorGridPartItem'; import { CategoryBaseModel } from './CategoryBaseModel'; import { CategoryData } from './CategoryData'; +import { FigureData } from './FigureData'; const MAX_PALETTES: number = 2; const DEFAULT_MALE_FIGURE: string = 'hr-100.hd-180-7.ch-215-66.lg-270-79.sh-305-62.ha-1002-70.wa-2007'; @@ -11,16 +12,13 @@ const DEFAULT_FEMALE_FIGURE: string = 'hr-515-33.hd-600-1.ch-635-70.lg-716-66-62 export class AvatarEditor { - private _figureStructureData: IStructureData; - private _figures: Map; - private _gender: string; + private _figureStructureData: IStructureData = GetAvatarRenderManager().structureData; + private _figures: Map = new Map(); + private _gender: string = FigureData.MALE; + private _notifier: () => void = null; constructor() { - this._figureStructureData = GetAvatarRenderManager().structureData; - this._figures = new Map(); - this._gender = FigureData.MALE; - const maleFigure = new FigureData(); const femaleFigure = new FigureData(); @@ -160,6 +158,7 @@ export class AvatarEditor if(partSet.isSellable) { + isValid = false; //isValid = (this._inventoryService && this._inventoryService.hasFigureSetId(partSet.id)); } @@ -284,6 +283,24 @@ export class AvatarEditor public set gender(gender: string) { + if(this._gender === gender) return; + this._gender = gender; + + if(this.figureData) this.figureData.notify = this.notify; + + if(this.notify) this.notify(); + } + + public get notify(): () => void + { + return this._notifier; + } + + public set notify(notifier: () => void) + { + if(this.figureData) this.figureData.notify = notifier; + + this._notifier = notifier; } } diff --git a/src/views/avatar-editor/common/AvatarEditorGridColorItem.ts b/src/views/avatar-editor/common/AvatarEditorGridColorItem.ts index b6e99efd..9757b1fc 100644 --- a/src/views/avatar-editor/common/AvatarEditorGridColorItem.ts +++ b/src/views/avatar-editor/common/AvatarEditorGridColorItem.ts @@ -6,6 +6,7 @@ export class AvatarEditorGridColorItem private _isDisabled: boolean; private _isHC: boolean; private _isSelected: boolean; + private _notifier: () => void; constructor(partColor: IPartColor, isDisabled: boolean = false) { @@ -48,5 +49,17 @@ export class AvatarEditorGridColorItem public set isSelected(flag: boolean) { this._isSelected = flag; + + if(this.notify) this.notify(); + } + + public get notify(): () => void + { + return this._notifier; + } + + public set notify(notifier: () => void) + { + this._notifier = notifier; } } diff --git a/src/views/avatar-editor/common/AvatarEditorGridPartItem.ts b/src/views/avatar-editor/common/AvatarEditorGridPartItem.ts index f22b3718..4ac82a7f 100644 --- a/src/views/avatar-editor/common/AvatarEditorGridPartItem.ts +++ b/src/views/avatar-editor/common/AvatarEditorGridPartItem.ts @@ -1,5 +1,6 @@ -import { AvatarFigurePartType, FigureData, IAvatarImageListener, IAvatarRenderManager, IFigurePart, IFigurePartSet, IGraphicAsset, IPartColor, NitroContainer, NitroSprite, TextureUtils } from 'nitro-renderer'; +import { AvatarFigurePartType, IAvatarImageListener, IAvatarRenderManager, IFigurePart, IFigurePartSet, IGraphicAsset, IPartColor, NitroContainer, NitroSprite, TextureUtils } from 'nitro-renderer'; import { GetAvatarRenderManager } from '../../../api'; +import { FigureData } from './FigureData'; export class AvatarEditorGridPartItem implements IAvatarImageListener { @@ -47,6 +48,7 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener private _isSelected: boolean; private _disposed: boolean; private _isInitalized: boolean; + private _notifier: () => void; constructor(partSet: IFigurePartSet, partColors: IPartColor[], useColors: boolean = true, isDisabled: boolean = false) { @@ -210,6 +212,8 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener if(this._isDisabled) this.setAlpha(container, 0.2); this._imageUrl = TextureUtils.generateImageUrl(container); + + if(this.notify) this.notify(); } private setAlpha(container: NitroContainer, alpha: number): NitroContainer @@ -259,21 +263,21 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener return this._partSet; } - public set colors(partColors: IPartColor[]) + public set partColors(partColors: IPartColor[]) { this._partColors = partColors; this.update(); } - public get isDisabledForWearing(): boolean + public get isDisabled(): boolean { return this._isDisabled; } - public set iconImage(k: NitroContainer) + public set thumbContainer(container: NitroContainer) { - this._thumbContainer = k; + this._thumbContainer = container; this.update(); } @@ -283,7 +287,7 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener return this._imageUrl; } - public get colorLayerCount(): number + public get maxColorIndex(): number { return this._maxColorIndex; } @@ -316,5 +320,17 @@ export class AvatarEditorGridPartItem implements IAvatarImageListener public set isSelected(flag: boolean) { this._isSelected = flag; + + if(this.notify) this.notify(); + } + + public get notify(): () => void + { + return this._notifier; + } + + public set notify(notifier: () => void) + { + this._notifier = notifier; } } diff --git a/src/views/avatar-editor/common/BodyModel.ts b/src/views/avatar-editor/common/BodyModel.ts index b1419c10..41971d51 100644 --- a/src/views/avatar-editor/common/BodyModel.ts +++ b/src/views/avatar-editor/common/BodyModel.ts @@ -1,6 +1,7 @@ -import { AvatarEditorFigureCategory, AvatarScaleType, AvatarSetType, FigureData, IAvatarImageListener } from 'nitro-renderer'; +import { AvatarEditorFigureCategory, AvatarScaleType, AvatarSetType, IAvatarImageListener } from 'nitro-renderer'; import { GetAvatarRenderManager } from '../../../api'; import { CategoryBaseModel } from './CategoryBaseModel'; +import { FigureData } from './FigureData'; export class BodyModel extends CategoryBaseModel implements IAvatarImageListener { @@ -50,7 +51,7 @@ export class BodyModel extends CategoryBaseModel implements IAvatarImageListener { sprite.y = 10; - part.iconImage = sprite; + part.thumbContainer = sprite; setTimeout(() => avatarImage.dispose(), 0); } diff --git a/src/views/avatar-editor/common/CategoryBaseModel.ts b/src/views/avatar-editor/common/CategoryBaseModel.ts index d7ea50a2..9d1100ee 100644 --- a/src/views/avatar-editor/common/CategoryBaseModel.ts +++ b/src/views/avatar-editor/common/CategoryBaseModel.ts @@ -174,7 +174,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel if(!partItem) return; - if(partItem.isDisabledForWearing) + if(partItem.isDisabled) { categoryData.selectPartIndex(selectedPartIndex); @@ -183,7 +183,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel return; } - this._maxPaletteCount = partItem.colorLayerCount; + this._maxPaletteCount = partItem.maxColorIndex; this._editor.figureData.savePartData(category, partItem.id, categoryData.getSelectedColorIds(), true); } @@ -233,7 +233,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel public get maxPaletteCount(): number { - return this._maxPaletteCount; + return (this._maxPaletteCount || 1); } public set maxPaletteCount(count: number) diff --git a/src/views/avatar-editor/common/CategoryData.ts b/src/views/avatar-editor/common/CategoryData.ts index 54ffaa89..1b740037 100644 --- a/src/views/avatar-editor/common/CategoryData.ts +++ b/src/views/avatar-editor/common/CategoryData.ts @@ -266,7 +266,7 @@ export class CategoryData if(!partItem) return null; - return colorIds.slice(0, Math.max(partItem.colorLayerCount, 1)); + return colorIds.slice(0, Math.max(partItem.maxColorIndex, 1)); } private getSelectedColors(): IPartColor[] @@ -333,7 +333,7 @@ export class CategoryData for(const partItem of this._parts) { - if(partItem) partItem.colors = partColors; + if(partItem) partItem.partColors = partColors; } } diff --git a/src/views/avatar-editor/common/FigureData.ts b/src/views/avatar-editor/common/FigureData.ts new file mode 100644 index 00000000..2e447cb3 --- /dev/null +++ b/src/views/avatar-editor/common/FigureData.ts @@ -0,0 +1,271 @@ +export class FigureData +{ + public static MALE: string = 'M'; + public static FEMALE: string = 'F'; + public static UNISEX: string = 'U'; + public static SCALE: string = 'h'; + public static STD: string = 'std'; + public static DEFAULT_FRAME: string = '0'; + public static FACE: string = 'hd'; + public static HAIR: string = 'hr'; + public static HAT: string = 'ha'; + public static HEAD_ACCESSORIES: string = 'he'; + public static EYE_ACCESSORIES: string = 'ea'; + public static FACE_ACCESSORIES: string = 'fa'; + public static JACKET: string = 'cc'; + public static SHIRT: string = 'ch'; + public static CHEST_ACCESSORIES: string = 'ca'; + public static CHEST_PRINTS: string = 'cp'; + public static TROUSERS: string = 'lg'; + public static SHOES: string = 'sh'; + public static TROUSER_ACCESSORIES: string = 'wa'; + public static PREVIEW_AVATAR_DIRECTION: number = 4; + + private _data: Map; + private _colors: Map; + private _gender: string = 'M'; + private _avatarEffectType: number = -1; + private _notifier: () => void = null; + + public loadAvatarData(figureString: string, gender: string): void + { + this._data = new Map(); + this._colors = new Map(); + this._gender = gender; + + this.parseFigureString(figureString); + this.updateView(); + } + + private parseFigureString(figure: string): void + { + if(!figure) return; + + const sets = figure.split('.'); + + if(!sets || !sets.length) return; + + for(const set of sets) + { + const parts = set.split('-'); + + if(!parts.length) continue; + + const setType = parts[0]; + const setId = parseInt(parts[1]); + const colorIds: number[] = []; + + let offset = 2; + + while(offset < parts.length) + { + colorIds.push(parseInt(parts[offset])); + + offset++; + } + + if(!colorIds.length) colorIds.push(0); + + this.savePartSetId(setType, setId, false); + this.savePartSetColourId(setType, colorIds, false); + } + } + + public getPartSetId(partSetId: string): number + { + const existing = this._data.get(partSetId); + + if(existing !== undefined) return existing; + + return -1; + } + + public getColourIds(colorId: string): number[] + { + const existing = this._colors.get(colorId); + + if(existing !== undefined) return existing; + + return []; + // return [this._avatarEditor._Str_24919(k)]; + } + + public getFigureString(): string + { + let figureString = ''; + const setParts: string[] = []; + + for(const [ setType, setId ] of this._data.entries()) + { + const colorIds = this._colors.get(setType); + + let setPart = ((setType + '-') + setId); + + if(colorIds && colorIds.length) + { + let i = 0; + + while(i < colorIds.length) + { + setPart = (setPart + ('-' + colorIds[i])); + + i++; + } + } + + setParts.push(setPart); + } + + let i = 0; + + while(i < setParts.length) + { + figureString = (figureString + setParts[i]); + + if(i < (setParts.length - 1)) figureString = (figureString + '.'); + + i++; + } + + return figureString; + } + + public savePartData(k: string, _arg_2: number, _arg_3: number[], _arg_4: boolean = false): void + { + this.savePartSetId(k, _arg_2, _arg_4); + this.savePartSetColourId(k, _arg_3, _arg_4); + } + + private savePartSetId(k: string, _arg_2: number, _arg_3: boolean = true): void + { + switch(k) + { + case FigureData.FACE: + case FigureData.HAIR: + case FigureData.HAT: + case FigureData.HEAD_ACCESSORIES: + case FigureData.EYE_ACCESSORIES: + case FigureData.FACE_ACCESSORIES: + case FigureData.SHIRT: + case FigureData.JACKET: + case FigureData.CHEST_ACCESSORIES: + case FigureData.CHEST_PRINTS: + case FigureData.TROUSERS: + case FigureData.SHOES: + case FigureData.TROUSER_ACCESSORIES: + if(_arg_2 >= 0) + { + this._data.set(k, _arg_2); + } + else + { + this._data.delete(k); + } + break; + } + + if(_arg_3) this.updateView(); + } + + public savePartSetColourId(k: string, _arg_2: number[], _arg_3: boolean = true): void + { + switch(k) + { + case FigureData.FACE: + case FigureData.HAIR: + case FigureData.HAT: + case FigureData.HEAD_ACCESSORIES: + case FigureData.EYE_ACCESSORIES: + case FigureData.FACE_ACCESSORIES: + case FigureData.SHIRT: + case FigureData.JACKET: + case FigureData.CHEST_ACCESSORIES: + case FigureData.CHEST_PRINTS: + case FigureData.TROUSERS: + case FigureData.SHOES: + case FigureData.TROUSER_ACCESSORIES: + this._colors.set(k, _arg_2); + break; + } + + if(_arg_3) this.updateView(); + } + + public getFigureStringWithFace(k: number, override = true): string + { + let figureString = ''; + + const setTypes: string[] = [ FigureData.FACE ]; + const figureSets: string[] = []; + + for(const setType of setTypes) + { + const colors = this._colors.get(setType); + + if(colors === undefined) continue; + + let setId = this._data.get(setType); + + if((setType === FigureData.FACE) && override) setId = k; + + let figureSet = ((setType + '-') + setId); + + if(setId >= 0) + { + let i = 0; + + while(i < colors.length) + { + figureSet = (figureSet + ('-' + colors[i])); + + i++; + } + } + + figureSets.push(figureSet); + } + + let i = 0; + + while(i < figureSets.length) + { + figureString = (figureString + figureSets[i]); + + if(i < (figureSets.length - 1)) figureString = (figureString + '.'); + + i++; + } + + return figureString; + } + + public updateView(): void + { + if(this.notify) this.notify(); + } + + public get gender(): string + { + return this._gender; + } + + public set avatarEffectType(k: number) + { + this._avatarEffectType = k; + } + + public get avatarEffectType(): number + { + return this._avatarEffectType; + } + + public get notify(): () => void + { + return this._notifier; + } + + public set notify(notifier: () => void) + { + this._notifier = notifier; + } +} diff --git a/src/views/avatar-editor/common/HeadModel.ts b/src/views/avatar-editor/common/HeadModel.ts index 1635b79a..bb6276e8 100644 --- a/src/views/avatar-editor/common/HeadModel.ts +++ b/src/views/avatar-editor/common/HeadModel.ts @@ -1,5 +1,6 @@ -import { AvatarEditorFigureCategory, FigureData } from 'nitro-renderer'; +import { AvatarEditorFigureCategory } from 'nitro-renderer'; import { CategoryBaseModel } from './CategoryBaseModel'; +import { FigureData } from './FigureData'; export class HeadModel extends CategoryBaseModel { diff --git a/src/views/avatar-editor/common/LegModel.ts b/src/views/avatar-editor/common/LegModel.ts index 73b7bafe..02aec797 100644 --- a/src/views/avatar-editor/common/LegModel.ts +++ b/src/views/avatar-editor/common/LegModel.ts @@ -1,5 +1,6 @@ -import { AvatarEditorFigureCategory, FigureData } from 'nitro-renderer'; +import { AvatarEditorFigureCategory } from 'nitro-renderer'; import { CategoryBaseModel } from './CategoryBaseModel'; +import { FigureData } from './FigureData'; export class LegModel extends CategoryBaseModel { diff --git a/src/views/avatar-editor/common/TorsoModel.ts b/src/views/avatar-editor/common/TorsoModel.ts index 089ca366..2875ffa4 100644 --- a/src/views/avatar-editor/common/TorsoModel.ts +++ b/src/views/avatar-editor/common/TorsoModel.ts @@ -1,5 +1,6 @@ -import { AvatarEditorFigureCategory, FigureData } from 'nitro-renderer'; +import { AvatarEditorFigureCategory } from 'nitro-renderer'; import { CategoryBaseModel } from './CategoryBaseModel'; +import { FigureData } from './FigureData'; export class TorsoModel extends CategoryBaseModel { diff --git a/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx new file mode 100644 index 00000000..73e37a69 --- /dev/null +++ b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx @@ -0,0 +1,28 @@ +import { FC, useCallback, useEffect, useState } from 'react'; +import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView'; +import { AvatarEditorFigurePreviewViewProps } from './AvatarEditorFigurePreviewView.types'; + +export const AvatarEditorFigurePreviewView: FC = props => +{ + const { editor = null } = props; + const [ updateId, setUpdateId ] = useState(-1); + + const rerender = useCallback(() => + { + setUpdateId(prevValue => (prevValue + 1)); + }, []); + + useEffect(() => + { + if(!editor) return; + + editor.notify = rerender; + + return () => + { + editor.notify = null; + } + }, [ editor, rerender ] ); + + return +} diff --git a/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts new file mode 100644 index 00000000..0bfcf8f9 --- /dev/null +++ b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts @@ -0,0 +1,6 @@ +import { AvatarEditor } from '../../common/AvatarEditor'; + +export interface AvatarEditorFigurePreviewViewProps +{ + editor: AvatarEditor; +} diff --git a/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx b/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx index fcb268cc..ef4c0cc4 100644 --- a/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx +++ b/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx @@ -1,16 +1,31 @@ -import { FC, useEffect, useState } from 'react'; +import { FC, useCallback, useEffect, useState } from 'react'; import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView'; +import { CurrencyIcon } from '../../../shared/currency-icon/CurrencyIcon'; import { AvatarEditorFigureSetItemViewProps } from './AvatarEditorFigureSetItemView.types'; export const AvatarEditorFigureSetItemView: FC = props => { const { partItem = null, onClick = null } = props; - const [ imageUrl, setImageUrl ] = useState(null); + const [ updateId, setUpdateId ] = useState(-1); + + const rerender = useCallback(() => + { + setUpdateId(prevValue => (prevValue + 1)); + }, []); useEffect(() => { - setImageUrl(partItem.imageUrl); - }, [ partItem.imageUrl ]); + partItem.notify = rerender; - return onClick(partItem) } /> + return () => + { + partItem.notify = null; + } + }) + + return ( + onClick(partItem) }> + { partItem.isHC && } + + ); } diff --git a/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx index e16afae6..c97fffdd 100644 --- a/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx +++ b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.tsx @@ -1,28 +1,33 @@ import { FC, useCallback } from 'react'; import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; +import { NitroCardGridThemes } from '../../../../layout/card/grid/NitroCardGridView.types'; import { AvatarEditorGridPartItem } from '../../common/AvatarEditorGridPartItem'; import { AvatarEditorFigureSetItemView } from '../figure-set-item/AvatarEditorFigureSetItemView'; import { AvatarEditorFigureSetViewProps } from './AvatarEditorFigureSetView.types'; export const AvatarEditorFigureSetView: FC = props => { - const { model = null, category = null } = props; + const { model = null, category = null, setMaxPaletteCount = null } = props; - const selectPart = useCallback((part: AvatarEditorGridPartItem) => + const selectPart = useCallback((item: AvatarEditorGridPartItem) => { - const index = category.parts.indexOf(part); + const index = category.parts.indexOf(item); if(index === -1) return; model.selectPart(category.name, index); - }, [ model, category ]); + + const partItem = category.getCurrentPart(); + + setMaxPaletteCount(partItem.maxColorIndex || 1); + }, [ model, category, setMaxPaletteCount ]); return ( - + { (category.parts.length > 0) && category.parts.map((item, index) => { return ; }) } - ) + ); } diff --git a/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts index b44992be..d2e9e5cf 100644 --- a/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts +++ b/src/views/avatar-editor/views/figure-set/AvatarEditorFigureSetView.types.ts @@ -1,3 +1,4 @@ +import { Dispatch, SetStateAction } from 'react'; import { CategoryData } from '../../common/CategoryData'; import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel'; @@ -5,4 +6,5 @@ export interface AvatarEditorFigureSetViewProps { model: IAvatarEditorCategoryModel; category: CategoryData; + setMaxPaletteCount: Dispatch>; } diff --git a/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx b/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx index 4dfc58d0..c842c94e 100644 --- a/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx +++ b/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx @@ -1,17 +1,19 @@ +import { UserFigureComposer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; +import { SendMessageHook } from '../../../../hooks'; +import { LocalizeText } from '../../../../utils/LocalizeText'; import { CategoryData } from '../../common/CategoryData'; +import { FigureData } from '../../common/FigureData'; +import { AvatarEditorFigurePreviewView } from '../figure-preview/AvatarEditorFigurePreviewView'; import { AvatarEditorFigureSetView } from '../figure-set/AvatarEditorFigureSetView'; +import { AvatarEditorPaletteSetView } from '../palette-set/AvatarEditorPaletteSetView'; import { AvatarEditorModelViewProps } from './AvatarEditorModelView.types'; export const AvatarEditorModelView: FC = props => { - const { model = null, editor = null } = props; + const { model = null, editor = null, selectGender = null } = props; const [ activeCategory, setActiveCategory ] = useState(null); - - const selectGender = useCallback((gender: string) => - { - editor.gender = gender; - }, [ editor ]); + const [ maxPaletteCount, setMaxPaletteCount ] = useState(1); const selectCategory = useCallback((name: string) => { @@ -27,12 +29,19 @@ export const AvatarEditorModelView: FC = props => { if(!part || !part.isSelected) continue; - model.maxPaletteCount = part.colorLayerCount; + setMaxPaletteCount(part.maxColorIndex || 1); break; } }, [ model ]); + const saveFigure = useCallback(() => + { + const figureData = editor.figureData; + + SendMessageHook(new UserFigureComposer(figureData.gender, figureData.getFigureString())); + }, [ editor ]); + useEffect(() => { model.init(); @@ -45,16 +54,54 @@ export const AvatarEditorModelView: FC = props => } }, [ model, selectCategory ]); - if(!activeCategory) return null; + if(!model || !activeCategory) return null; return (
    -
    -
    - +
    + { model.canSetGender && + <> + selectGender(FigureData.MALE) } /> + selectGender(FigureData.FEMALE) } /> + } + { !model.canSetGender && model.categories && (model.categories.size > 0) && Array.from(model.categories.keys()).map(name => + { + const category = model.categories.get(name); + + return ( + selectCategory(name) } /> + ); + })} +
    +
    + +
    +
    +
    + +
    + + +
    +
    +
    +
    + + +
    + +
    +
    +
    + { (maxPaletteCount >= 1) && + } + { (maxPaletteCount === 2) && + }
    -
    -
    ); } diff --git a/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts b/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts index 322e9a86..dc81491a 100644 --- a/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts +++ b/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts @@ -5,4 +5,5 @@ export interface AvatarEditorModelViewProps { model: IAvatarEditorCategoryModel; editor: AvatarEditor; + selectGender: (gender: string) => void; } diff --git a/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx new file mode 100644 index 00000000..2dab88d1 --- /dev/null +++ b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx @@ -0,0 +1,26 @@ +import { FC, useCallback, useEffect, useState } from 'react'; +import { NitroCardGridItemView } from '../../../../layout/card/grid/item/NitroCardGridItemView'; +import { AvatarEditorPaletteSetItemProps } from './AvatarEditorPaletteSetItem.types'; + +export const AvatarEditorPaletteSetItem: FC = props => +{ + const { colorItem = null, onClick = null } = props; + const [ updateId, setUpdateId ] = useState(-1); + + const rerender = useCallback(() => + { + setUpdateId(prevValue => (prevValue + 1)); + }, []); + + useEffect(() => + { + colorItem.notify = rerender; + + return () => + { + colorItem.notify = null; + } + }) + + return onClick(colorItem) } /> +} diff --git a/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts new file mode 100644 index 00000000..5930f9a4 --- /dev/null +++ b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts @@ -0,0 +1,7 @@ +import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem'; + +export interface AvatarEditorPaletteSetItemProps +{ + colorItem: AvatarEditorGridColorItem; + onClick: (item: AvatarEditorGridColorItem) => void; +} diff --git a/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx new file mode 100644 index 00000000..fc8c4fc9 --- /dev/null +++ b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx @@ -0,0 +1,29 @@ +import { FC, useCallback } from 'react'; +import { NitroCardGridView } from '../../../../layout/card/grid/NitroCardGridView'; +import { NitroCardGridThemes } from '../../../../layout/card/grid/NitroCardGridView.types'; +import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem'; +import { AvatarEditorPaletteSetItem } from '../palette-set-item/AvatarEditorPaletteSetItem'; +import { AvatarEditorPaletteSetViewProps } from './AvatarEditorPaletteSetView.types'; + +export const AvatarEditorPaletteSetView: FC = props => +{ + const { model = null, category = null, paletteSet = [], paletteIndex = -1 } = props; + + const selectColor = useCallback((item: AvatarEditorGridColorItem) => + { + const index = paletteSet.indexOf(item); + + if(index === -1) return; + + model.selectColor(category.name, index, paletteIndex); + }, [ model, category, paletteSet, paletteIndex ]); + + return ( + + { (paletteSet.length > 0) && paletteSet.map((item, index) => + { + return ; + }) } + + ); +} diff --git a/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts new file mode 100644 index 00000000..9fa8e2b6 --- /dev/null +++ b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts @@ -0,0 +1,11 @@ +import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem'; +import { CategoryData } from '../../common/CategoryData'; +import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel'; + +export interface AvatarEditorPaletteSetViewProps +{ + model: IAvatarEditorCategoryModel; + category: CategoryData; + paletteSet: AvatarEditorGridColorItem[]; + paletteIndex: number; +} diff --git a/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx b/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx index 859a1f69..de3c10c4 100644 --- a/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx +++ b/src/views/room/widgets/furniture/context-menu/views/purchaseable-clothing/PurchasableClothingConfirmView.tsx @@ -1,8 +1,9 @@ -import { FigureData, RedeemItemClothingComposer, RoomObjectCategory, UserFigureComposer } from 'nitro-renderer'; +import { RedeemItemClothingComposer, RoomObjectCategory, UserFigureComposer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; import { GetAvatarRenderManager, GetConnection, GetFurnitureDataForRoomObject, GetSessionDataManager } from '../../../../../../../api'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../../../../layout'; import { LocalizeText } from '../../../../../../../utils/LocalizeText'; +import { FigureData } from '../../../../../../avatar-editor/common/FigureData'; import { FurniCategory } from '../../../../../../inventory/common/FurniCategory'; import { AvatarImageView } from '../../../../../../shared/avatar-image/AvatarImageView'; import { useRoomContext } from '../../../../../context/RoomContext'; diff --git a/src/views/shared/avatar-image/AvatarImage.scss b/src/views/shared/avatar-image/AvatarImage.scss index c1d05822..f85ca9c4 100644 --- a/src/views/shared/avatar-image/AvatarImage.scss +++ b/src/views/shared/avatar-image/AvatarImage.scss @@ -5,4 +5,5 @@ background-repeat: no-repeat; background-position-x: center; background-position-y: -8px !important; + pointer-events: none; } diff --git a/src/views/toolbar/ToolbarView.tsx b/src/views/toolbar/ToolbarView.tsx index 28419e69..72ed9010 100644 --- a/src/views/toolbar/ToolbarView.tsx +++ b/src/views/toolbar/ToolbarView.tsx @@ -1,4 +1,4 @@ -import { Dispose, DropBounce, EaseOut, JumpBy, Motions, NitroToolbarAnimateIconEvent, Queue, Wait } from 'nitro-renderer'; +import { Dispose, DropBounce, EaseOut, JumpBy, Motions, NitroToolbarAnimateIconEvent, Queue, UserFigureEvent, Wait } from 'nitro-renderer'; import { UserInfoEvent } from 'nitro-renderer/src/nitro/communication/messages/incoming/user/data/UserInfoEvent'; import { UserInfoDataParser } from 'nitro-renderer/src/nitro/communication/messages/parser/user/data/UserInfoDataParser'; import { FC, useCallback, useState } from 'react'; @@ -17,6 +17,7 @@ export const ToolbarView: FC = props => const { isInRoom } = props; const [ userInfo, setUserInfo ] = useState(null); + const [ userFigure, setUserFigure ] = useState(null); const [ isMeExpanded, setMeExpanded ] = useState(false); const [ unseenInventoryCount, setUnseenInventoryCount ] = useState(0); @@ -28,10 +29,20 @@ export const ToolbarView: FC = props => const parser = event.getParser(); setUserInfo(parser.userInfo); + setUserFigure(parser.userInfo.figure); }, []); CreateMessageHook(UserInfoEvent, onUserInfoEvent); + const onUserFigureEvent = useCallback((event: UserFigureEvent) => + { + const parser = event.getParser(); + + setUserFigure(parser.figure); + }, []); + + CreateMessageHook(UserFigureEvent, onUserFigureEvent); + const onUnseenItemTrackerUpdateEvent = useCallback((event: UnseenItemTrackerUpdateEvent) => { setUnseenInventoryCount(event.count); @@ -116,7 +127,7 @@ export const ToolbarView: FC = props =>
    setMeExpanded(!isMeExpanded) }> - { userInfo && } + { userFigure && }
    { (unseenAchievementsCount > 0) && ( From 918d2eb6bd34173aba2baf9a6d2bd41ac05fe102 Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 21 Jul 2021 03:09:03 -0400 Subject: [PATCH 58/72] Avatar editor updates --- src/api/nitro/avatar/GetAvatarPalette.ts | 7 + src/api/nitro/avatar/GetAvatarSetType.ts | 7 + src/api/nitro/avatar/index.ts | 2 + src/api/nitro/session/GetClubMemberLevel.ts | 6 + src/api/nitro/session/index.ts | 1 + src/assets/images/avatareditor/clear-icon.png | Bin 263 -> 272 bytes .../images/avatareditor/female-icon.png | Bin 146 -> 236 bytes .../avatareditor/female-selected-icon.png | Bin 196 -> 270 bytes src/assets/images/avatareditor/lg-icon.png | Bin 135 -> 196 bytes .../images/avatareditor/lg-selected-icon.png | Bin 162 -> 236 bytes src/assets/images/avatareditor/male-icon.png | Bin 137 -> 228 bytes .../avatareditor/male-selected-icon.png | Bin 195 -> 256 bytes src/assets/images/avatareditor/sh-icon.png | Bin 122 -> 208 bytes .../images/avatareditor/sh-selected-icon.png | Bin 165 -> 266 bytes src/assets/images/avatareditor/wa-icon.png | Bin 164 -> 257 bytes .../images/avatareditor/wa-selected-icon.png | Bin 199 -> 308 bytes src/assets/styles/icons.scss | 13 +- .../card/content/NitroCardContentView.scss | 2 + src/layout/card/grid/NitroCardGridView.tsx | 4 +- .../card/grid/NitroCardGridView.types.ts | 4 +- .../card/grid/item/NitroCardGridItemView.scss | 3 + src/views/avatar-editor/AvatarEditorView.scss | 61 +++- src/views/avatar-editor/AvatarEditorView.tsx | 260 ++++++++++++------ ...atarEditor.ts => AvatarEditorUtilities.ts} | 175 +++++------- src/views/avatar-editor/common/BodyModel.ts | 9 +- .../avatar-editor/common/CategoryBaseModel.ts | 24 +- src/views/avatar-editor/common/FigureData.ts | 34 ++- .../AvatarEditorFigurePreviewView.tsx | 12 +- .../AvatarEditorFigurePreviewView.types.ts | 4 +- .../AvatarEditorFigureSetItemView.tsx | 3 +- .../views/model/AvatarEditorModelView.tsx | 53 +--- .../model/AvatarEditorModelView.types.ts | 6 +- .../AvatarEditorPaletteSetItem.tsx | 4 +- .../AvatarEditorPaletteSetItem.types.ts | 4 +- .../AvatarEditorPaletteSetView.tsx | 6 +- .../AvatarEditorPaletteSetView.types.ts | 3 +- 36 files changed, 407 insertions(+), 300 deletions(-) create mode 100644 src/api/nitro/avatar/GetAvatarPalette.ts create mode 100644 src/api/nitro/avatar/GetAvatarSetType.ts create mode 100644 src/api/nitro/session/GetClubMemberLevel.ts rename src/views/avatar-editor/common/{AvatarEditor.ts => AvatarEditorUtilities.ts} (62%) diff --git a/src/api/nitro/avatar/GetAvatarPalette.ts b/src/api/nitro/avatar/GetAvatarPalette.ts new file mode 100644 index 00000000..af3526c3 --- /dev/null +++ b/src/api/nitro/avatar/GetAvatarPalette.ts @@ -0,0 +1,7 @@ +import { IPalette } from 'nitro-renderer'; +import { GetAvatarRenderManager } from './GetAvatarRenderManager'; + +export function GetAvatarPalette(paletteId: number): IPalette +{ + return GetAvatarRenderManager().structureData.getPalette(paletteId); +} diff --git a/src/api/nitro/avatar/GetAvatarSetType.ts b/src/api/nitro/avatar/GetAvatarSetType.ts new file mode 100644 index 00000000..ba7c8edd --- /dev/null +++ b/src/api/nitro/avatar/GetAvatarSetType.ts @@ -0,0 +1,7 @@ +import { ISetType } from 'nitro-renderer'; +import { GetAvatarRenderManager } from './GetAvatarRenderManager'; + +export function GetAvatarSetType(setType: string): ISetType +{ + return GetAvatarRenderManager().structureData.getSetType(setType); +} diff --git a/src/api/nitro/avatar/index.ts b/src/api/nitro/avatar/index.ts index 0076857a..258a1ced 100644 --- a/src/api/nitro/avatar/index.ts +++ b/src/api/nitro/avatar/index.ts @@ -1 +1,3 @@ +export * from './GetAvatarPalette'; export * from './GetAvatarRenderManager'; +export * from './GetAvatarSetType'; diff --git a/src/api/nitro/session/GetClubMemberLevel.ts b/src/api/nitro/session/GetClubMemberLevel.ts new file mode 100644 index 00000000..be5e3ffc --- /dev/null +++ b/src/api/nitro/session/GetClubMemberLevel.ts @@ -0,0 +1,6 @@ +import { GetSessionDataManager } from './GetSessionDataManager'; + +export function GetClubMemberLevel(): number +{ + return GetSessionDataManager().clubLevel; +} diff --git a/src/api/nitro/session/index.ts b/src/api/nitro/session/index.ts index ff62191c..31861a96 100644 --- a/src/api/nitro/session/index.ts +++ b/src/api/nitro/session/index.ts @@ -1,6 +1,7 @@ export * from './CanManipulateFurniture'; export * from './GetCanStandUp'; export * from './GetCanUseExpression'; +export * from './GetClubMemberLevel'; export * from './GetFurnitureDataForProductOffer'; export * from './GetFurnitureDataForRoomObject'; export * from './GetOwnPosture'; diff --git a/src/assets/images/avatareditor/clear-icon.png b/src/assets/images/avatareditor/clear-icon.png index 5123270aae46af8eefc40134e4ccf73a84e9222f..e0d50abca8bec826229748f4b83deb79888594af 100644 GIT binary patch literal 272 zcmeAS@N?(olHy`uVBq!ia0vp^(jd&i3?z4Pv7`ej#^NA%Cx&(BWL^R}Ea{HEjtmSN z`?>!lvI6-$0X`wF_4V~f4(;E#ZY5Aa=f>$fAax}{e!>6$|7UQ}TKNUY=PdAuEM{Qf zI}E~%$MaXD00nD3T^vI+f@9BK6l*ZxU<%0o|Ns0=2i97NzT1(7&)+!8`k!-~vZ3`& zMqB7q&NAW6c~&mnS{@mb4_%jPsh2$%&9G zmoNLZE=rwryL_l@|E*lxWQo}PtW$!Y%=830gu&C* K&t;ucLK6Vke`HAj literal 263 zcmV+i0r>ujP)+|00cT90wmV(pW#0caAYzta>z(5Sa7hBgOkmJV}Ziq zHhxaE7>U3|4qaTbN=rHf7ai@EbM(8@vGK86tGs)hj^sv_)9rfxt5|MsT;?;Gt#Db6 urLdaMWZuR}F_9nB0vEd$ue)+0AmhY5quFvir=~o=yhN!#NK{II!5RRn7BcGq diff --git a/src/assets/images/avatareditor/female-selected-icon.png b/src/assets/images/avatareditor/female-selected-icon.png index bfddd6b217f140e98f910bdcd11cf60453156a3a..50ffde0999e1a120ebe110feede7c6606c511e23 100644 GIT binary patch literal 270 zcmeAS@N?(olHy`uVBq!ia0vp^LO?9d!3-qbJ3`31=5EbxddW?978mMmrn2&YB1n%zIgBdxk=Nn_{Z)rI44jetFe?#Ys#DeX`_&g z4U5~{L=`$iJEB^@vM=m3p6{r}+&bg0i+A;$m9`Hp!|m70ukz7Yld6=G_R)Ltfo#i7 zZT+IBVqL6i9cMYTZjXzyExt2B-)HUN-2wk<7u$p;_b|`aWIpWb+{zAg27{-opUXO@ GgeCy3+F73f literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^0zfRu!3HEP{;XRGq`Ey_978O6?*=>aH7M}B=J@~r zQ;(X&8d;ymjXR{HuZzAob63$xjZs2fYwlvVb@N@GI&PK;vAoE7I`vH5wxVq1&dGNQ zS<|K+SnzC3!WA9Ei=vk{$~hk67WeV|^L>TbFNcX9kDj@3&oSd--s^ab*<2?-S$j|1 w^A3%W@676}%x6?SxSboq^^0@$f2IcBsRyNO#s3)Z0XmDp)78&qol`;+0A1fpE&u=k diff --git a/src/assets/images/avatareditor/lg-icon.png b/src/assets/images/avatareditor/lg-icon.png index aa9782f68bf5c01a4405cfdf27f370cee9021829..0bdd750e4ec304e7725bcef1891d2957e09f4d77 100644 GIT binary patch literal 196 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv-!3-oLy1%&rDaPU;cPEB*=VV?2IV|apzK#qG z8~eHcB(eheYymzYuB%tC1~R=BGZKLmQ%R6t@PCG<+YP*cJkA1-$YKTtzQZ8Qcszea z3Q*9})5S4FBRDxBCB=c&fl#~JO0!)j<&Nw|?%yjAKhD{IF iNiroFFeDorFfbf?$;hl_Ccq6egu&C*&t;ucLK6Unk}_KW literal 135 zcmZ?wbhEHb6lM@%C}&_${K>+|00cT90wmV(pW#0caKte%GH^I-Sa7hJiCv3FVS?h} zRsl{v9gDz4uAQ9HX=gkPA0BR(vb8#5G4b)yUX8#>J~N9{PxtCcAJbVGw9spUOzxp0 iF9VmKoMz|B^i;Dr!+ViHzEo(G@Jq)Qe{MDw25SJZ=q*YB diff --git a/src/assets/images/avatareditor/lg-selected-icon.png b/src/assets/images/avatareditor/lg-selected-icon.png index d2dfdc72d93b6c8bf575010aba023e32fdc6e25d..7a2853b0272603ea329037f4fbe060b4b8ab4ca9 100644 GIT binary patch delta 219 zcmZ3)_=a(UWIZzj14BgjH#Z=~SRCZ;#IWw1%u67LCEd~2k%3`jKlh(RRv@20z$e5N zNJsT-FpI4U+7%83X4!THj-5a9 zfd-N6x0m3S{tsJi_Y+LgfgM-@lRo59W_|(U&lfKxy7e~z015yANkvXXu0mjfR9`*8 diff --git a/src/assets/images/avatareditor/male-icon.png b/src/assets/images/avatareditor/male-icon.png index aeca1540a347f96eb2114e603d8a97f26786755e..95a1b35267aeeba204ae4c2076fe2c26a0daa767 100644 GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^q9Dw{3?%2B3|#`G7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`1M1^9%xu3o(w$n;jsNCZ+$B|(0{{~4ZcH}C@TI14-?iy0XB4ude`@%$Aj zK*2~)7sn8d;I)0;d<=>l&JX`h5BtrSbnLE) literal 137 zcmZ?wbhEHb6lD-)C}&_${K>+|00cT90wmV(pW#0ca3nA=a>#fTBs4U0@QcM{Y)D{e z6OcD6nGvw)NGFqMP)x-~r6X-(_EszlE+~7pC>u{wd9hLT^mNV8Q!ytuD7#HIFTQrg kbF%XJc@mAgc(OKWc+K#ze>7)ju%=(HlE2y?2>}Lc02cNyI{*Lx diff --git a/src/assets/images/avatareditor/male-selected-icon.png b/src/assets/images/avatareditor/male-selected-icon.png index 3b437c7be92a1fa8c6f0a786806adcad25c1c05c..85debbb3ef2634ce46e8790558cc1c98c4b66ff9 100644 GIT binary patch literal 256 zcmeAS@N?(olHy`uVBq!ia0vp^q9Dw{3?%2B3|#`G7>k44ofy`glX(f`u%tWsIx;Y9 z?C1WI$O`211o(uw0_jCh{s--N4Pah(T>d>cMXHD{tH>YCql~P|BA!Aznz{IpcBNkeQjEnx?oJHr&dIz4iKRRGIx;Y9 z?C1WI$O`1M1^9%xu3o(w$n;jsNCZ+$B|(0{{~4ZcH}C@TI14-?iy0XB4ude`@%$Aj zKtWee7sn8d;HiC#Tnq|4OxOS0-(6BNRj@=ypmcGDlA3DE>72lh`(jh0+_(K-6eapZ vT6tR7A(?xdS=l!io9=M@Gi@!Sv9i^fe+(Z@mIyBd8pz=3>gTe~DWM4fPHa9M literal 122 zcmZ?wbhEHbRAt~|C}&_${K>+|00cT90wmV(pW#0ca0D_ia>#fXG#qSZV^nbQ*s$<$ z8>5U{568!aN4rEd#rB*CeC*cG>}VIG5%j>NTg7nNpA&%#Pfjqf-ZkZCk(ES#>oZ-YXIyeEZ_hD diff --git a/src/assets/images/avatareditor/sh-selected-icon.png b/src/assets/images/avatareditor/sh-selected-icon.png index 3bdb60521e1249dc9433de433ebd1ed594035043..12c6deb1fb8d7e519e7cb0a09125ddaf7d5b599e 100644 GIT binary patch delta 251 zcmZ3=*u^wKyq=4LnSp_UWmozoAjMc5tq4(EAG;tGVOo@moH!b|NlRbvGPTcD3D?=3GxdDihu;AyqVpALYxI2k;M!Qe1}1p z@p%4<6rf(iwCZ{~8REtBz#uFEJ6nmoZvak^_ppzsf?zrmbhMwWH0 oifeD=WTX}?TJrU9{bz=n##1cQk{I0<0PSV)boFyt=akR{078ITk^lez delta 150 zcmV;H0BQe<0;K_v7k>)~1^@s6_&7vG0001NNklT^L=PBxb^rhX07*qoM6N<$ Ef+5B_oB#j- diff --git a/src/assets/images/avatareditor/wa-icon.png b/src/assets/images/avatareditor/wa-icon.png index 75dffe5b19458c9550ffbb7ef0dd899c6407aea6..8a73b7aef1f23cf4bf38945bd95d23a2e693d349 100644 GIT binary patch literal 257 zcmeAS@N?(olHy`uVBq!ia0vp^DnKm6!3-o>{`N=#DaPU;cPEB*=VV@j#L^vo9T^xl z_H+M9WCils0(?STSFc_TWO^%RBmya>k|4j}{|ryJ8+ZYEoCO|{#S9F5he4R}c>anM zpkSG&i(`mJaBCl@P=f&n^XdQgy3#AA-AbOj(zD}An(M^i(-9OP8^mo;s1Kd-zq+|00cT90wmV(pW#0ca8xrea>#gWSa5)WgIOZx#07;z z%`Bp3b0Pv3y0(jGtKH!UOghr5VC$4q5%|b;60@tG&drIBPBx3#PV?b#cuak2BIoJ9&dd{`N=#DaPU;cPEB*=VV@j#L^vo9T^xl z_H+M9WCf`V@Ck7R(x0X<{6E96CfmNuQya+jSNJLhq}WP={DS|30K?|}OZEdrI14-? ziy0XB4ude`@%$AjK*5=wE{-7@!L1Xy`Hm=Xux@eld}4^Obi#s&9Wi)$%zz_d0f0|L)3Cpd%SPUHx3vIVCg!0KTJfaR2}S literal 199 zcmeAS@N?(olHy`uVBq!ia0vp^N9Z=x7a`FHF zP0fxQJJ;FtzMa?d=-n1?F+ndUVFRafmiO6#tGQQf?hy2Em}}LtO`#=e>U*R6>XS?l zW|-~z_OPY5w@Q79f@NCY zI>h=uZ7^$Elp+|WyM@OsVn0t7`~Sz+1uk+*|C7{m+jC3?=rRURS3j3^P6 = props => { - const { columns = 5, theme = NitroCardGridThemes.THEME_DEFAULT, children = null } = props; + const { columns = 5, theme = NitroCardGridThemes.THEME_DEFAULT, className = '', children = null, ...rest } = props; return ( -
    +
    { children }
    diff --git a/src/layout/card/grid/NitroCardGridView.types.ts b/src/layout/card/grid/NitroCardGridView.types.ts index 58c052ac..f3cc6c80 100644 --- a/src/layout/card/grid/NitroCardGridView.types.ts +++ b/src/layout/card/grid/NitroCardGridView.types.ts @@ -1,4 +1,6 @@ -export interface NitroCardGridViewProps +import { DetailsHTMLAttributes } from 'react'; + +export interface NitroCardGridViewProps extends DetailsHTMLAttributes { columns?: number; theme?: string; diff --git a/src/layout/card/grid/item/NitroCardGridItemView.scss b/src/layout/card/grid/item/NitroCardGridItemView.scss index 19f6c716..69de83c1 100644 --- a/src/layout/card/grid/item/NitroCardGridItemView.scss +++ b/src/layout/card/grid/item/NitroCardGridItemView.scss @@ -3,6 +3,9 @@ max-height: 50px; .grid-item { + display: flex; + justify-content: center; + align-items: center; position: relative; width: 100%; height: 100%; diff --git a/src/views/avatar-editor/AvatarEditorView.scss b/src/views/avatar-editor/AvatarEditorView.scss index d94a3cdc..aaef735d 100644 --- a/src/views/avatar-editor/AvatarEditorView.scss +++ b/src/views/avatar-editor/AvatarEditorView.scss @@ -1,9 +1,13 @@ .nitro-avatar-editor { - width: 600px; + width: 620px; .content-area { - height: 330px; - max-height: 330px; + min-height: 300px; + height: 300px; + } + + .category-item { + height: 40px; } .figure-preview-container { @@ -13,27 +17,53 @@ overflow: hidden; z-index: 1; - .avatar-image { - margin: 45px auto 0; - z-index: 2; - } - .arrow-container { position: absolute; width: 100%; margin: 0 auto; + padding: 0 10px; display: flex; - justify-content: center; + justify-content: space-between; bottom: 12px; - z-index: 3; + z-index: 5; .icon { cursor: pointer; } - - .arrow-left-icon { - margin-right: 10px; - } + } + + .avatar-image { + position: absolute; + left: 0; + right: 0; + bottom: 50px; + margin: 0 auto; + z-index: 4; + } + + .avatar-spotlight { + position: absolute; + top: -10px; + width: 100%; + height: 305px; + margin: 0 auto; + background: transparent url('../../assets/images/avatareditor/spotlight.png') no-repeat center; + opacity: 0.3; + pointer-events: none; + z-index: 3; + } + + .avatar-shadow { + position: absolute; + left: 0; + right: 0; + bottom: 15px; + width: 70px; + height: 30px; + margin: 0 auto; + border-radius: 100%; + background-color: rgba(0, 0, 0, 0.20); + z-index: 2; } &:after { @@ -44,7 +74,8 @@ left: 0; right: 0; border-radius: 50%; - background-color: red; + background-color: $pale-sky; + box-shadow: 0 0 8px 2px rgba($white,.6); transform: scale(2); } } diff --git a/src/views/avatar-editor/AvatarEditorView.tsx b/src/views/avatar-editor/AvatarEditorView.tsx index b8d5a07d..1695ad15 100644 --- a/src/views/avatar-editor/AvatarEditorView.tsx +++ b/src/views/avatar-editor/AvatarEditorView.tsx @@ -1,103 +1,91 @@ -import { AvatarEditorFigureCategory } from 'nitro-renderer'; -import { FC, useCallback, useEffect, useReducer, useState } from 'react'; +import { AvatarDirectionAngle, AvatarEditorFigureCategory, UserFigureComposer } from 'nitro-renderer'; +import { FC, useCallback, useEffect, useState } from 'react'; import { GetSessionDataManager } from '../../api'; import { AvatarEditorEvent } from '../../events/avatar-editor'; +import { SendMessageHook } from '../../hooks'; import { useUiEvent } from '../../hooks/events/ui/ui-event'; import { NitroCardContentView, NitroCardHeaderView, NitroCardTabsItemView, NitroCardTabsView, NitroCardView } from '../../layout'; import { LocalizeText } from '../../utils/LocalizeText'; import { AvatarEditorViewProps } from './AvatarEditorView.types'; -import { AvatarEditor } from './common/AvatarEditor'; +import { AvatarEditorUtilities } from './common/AvatarEditorUtilities'; import { BodyModel } from './common/BodyModel'; import { FigureData } from './common/FigureData'; import { HeadModel } from './common/HeadModel'; import { IAvatarEditorCategoryModel } from './common/IAvatarEditorCategoryModel'; import { LegModel } from './common/LegModel'; import { TorsoModel } from './common/TorsoModel'; -import { AvatarEditorContextProvider } from './context/AvatarEditorContext'; -import { AvatarEditorReducer, initialAvatarEditor } from './reducers/AvatarEditorReducer'; +import { AvatarEditorFigurePreviewView } from './views/figure-preview/AvatarEditorFigurePreviewView'; import { AvatarEditorModelView } from './views/model/AvatarEditorModelView'; +const DEFAULT_MALE_FIGURE: string = 'hr-100.hd-180-7.ch-215-66.lg-270-79.sh-305-62.ha-1002-70.wa-2007'; +const DEFAULT_FEMALE_FIGURE: string = 'hr-515-33.hd-600-1.ch-635-70.lg-716-66-62.sh-735-68'; + export const AvatarEditorView: FC = props => { const [ isVisible, setIsVisible ] = useState(false); - const [ avatarEditorState, dispatchAvatarEditorState ] = useReducer(AvatarEditorReducer, initialAvatarEditor); - const [ avatarEditor, setAvatarEditor ] = useState(null); + const [ figures, setFigures ] = useState>(null); + const [ figureData, setFigureData ] = useState(null); const [ categories, setCategories ] = useState>(null); const [ activeCategory, setActiveCategory ] = useState(null); + const [ lastFigure, setLastFigure ] = useState(null); + const [ lastGender, setLastGender ] = useState(null); + const [ needsReset, setNeedsReset ] = useState(false); const [ isInitalized, setIsInitalized ] = useState(false); const selectCategory = useCallback((name: string) => { + if(!categories) return; + setActiveCategory(categories.get(name)); }, [ categories ]); - const resetCategories = useCallback((editor: AvatarEditor) => + const resetCategories = useCallback(() => { const categories = new Map(); - categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel(editor)); - categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel(editor)); - categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel(editor)); - categories.set(AvatarEditorFigureCategory.LEGS, new LegModel(editor)); + categories.set(AvatarEditorFigureCategory.GENERIC, new BodyModel()); + categories.set(AvatarEditorFigureCategory.HEAD, new HeadModel()); + categories.set(AvatarEditorFigureCategory.TORSO, new TorsoModel()); + categories.set(AvatarEditorFigureCategory.LEGS, new LegModel()); setCategories(categories); - setActiveCategory(categories.get(AvatarEditorFigureCategory.GENERIC)); }, []); - const selectGender = useCallback((gender: string) => + const setupFigures = useCallback(() => { - if(gender === avatarEditor.gender) return; - - avatarEditor.gender = gender; + const figures: Map = new Map(); - resetCategories(avatarEditor); - }, [ avatarEditor, resetCategories ]); + const maleFigure = new FigureData(); + const femaleFigure = new FigureData(); + + maleFigure.loadAvatarData(DEFAULT_MALE_FIGURE, FigureData.MALE); + femaleFigure.loadAvatarData(DEFAULT_FEMALE_FIGURE, FigureData.FEMALE); + + figures.set(FigureData.MALE, maleFigure); + figures.set(FigureData.FEMALE, femaleFigure); + + setFigures(figures); + setFigureData(figures.get(FigureData.MALE)); + }, []); const loadAvatarInEditor = useCallback((figure: string, gender: string, reset: boolean = true) => { - if(!avatarEditor) return; - - switch(gender) + gender = AvatarEditorUtilities.getGender(gender); + + let newFigureData = figureData; + + if(gender !== newFigureData.gender) newFigureData = figures.get(gender); + + if(figure !== newFigureData.getFigureString()) newFigureData.loadAvatarData(figure, gender); + + if(newFigureData !== figureData) setFigureData(newFigureData); + + if(reset) { - case FigureData.MALE: - case 'm': - case 'M': - gender = FigureData.MALE; - break; - case FigureData.FEMALE: - case 'f': - case 'F': - gender = FigureData.FEMALE; - break; - default: - gender = FigureData.MALE; + setLastFigure(figureData.getFigureString()); + setLastGender(figureData.gender); } - - let update = false; - - if(gender !== avatarEditor.gender) - { - avatarEditor.gender = gender; - - update = true; - } - - const figureData = avatarEditor.figureData; - - if(!figureData) return; - - if(figure !== figureData.getFigureString()) - { - update = true; - } - - figureData.loadAvatarData(figure, gender); - - if(update) - { - resetCategories(avatarEditor); - } - }, [ avatarEditor, resetCategories ]); + }, [ figures, figureData ]); const onAvatarEditorEvent = useCallback((event: AvatarEditorEvent) => { @@ -105,12 +93,20 @@ export const AvatarEditorView: FC = props => { case AvatarEditorEvent.SHOW_EDITOR: setIsVisible(true); + setNeedsReset(true); return; case AvatarEditorEvent.HIDE_EDITOR: setIsVisible(false); return; case AvatarEditorEvent.TOGGLE_EDITOR: - setIsVisible(prevValue => !prevValue); + setIsVisible(prevValue => + { + const flag = !prevValue; + + if(flag) setNeedsReset(true); + + return flag; + }); return; } }, []); @@ -119,42 +115,130 @@ export const AvatarEditorView: FC = props => useUiEvent(AvatarEditorEvent.HIDE_EDITOR, onAvatarEditorEvent); useUiEvent(AvatarEditorEvent.TOGGLE_EDITOR, onAvatarEditorEvent); - useEffect(() => + const clearFigure = useCallback(() => { - if(!isVisible || isInitalized) return; + loadAvatarInEditor(figureData.getFigureStringWithFace(0, false), figureData.gender, false); + resetCategories(); + }, [ figureData, loadAvatarInEditor, resetCategories ]); - const newEditor = new AvatarEditor(); + const resetFigure = useCallback(() => + { + loadAvatarInEditor(lastFigure, lastGender); + resetCategories(); + }, [ lastFigure, lastGender, loadAvatarInEditor, resetCategories ]); - setAvatarEditor(newEditor); - setIsInitalized(true); - }, [ isVisible, isInitalized ]); + const rotateFigure = useCallback((direction: number) => + { + if(direction < AvatarDirectionAngle.MIN_DIRECTION) + { + direction = (AvatarDirectionAngle.MAX_DIRECTION + (direction + 1)); + } + + if(direction > AvatarDirectionAngle.MAX_DIRECTION) + { + direction = (direction - (AvatarDirectionAngle.MAX_DIRECTION + 1)); + } + + figureData.direction = direction; + }, [ figureData ]); + + const saveFigure = useCallback(() => + { + SendMessageHook(new UserFigureComposer(figureData.gender, figureData.getFigureString())); + }, [ figureData ]); + + const setGender = useCallback((gender: string) => + { + gender = AvatarEditorUtilities.getGender(gender); + + setFigureData(figures.get(gender)); + }, [ figures ]); useEffect(() => { - if(!isVisible || !avatarEditor) return; + if(!categories) return; + + selectCategory(AvatarEditorFigureCategory.GENERIC); + }, [ categories, selectCategory ]); + + useEffect(() => + { + if(!figureData) return; + + AvatarEditorUtilities.CURRENT_FIGURE = figureData; + + resetCategories(); + + return () => AvatarEditorUtilities.CURRENT_FIGURE = null; + }, [ figureData, resetCategories ]); + + useEffect(() => + { + if(!isVisible) return; + + if(!figures) + { + setupFigures(); + + setIsInitalized(true); + + return; + } + }, [ isVisible, figures, setupFigures ]); + + useEffect(() => + { + if(!isVisible || !isInitalized || !needsReset) return; loadAvatarInEditor(GetSessionDataManager().figure, GetSessionDataManager().gender); - }, [ isVisible, avatarEditor, loadAvatarInEditor ]); + setNeedsReset(false); + }, [ isVisible, isInitalized, needsReset, loadAvatarInEditor ]); + + if(!isVisible) return null; return ( - - { isVisible && - - setIsVisible(false) } /> - - { categories && (categories.size > 0) && Array.from(categories.keys()).map(category => - { - return ( - selectCategory(category) }> - { LocalizeText(`avatareditor.category.${ category }`) } - - ); - })} - - - { activeCategory && } - - } - + + setIsVisible(false) } /> + + { categories && (categories.size > 0) && activeCategory && Array.from(categories.keys()).map(category => + { + return ( + selectCategory(category) }> + { LocalizeText(`avatareditor.category.${ category }`) } + + ); + })} + + +
    +
    + { activeCategory && } +
    +
    + { figureData && +
    + +
    +
    +
    + rotateFigure(figureData.direction + 1) } /> + rotateFigure(figureData.direction - 1) } /> +
    +
    } +
    +
    + + +
    + +
    +
    +
    + + ); } diff --git a/src/views/avatar-editor/common/AvatarEditor.ts b/src/views/avatar-editor/common/AvatarEditorUtilities.ts similarity index 62% rename from src/views/avatar-editor/common/AvatarEditor.ts rename to src/views/avatar-editor/common/AvatarEditorUtilities.ts index 3ba88477..eb8b9d25 100644 --- a/src/views/avatar-editor/common/AvatarEditor.ts +++ b/src/views/avatar-editor/common/AvatarEditorUtilities.ts @@ -1,88 +1,79 @@ -import { IPalette, IPartColor, ISetType, IStructureData } from 'nitro-renderer'; -import { GetAvatarRenderManager, GetConfiguration, GetSessionDataManager } from '../../../api'; +import { IPartColor } from 'nitro-renderer'; +import { GetAvatarPalette, GetAvatarRenderManager, GetAvatarSetType, GetClubMemberLevel, GetConfiguration } from '../../../api'; import { AvatarEditorGridColorItem } from './AvatarEditorGridColorItem'; import { AvatarEditorGridPartItem } from './AvatarEditorGridPartItem'; import { CategoryBaseModel } from './CategoryBaseModel'; import { CategoryData } from './CategoryData'; import { FigureData } from './FigureData'; -const MAX_PALETTES: number = 2; -const DEFAULT_MALE_FIGURE: string = 'hr-100.hd-180-7.ch-215-66.lg-270-79.sh-305-62.ha-1002-70.wa-2007'; -const DEFAULT_FEMALE_FIGURE: string = 'hr-515-33.hd-600-1.ch-635-70.lg-716-66-62.sh-735-68'; - -export class AvatarEditor +export class AvatarEditorUtilities { - private _figureStructureData: IStructureData = GetAvatarRenderManager().structureData; - private _figures: Map = new Map(); - private _gender: string = FigureData.MALE; - private _notifier: () => void = null; + private static MAX_PALETTES: number = 2; - constructor() + public static CURRENT_FIGURE: FigureData = null; + + public static getGender(gender: string): string { - const maleFigure = new FigureData(); - const femaleFigure = new FigureData(); + switch(gender) + { + case FigureData.MALE: + case 'm': + case 'M': + gender = FigureData.MALE; + break; + case FigureData.FEMALE: + case 'f': + case 'F': + gender = FigureData.FEMALE; + break; + default: + gender = FigureData.MALE; + } - maleFigure.loadAvatarData(DEFAULT_MALE_FIGURE, FigureData.MALE); - femaleFigure.loadAvatarData(DEFAULT_FEMALE_FIGURE, FigureData.FEMALE); - - this._figures.set(FigureData.MALE, maleFigure); - this._figures.set(FigureData.FEMALE, femaleFigure); + return gender; } - public getSetType(setType: string): ISetType + public static createCategory(model: CategoryBaseModel, name: string): CategoryData { - if(!this._figureStructureData) return null; - - return this._figureStructureData.getSetType(setType); - } - - public getPalette(paletteId: number): IPalette - { - if(!this._figureStructureData) return null; - - return this._figureStructureData.getPalette(paletteId); - } - - public createCategory(model: CategoryBaseModel, name: string): CategoryData - { - if(!model || !name) return null; + if(!model || !name || !this.CURRENT_FIGURE) return null; const partItems: AvatarEditorGridPartItem[] = []; const colorItems: AvatarEditorGridColorItem[][] = []; let i = 0; - while(i < MAX_PALETTES) + while(i < this.MAX_PALETTES) { colorItems.push([]); i++; } - const setType = this.getSetType(name); + const setType = GetAvatarSetType(name); if(!setType) return null; - const palette = this.getPalette(setType.paletteID); + const palette = GetAvatarPalette(setType.paletteID); if(!palette) return null; - let colorIds = this.figureData.getColourIds(name); + let colorIds = this.CURRENT_FIGURE.getColorIds(name); if(!colorIds) colorIds = []; const partColors: IPartColor[] = new Array(colorIds.length); const clubItemsDimmed = this.clubItemsDimmed; + const clubMemberLevel = GetClubMemberLevel(); for(const partColor of palette.colors.values()) { - if(partColor.isSelectable && (clubItemsDimmed || (this.clubMemberLevel >= partColor.clubLevel))) + if(partColor.isSelectable && (clubItemsDimmed || (clubMemberLevel >= partColor.clubLevel))) { let i = 0; - while(i < MAX_PALETTES) + while(i < this.MAX_PALETTES) { - const isDisabled = (this.clubMemberLevel < partColor.clubLevel); + const isDisabled = (clubMemberLevel < partColor.clubLevel); const colorItem = new AvatarEditorGridColorItem(partColor, isDisabled); colorItems[i].push(colorItem); @@ -108,11 +99,11 @@ export class AvatarEditor if(clubItemsDimmed) { - mandatorySetIds = GetAvatarRenderManager().getMandatoryAvatarPartSetIds(this._gender, 2); + mandatorySetIds = GetAvatarRenderManager().getMandatoryAvatarPartSetIds(this.CURRENT_FIGURE.gender, 2); } else { - mandatorySetIds = GetAvatarRenderManager().getMandatoryAvatarPartSetIds(this._gender, this.clubMemberLevel); + mandatorySetIds = GetAvatarRenderManager().getMandatoryAvatarPartSetIds(this.CURRENT_FIGURE.gender, clubMemberLevel); } const isntMandatorySet = (mandatorySetIds.indexOf(name) === -1); @@ -142,17 +133,15 @@ export class AvatarEditor { isValidGender = true; } - else + + else if(partSet.gender === this.CURRENT_FIGURE.gender) { - if(partSet.gender === this._gender) - { - isValidGender = true; - } + isValidGender = true; } - if(partSet.isSelectable && isValidGender && (clubItemsDimmed || (this.clubMemberLevel >= partSet.clubLevel))) + if(partSet.isSelectable && isValidGender && (clubItemsDimmed || (clubMemberLevel >= partSet.clubLevel))) { - const isDisabled = (this.clubMemberLevel < partSet.clubLevel); + const isDisabled = (clubMemberLevel < partSet.clubLevel); let isValid = true; @@ -186,7 +175,7 @@ export class AvatarEditor i = 0; - while(i < MAX_PALETTES) + while(i < this.MAX_PALETTES) { colorItems[i].sort(this.colorSorter); @@ -196,7 +185,7 @@ export class AvatarEditor return new CategoryData(name, partItems, colorItems); } - private clubSorter(a: AvatarEditorGridPartItem, b: AvatarEditorGridPartItem): number + public static clubSorter(a: AvatarEditorGridPartItem, b: AvatarEditorGridPartItem): number { const clubLevelA = (!a.partSet ? 9999999999 : a.partSet.clubLevel); const clubLevelB = (!b.partSet ? 9999999999 : b.partSet.clubLevel); @@ -218,7 +207,23 @@ export class AvatarEditor return 0; } - private noobSorter(a: AvatarEditorGridPartItem, b: AvatarEditorGridPartItem): number + public static colorSorter(a: AvatarEditorGridColorItem, b: AvatarEditorGridColorItem): number + { + const clubLevelA = (!a.partColor ? -1 : a.partColor.clubLevel); + const clubLevelB = (!b.partColor ? -1 : b.partColor.clubLevel); + + if(clubLevelA < clubLevelB) return -1; + + if(clubLevelA > clubLevelB) return 1; + + if(a.partColor.index < b.partColor.index) return -1; + + if(a.partColor.index > b.partColor.index) return 1; + + return 0; + } + + public static noobSorter(a: AvatarEditorGridPartItem, b: AvatarEditorGridPartItem): number { const clubLevelA = (!a.partSet ? -1 : a.partSet.clubLevel); const clubLevelB = (!b.partSet ? -1 : b.partSet.clubLevel); @@ -240,67 +245,33 @@ export class AvatarEditor return 0; } - private colorSorter(a: AvatarEditorGridColorItem, b: AvatarEditorGridColorItem): number + public static avatarSetFirstSelectableColor(name: string): number { - const clubLevelA = (!a.partColor ? -1 : a.partColor.clubLevel); - const clubLevelB = (!b.partColor ? -1 : b.partColor.clubLevel); + const setType = GetAvatarSetType(name); - if(clubLevelA < clubLevelB) return -1; + if(!setType) return -1; - if(clubLevelA > clubLevelB) return 1; + const palette = GetAvatarPalette(setType.paletteID); - if(a.partColor.index < b.partColor.index) return -1; + if(!palette) return -1; - if(a.partColor.index > b.partColor.index) return 1; + for(const color of palette.colors.values()) + { + if(!color.isSelectable || (GetClubMemberLevel() < color.clubLevel)) continue; - return 0; + return color.id; + } + + return -1; } - public get clubMemberLevel(): number - { - return GetSessionDataManager().clubLevel; - } - - private get clubItemsFirst(): boolean + public static get clubItemsFirst(): boolean { return GetConfiguration('avatareditor.show.clubitems.first', true); } - private get clubItemsDimmed(): boolean + public static get clubItemsDimmed(): boolean { return GetConfiguration('avatareditor.show.clubitems.dimmed', true); } - - public get figureData(): FigureData - { - return this._figures.get(this._gender); - } - - public get gender(): string - { - return this._gender; - } - - public set gender(gender: string) - { - if(this._gender === gender) return; - - this._gender = gender; - - if(this.figureData) this.figureData.notify = this.notify; - - if(this.notify) this.notify(); - } - - public get notify(): () => void - { - return this._notifier; - } - - public set notify(notifier: () => void) - { - if(this.figureData) this.figureData.notify = notifier; - - this._notifier = notifier; - } } diff --git a/src/views/avatar-editor/common/BodyModel.ts b/src/views/avatar-editor/common/BodyModel.ts index 41971d51..02151180 100644 --- a/src/views/avatar-editor/common/BodyModel.ts +++ b/src/views/avatar-editor/common/BodyModel.ts @@ -1,5 +1,6 @@ import { AvatarEditorFigureCategory, AvatarScaleType, AvatarSetType, IAvatarImageListener } from 'nitro-renderer'; import { GetAvatarRenderManager } from '../../../api'; +import { AvatarEditorUtilities } from './AvatarEditorUtilities'; import { CategoryBaseModel } from './CategoryBaseModel'; import { FigureData } from './FigureData'; @@ -25,15 +26,15 @@ export class BodyModel extends CategoryBaseModel implements IAvatarImageListener protected updateSelectionsFromFigure(name: string): void { - if(!this._categories || !this._editor || !this._editor.figureData) return; + if(!this._categories || !AvatarEditorUtilities.CURRENT_FIGURE) return; const category = this._categories.get(name); if(!category) return; - const setId = this._editor.figureData.getPartSetId(name); + const setId = AvatarEditorUtilities.CURRENT_FIGURE.getPartSetId(name); - let colorIds = this._editor.figureData.getColourIds(name); + let colorIds = AvatarEditorUtilities.CURRENT_FIGURE.getColorIds(name); if(!colorIds) colorIds = []; @@ -42,7 +43,7 @@ export class BodyModel extends CategoryBaseModel implements IAvatarImageListener for(const part of category.parts) { - const figure = this._editor.figureData.getFigureStringWithFace(part.id); + const figure = AvatarEditorUtilities.CURRENT_FIGURE.getFigureStringWithFace(part.id); const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, null, this); const sprite = avatarImage.getImageAsSprite(AvatarSetType.HEAD); diff --git a/src/views/avatar-editor/common/CategoryBaseModel.ts b/src/views/avatar-editor/common/CategoryBaseModel.ts index 9d1100ee..ab65af72 100644 --- a/src/views/avatar-editor/common/CategoryBaseModel.ts +++ b/src/views/avatar-editor/common/CategoryBaseModel.ts @@ -1,18 +1,16 @@ -import { AvatarEditor } from './AvatarEditor'; +import { AvatarEditorUtilities } from './AvatarEditorUtilities'; import { CategoryData } from './CategoryData'; import { IAvatarEditorCategoryModel } from './IAvatarEditorCategoryModel'; export class CategoryBaseModel implements IAvatarEditorCategoryModel { - protected _editor: AvatarEditor; protected _categories: Map; protected _isInitalized: boolean; protected _maxPaletteCount: number; private _disposed: boolean; - constructor(editor: AvatarEditor) + constructor() { - this._editor = editor; this._isInitalized = false; this._maxPaletteCount = 0; } @@ -51,7 +49,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel if(existing) return; - existing = this._editor.createCategory(this, name); + existing = AvatarEditorUtilities.createCategory(this, name); if(!existing) return; @@ -66,9 +64,9 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel if(!category) return; - const setId = this._editor.figureData.getPartSetId(figure); + const setId = AvatarEditorUtilities.CURRENT_FIGURE.getPartSetId(figure); - let colorIds = this._editor.figureData.getColourIds(figure); + let colorIds = AvatarEditorUtilities.CURRENT_FIGURE.getColorIds(figure); if(!colorIds) colorIds = []; @@ -120,9 +118,9 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel { const partItem = category.getCurrentPart(); - if(partItem && this._editor && this._editor.figureData) + if(partItem && AvatarEditorUtilities.CURRENT_FIGURE) { - this._editor.figureData.savePartData(name, partItem.id, category.getSelectedColorIds(), true); + AvatarEditorUtilities.CURRENT_FIGURE.savePartData(name, partItem.id, category.getSelectedColorIds(), true); } didStrip = true; @@ -148,9 +146,9 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel { const partItem = category.getCurrentPart(); - if(partItem && this._editor && this._editor.figureData) + if(partItem && AvatarEditorUtilities.CURRENT_FIGURE) { - this._editor.figureData.savePartData(name, partItem.id, category.getSelectedColorIds(), true); + AvatarEditorUtilities.CURRENT_FIGURE.savePartData(name, partItem.id, category.getSelectedColorIds(), true); } didStrip = true; @@ -185,7 +183,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel this._maxPaletteCount = partItem.maxColorIndex; - this._editor.figureData.savePartData(category, partItem.id, categoryData.getSelectedColorIds(), true); + AvatarEditorUtilities.CURRENT_FIGURE.savePartData(category, partItem.id, categoryData.getSelectedColorIds(), true); } public selectColor(category: string, colorIndex: number, paletteId: number): void @@ -209,7 +207,7 @@ export class CategoryBaseModel implements IAvatarEditorCategoryModel return; } - this._editor.figureData.savePartSetColourId(category, categoryData.getSelectedColorIds(), true); + AvatarEditorUtilities.CURRENT_FIGURE.savePartSetColourId(category, categoryData.getSelectedColorIds(), true); } public getCategoryData(category: string): CategoryData diff --git a/src/views/avatar-editor/common/FigureData.ts b/src/views/avatar-editor/common/FigureData.ts index 2e447cb3..d186b4c0 100644 --- a/src/views/avatar-editor/common/FigureData.ts +++ b/src/views/avatar-editor/common/FigureData.ts @@ -1,5 +1,9 @@ -export class FigureData +import { AvatarEditorUtilities } from './AvatarEditorUtilities'; + +export class FigureData { + private static DEFAULT_DIRECTION: number = 4; + public static MALE: string = 'M'; public static FEMALE: string = 'F'; public static UNISEX: string = 'U'; @@ -24,6 +28,7 @@ private _data: Map; private _colors: Map; private _gender: string = 'M'; + private _direction: number = FigureData.DEFAULT_DIRECTION; private _avatarEffectType: number = -1; private _notifier: () => void = null; @@ -80,14 +85,13 @@ return -1; } - public getColourIds(colorId: string): number[] + public getColorIds(setType: string): number[] { - const existing = this._colors.get(colorId); + const existing = this._colors.get(setType); if(existing !== undefined) return existing; - return []; - // return [this._avatarEditor._Str_24919(k)]; + return [ AvatarEditorUtilities.avatarSetFirstSelectableColor(setType) ]; } public getFigureString(): string @@ -167,9 +171,9 @@ if(_arg_3) this.updateView(); } - public savePartSetColourId(k: string, _arg_2: number[], _arg_3: boolean = true): void + public savePartSetColourId(setType: string, colorIds: number[], update: boolean = true): void { - switch(k) + switch(setType) { case FigureData.FACE: case FigureData.HAIR: @@ -184,11 +188,11 @@ case FigureData.TROUSERS: case FigureData.SHOES: case FigureData.TROUSER_ACCESSORIES: - this._colors.set(k, _arg_2); + this._colors.set(setType, colorIds); break; } - if(_arg_3) this.updateView(); + if(update) this.updateView(); } public getFigureStringWithFace(k: number, override = true): string @@ -249,6 +253,18 @@ return this._gender; } + public get direction(): number + { + return this._direction; + } + + public set direction(direction: number) + { + this._direction = direction; + + this.updateView(); + } + public set avatarEffectType(k: number) { this._avatarEffectType = k; diff --git a/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx index 73e37a69..352f7e58 100644 --- a/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx +++ b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.tsx @@ -4,7 +4,7 @@ import { AvatarEditorFigurePreviewViewProps } from './AvatarEditorFigurePreviewV export const AvatarEditorFigurePreviewView: FC = props => { - const { editor = null } = props; + const { figureData = null } = props; const [ updateId, setUpdateId ] = useState(-1); const rerender = useCallback(() => @@ -14,15 +14,15 @@ export const AvatarEditorFigurePreviewView: FC { - if(!editor) return; + if(!figureData) return; - editor.notify = rerender; + figureData.notify = rerender; return () => { - editor.notify = null; + figureData.notify = null; } - }, [ editor, rerender ] ); + }, [ figureData, rerender ] ); - return + return } diff --git a/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts index 0bfcf8f9..3956305c 100644 --- a/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts +++ b/src/views/avatar-editor/views/figure-preview/AvatarEditorFigurePreviewView.types.ts @@ -1,6 +1,6 @@ -import { AvatarEditor } from '../../common/AvatarEditor'; +import { FigureData } from '../../common/FigureData'; export interface AvatarEditorFigurePreviewViewProps { - editor: AvatarEditor; + figureData: FigureData; } diff --git a/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx b/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx index ef4c0cc4..09b4e33e 100644 --- a/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx +++ b/src/views/avatar-editor/views/figure-set-item/AvatarEditorFigureSetItemView.tsx @@ -24,8 +24,9 @@ export const AvatarEditorFigureSetItemView: FC onClick(partItem) }> + onClick(partItem) }> { partItem.isHC && } + { partItem.isClear && } ); } diff --git a/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx b/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx index c842c94e..68e1645b 100644 --- a/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx +++ b/src/views/avatar-editor/views/model/AvatarEditorModelView.tsx @@ -1,17 +1,13 @@ -import { UserFigureComposer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; -import { SendMessageHook } from '../../../../hooks'; -import { LocalizeText } from '../../../../utils/LocalizeText'; import { CategoryData } from '../../common/CategoryData'; import { FigureData } from '../../common/FigureData'; -import { AvatarEditorFigurePreviewView } from '../figure-preview/AvatarEditorFigurePreviewView'; import { AvatarEditorFigureSetView } from '../figure-set/AvatarEditorFigureSetView'; import { AvatarEditorPaletteSetView } from '../palette-set/AvatarEditorPaletteSetView'; import { AvatarEditorModelViewProps } from './AvatarEditorModelView.types'; export const AvatarEditorModelView: FC = props => { - const { model = null, editor = null, selectGender = null } = props; + const { model = null, gender = null, setGender = null } = props; const [ activeCategory, setActiveCategory ] = useState(null); const [ maxPaletteCount, setMaxPaletteCount ] = useState(1); @@ -35,13 +31,6 @@ export const AvatarEditorModelView: FC = props => } }, [ model ]); - const saveFigure = useCallback(() => - { - const figureData = editor.figureData; - - SendMessageHook(new UserFigureComposer(figureData.gender, figureData.getFigureString())); - }, [ editor ]); - useEffect(() => { model.init(); @@ -58,49 +47,35 @@ export const AvatarEditorModelView: FC = props => return (
    -
    +
    { model.canSetGender && <> - selectGender(FigureData.MALE) } /> - selectGender(FigureData.FEMALE) } /> +
    setGender(FigureData.MALE) }> + +
    +
    setGender(FigureData.FEMALE) }> + +
    } { !model.canSetGender && model.categories && (model.categories.size > 0) && Array.from(model.categories.keys()).map(name => { const category = model.categories.get(name); return ( - selectCategory(name) } /> +
    selectCategory(name) }> + +
    ); })}
    -
    +
    -
    -
    - -
    - - -
    -
    -
    -
    - - -
    - -
    -
    -
    +
    { (maxPaletteCount >= 1) && } { (maxPaletteCount === 2) && - } + }
    ); diff --git a/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts b/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts index dc81491a..b86b58aa 100644 --- a/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts +++ b/src/views/avatar-editor/views/model/AvatarEditorModelView.types.ts @@ -1,9 +1,9 @@ -import { AvatarEditor } from '../../common/AvatarEditor'; +import { Dispatch, SetStateAction } from 'react'; import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel'; export interface AvatarEditorModelViewProps { model: IAvatarEditorCategoryModel; - editor: AvatarEditor; - selectGender: (gender: string) => void; + gender: string; + setGender: Dispatch>; } diff --git a/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx index 2dab88d1..1a46b115 100644 --- a/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx +++ b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.tsx @@ -4,7 +4,7 @@ import { AvatarEditorPaletteSetItemProps } from './AvatarEditorPaletteSetItem.ty export const AvatarEditorPaletteSetItem: FC = props => { - const { colorItem = null, onClick = null } = props; + const { colorItem = null, ...rest } = props; const [ updateId, setUpdateId ] = useState(-1); const rerender = useCallback(() => @@ -22,5 +22,5 @@ export const AvatarEditorPaletteSetItem: FC = p } }) - return onClick(colorItem) } /> + return } diff --git a/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts index 5930f9a4..a0abc62e 100644 --- a/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts +++ b/src/views/avatar-editor/views/palette-set-item/AvatarEditorPaletteSetItem.types.ts @@ -1,7 +1,7 @@ +import { DetailsHTMLAttributes } from 'react'; import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem'; -export interface AvatarEditorPaletteSetItemProps +export interface AvatarEditorPaletteSetItemProps extends DetailsHTMLAttributes { colorItem: AvatarEditorGridColorItem; - onClick: (item: AvatarEditorGridColorItem) => void; } diff --git a/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx index fc8c4fc9..65c2968f 100644 --- a/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx +++ b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.tsx @@ -7,7 +7,7 @@ import { AvatarEditorPaletteSetViewProps } from './AvatarEditorPaletteSetView.ty export const AvatarEditorPaletteSetView: FC = props => { - const { model = null, category = null, paletteSet = [], paletteIndex = -1 } = props; + const { model = null, category = null, paletteSet = [], paletteIndex = -1, ...rest } = props; const selectColor = useCallback((item: AvatarEditorGridColorItem) => { @@ -19,10 +19,10 @@ export const AvatarEditorPaletteSetView: FC = p }, [ model, category, paletteSet, paletteIndex ]); return ( - + { (paletteSet.length > 0) && paletteSet.map((item, index) => { - return ; + return selectColor(item) } />; }) } ); diff --git a/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts index 9fa8e2b6..e7e62483 100644 --- a/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts +++ b/src/views/avatar-editor/views/palette-set/AvatarEditorPaletteSetView.types.ts @@ -1,8 +1,9 @@ +import { DetailsHTMLAttributes } from 'react'; import { AvatarEditorGridColorItem } from '../../common/AvatarEditorGridColorItem'; import { CategoryData } from '../../common/CategoryData'; import { IAvatarEditorCategoryModel } from '../../common/IAvatarEditorCategoryModel'; -export interface AvatarEditorPaletteSetViewProps +export interface AvatarEditorPaletteSetViewProps extends DetailsHTMLAttributes { model: IAvatarEditorCategoryModel; category: CategoryData; From 8f883bc7615a133638b7dbf93e2109cd94cd5fca Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 21 Jul 2021 05:31:36 -0400 Subject: [PATCH 59/72] More updates --- .../images/avatareditor/sellable-icon.png | Bin 0 -> 229 bytes src/assets/styles/icons.scss | 6 + src/assets/styles/utils.scss | 16 --- src/views/avatar-editor/AvatarEditorView.tsx | 108 +++++++++++------- .../common/AvatarEditorUtilities.ts | 18 +-- .../AvatarEditorFigureSetItemView.tsx | 3 +- .../shared/currency-icon/CurrencyIcon.tsx | 17 ++- .../currency-icon/CurrencyIcon.types.ts | 4 +- 8 files changed, 98 insertions(+), 74 deletions(-) create mode 100644 src/assets/images/avatareditor/sellable-icon.png diff --git a/src/assets/images/avatareditor/sellable-icon.png b/src/assets/images/avatareditor/sellable-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..4485b518d621e02512948def4dbb4317a75a2989 GIT binary patch literal 229 zcmeAS@N?(olHy`uVBq!ia0vp^f = props => const [ figureData, setFigureData ] = useState(null); const [ categories, setCategories ] = useState>(null); const [ activeCategory, setActiveCategory ] = useState(null); + const [ figureSetIds, setFigureSetIds ] = useState([]); + const [ boundFurnitureNames, setBoundFurnitureNames ] = useState([]); const [ lastFigure, setLastFigure ] = useState(null); const [ lastGender, setLastGender ] = useState(null); const [ needsReset, setNeedsReset ] = useState(false); const [ isInitalized, setIsInitalized ] = useState(false); + const onAvatarEditorEvent = useCallback((event: AvatarEditorEvent) => + { + switch(event.type) + { + case AvatarEditorEvent.SHOW_EDITOR: + setIsVisible(true); + setNeedsReset(true); + return; + case AvatarEditorEvent.HIDE_EDITOR: + setIsVisible(false); + return; + case AvatarEditorEvent.TOGGLE_EDITOR: + setIsVisible(prevValue => + { + const flag = !prevValue; + + if(flag) setNeedsReset(true); + + return flag; + }); + return; + } + }, []); + + useUiEvent(AvatarEditorEvent.SHOW_EDITOR, onAvatarEditorEvent); + useUiEvent(AvatarEditorEvent.HIDE_EDITOR, onAvatarEditorEvent); + useUiEvent(AvatarEditorEvent.TOGGLE_EDITOR, onAvatarEditorEvent); + const selectCategory = useCallback((name: string) => { if(!categories) return; @@ -87,34 +117,6 @@ export const AvatarEditorView: FC = props => } }, [ figures, figureData ]); - const onAvatarEditorEvent = useCallback((event: AvatarEditorEvent) => - { - switch(event.type) - { - case AvatarEditorEvent.SHOW_EDITOR: - setIsVisible(true); - setNeedsReset(true); - return; - case AvatarEditorEvent.HIDE_EDITOR: - setIsVisible(false); - return; - case AvatarEditorEvent.TOGGLE_EDITOR: - setIsVisible(prevValue => - { - const flag = !prevValue; - - if(flag) setNeedsReset(true); - - return flag; - }); - return; - } - }, []); - - useUiEvent(AvatarEditorEvent.SHOW_EDITOR, onAvatarEditorEvent); - useUiEvent(AvatarEditorEvent.HIDE_EDITOR, onAvatarEditorEvent); - useUiEvent(AvatarEditorEvent.TOGGLE_EDITOR, onAvatarEditorEvent); - const clearFigure = useCallback(() => { loadAvatarInEditor(figureData.getFigureStringWithFace(0, false), figureData.gender, false); @@ -145,6 +147,7 @@ export const AvatarEditorView: FC = props => const saveFigure = useCallback(() => { SendMessageHook(new UserFigureComposer(figureData.gender, figureData.getFigureString())); + setIsVisible(false); }, [ figureData ]); const setGender = useCallback((gender: string) => @@ -154,6 +157,18 @@ export const AvatarEditorView: FC = props => setFigureData(figures.get(gender)); }, [ figures ]); + const onFigureSetIdsMessageEvent = useCallback((event: FigureSetIdsMessageEvent) => + { + const parser = event.getParser(); + + setFigureSetIds(parser.figureSetIds); + setBoundFurnitureNames(parser.boundsFurnitureNames); + + resetCategories(); + }, [ resetCategories ]); + + CreateMessageHook(FigureSetIdsMessageEvent, onFigureSetIdsMessageEvent); + useEffect(() => { if(!categories) return; @@ -172,6 +187,18 @@ export const AvatarEditorView: FC = props => return () => AvatarEditorUtilities.CURRENT_FIGURE = null; }, [ figureData, resetCategories ]); + useEffect(() => + { + AvatarEditorUtilities.FIGURE_SET_IDS = figureSetIds; + AvatarEditorUtilities.BOUND_FURNITURE_NAMES = boundFurnitureNames; + + return () => + { + AvatarEditorUtilities.FIGURE_SET_IDS = null; + AvatarEditorUtilities.BOUND_FURNITURE_NAMES = null; + } + }, [ figureSetIds, boundFurnitureNames ]); + useEffect(() => { if(!isVisible) return; @@ -194,7 +221,7 @@ export const AvatarEditorView: FC = props => setNeedsReset(false); }, [ isVisible, isInitalized, needsReset, loadAvatarInEditor ]); - if(!isVisible) return null; + if(!isVisible || !figureData) return null; return ( @@ -215,16 +242,15 @@ export const AvatarEditorView: FC = props => { activeCategory && }
    - { figureData && -
    - -
    -
    -
    - rotateFigure(figureData.direction + 1) } /> - rotateFigure(figureData.direction - 1) } /> -
    -
    } +
    + +
    +
    +
    + rotateFigure(figureData.direction + 1) } /> + rotateFigure(figureData.direction - 1) } /> +
    +
    + { figureString && } +
    + + ); + }); return items; - }, [ figures ]); - - console.log(figures.length); + }, [ savedFigures, saveFigureAtWardrobeIndex, wearFigureAtIndex ]); return (
    - - { savedFigures } + + { figures }
    diff --git a/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.types.ts b/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.types.ts index a6d5c978..2311c58e 100644 --- a/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.types.ts +++ b/src/views/avatar-editor/views/wardrobe/AvatarEditorWardrobeView.types.ts @@ -1,4 +1,10 @@ +import { Dispatch, SetStateAction } from 'react'; +import { FigureData } from '../../common/FigureData'; + export interface AvatarEditorWardrobeViewProps { - figures: [ string, string ][]; + figureData: FigureData; + savedFigures: [ string, string ][]; + setSavedFigures: Dispatch>; + loadAvatarInEditor: (figure: string, gender: string, reset?: boolean) => void; } From 629d231887f00c1e01b00afbe5c3a966a3b11697 Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 21 Jul 2021 23:54:00 -0400 Subject: [PATCH 69/72] Fix alert height --- src/views/notification-center/NotificationCenterView.scss | 1 + 1 file changed, 1 insertion(+) diff --git a/src/views/notification-center/NotificationCenterView.scss b/src/views/notification-center/NotificationCenterView.scss index d2a9445f..78a94d63 100644 --- a/src/views/notification-center/NotificationCenterView.scss +++ b/src/views/notification-center/NotificationCenterView.scss @@ -3,6 +3,7 @@ .content-area { min-height: 125px; + max-height: 300px; } } From ac392c71cfa5eb6f42777a3c2868b2bdacaf4e33 Mon Sep 17 00:00:00 2001 From: Bill Date: Wed, 21 Jul 2021 23:54:13 -0400 Subject: [PATCH 70/72] Open avatar editor from context menu --- .../views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx index 1fa8cb40..93df5e2c 100644 --- a/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx +++ b/src/views/room/widgets/avatar-info/views/own-avatar/AvatarInfoWidgetOwnAvatarView.tsx @@ -1,6 +1,8 @@ import { AvatarAction, AvatarExpressionEnum, RoomObjectCategory } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; import { GetCanStandUp, GetCanUseExpression, GetOwnPosture, HasHabboClub, HasHabboVip, IsRidingHorse } from '../../../../../../api'; +import { AvatarEditorEvent } from '../../../../../../events'; +import { dispatchUiEvent } from '../../../../../../hooks'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { CurrencyIcon } from '../../../../../shared/currency-icon/CurrencyIcon'; import { useRoomContext } from '../../../../context/RoomContext'; @@ -43,6 +45,7 @@ export const AvatarInfoWidgetOwnAvatarView: FC Date: Thu, 22 Jul 2021 01:09:31 -0400 Subject: [PATCH 71/72] Update api --- src/App.tsx | 18 +++++++++--------- src/api/catalog/GetCatalogPageComposer.ts | 6 ------ src/api/core/GetConfigurationManager.ts | 7 +++++++ src/api/core/GetNitroCore.ts | 7 +++++++ src/api/core/index.ts | 2 ++ src/api/index.ts | 1 + src/api/nitro/AddLinkEventTracker.ts | 7 +++++++ src/api/nitro/GetCommunication.ts | 7 +++++++ src/api/nitro/GetConfiguration.ts | 4 ++-- src/api/nitro/GetConnection.ts | 5 +++-- src/api/nitro/GetNitroInstance.ts | 6 ++++++ src/api/nitro/GetTicker.ts | 4 ++-- src/api/nitro/RemoveLinkEventTracker.ts | 7 +++++++ src/api/nitro/avatar/GetAvatarRenderManager.ts | 5 +++-- .../nitro/camera/GetRoomCameraWidgetManager.ts | 4 ++-- src/api/nitro/index.ts | 4 ++++ src/api/nitro/room/GetRoomEngine.ts | 5 +++-- src/api/nitro/session/GetRoomSessionManager.ts | 5 +++-- src/api/nitro/session/GetSessionDataManager.ts | 5 +++-- .../communication/communication-event.tsx | 4 ++-- .../{nitro => core}/communication/index.ts | 0 .../core/configuration/configuration-event.tsx | 4 ++-- src/hooks/events/core/index.ts | 1 + src/hooks/events/nitro/avatar/avatar-event.tsx | 4 ++-- src/hooks/events/nitro/camera/camera-event.tsx | 4 ++-- src/hooks/events/nitro/index.ts | 1 - .../nitro/localization/localization-event.tsx | 4 ++-- src/hooks/events/nitro/main-event.tsx | 7 ++++--- .../events/nitro/room/room-engine-event.tsx | 4 ++-- .../session/room-session-manager-event.tsx | 5 +++-- src/hooks/index.ts | 7 ------- src/hooks/messages/message-event.tsx | 8 ++++---- src/utils/LocalizeBageName.ts | 4 ++-- src/utils/LocalizeText.ts | 4 ++-- 34 files changed, 106 insertions(+), 64 deletions(-) delete mode 100644 src/api/catalog/GetCatalogPageComposer.ts create mode 100644 src/api/core/GetConfigurationManager.ts create mode 100644 src/api/core/GetNitroCore.ts create mode 100644 src/api/core/index.ts create mode 100644 src/api/nitro/AddLinkEventTracker.ts create mode 100644 src/api/nitro/GetCommunication.ts create mode 100644 src/api/nitro/GetNitroInstance.ts create mode 100644 src/api/nitro/RemoveLinkEventTracker.ts rename src/hooks/events/{nitro => core}/communication/communication-event.tsx (61%) rename src/hooks/events/{nitro => core}/communication/index.ts (100%) diff --git a/src/App.tsx b/src/App.tsx index eb7bb5df..9a1421c7 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,6 +1,6 @@ import { ConfigurationEvent, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroEvent, NitroLocalizationEvent, RoomEngineEvent, WebGL } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { GetConfiguration } from './api'; +import { GetCommunication, GetConfiguration, GetNitroInstance } from './api'; import { useConfigurationEvent } from './hooks/events/core/configuration/configuration-event'; import { useLocalizationEvent } from './hooks/events/nitro/localization/localization-event'; import { dispatchMainEvent, useMainEvent } from './hooks/events/nitro/main-event'; @@ -19,7 +19,7 @@ export const App: FC<{}> = props => //@ts-ignore if(!NitroConfig) throw new Error('NitroConfig is not defined!'); - if(!Nitro.instance) Nitro.bootstrap(); + if(!GetNitroInstance()) Nitro.bootstrap(); const getPreloadAssetUrls = useCallback(() => { @@ -28,7 +28,7 @@ export const App: FC<{}> = props => if(assetUrls && assetUrls.length) { - for(const url of assetUrls) urls.push(Nitro.instance.core.configuration.interpolate(url)); + for(const url of assetUrls) urls.push(GetNitroInstance().core.configuration.interpolate(url)); } return urls; @@ -39,7 +39,7 @@ export const App: FC<{}> = props => switch(event.type) { case ConfigurationEvent.LOADED: - Nitro.instance.localization.init(); + GetNitroInstance().localization.init(); return; case ConfigurationEvent.FAILED: setIsError(true); @@ -73,14 +73,14 @@ export const App: FC<{}> = props => case NitroCommunicationDemoEvent.CONNECTION_AUTHENTICATED: setMessage('Finishing Up'); - Nitro.instance.init(); + GetNitroInstance().init(); return; case NitroCommunicationDemoEvent.CONNECTION_ERROR: setIsError(true); setMessage('Connection Error'); return; case NitroCommunicationDemoEvent.CONNECTION_CLOSED: - if(Nitro.instance.roomEngine) Nitro.instance.roomEngine.dispose(); + if(GetNitroInstance().roomEngine) GetNitroInstance().roomEngine.dispose(); setIsError(true); setMessage('Connection Error'); @@ -91,13 +91,13 @@ export const App: FC<{}> = props => setIsReady(true); return; case NitroLocalizationEvent.LOADED: - Nitro.instance.core.asset.downloadAssets(getPreloadAssetUrls(), (status: boolean) => + GetNitroInstance().core.asset.downloadAssets(getPreloadAssetUrls(), (status: boolean) => { if(status) { setMessage('Connecting'); - Nitro.instance.communication.init(); + GetCommunication().init(); } else { @@ -127,7 +127,7 @@ export const App: FC<{}> = props => } else { - Nitro.instance.core.configuration.init(); + GetNitroInstance().core.configuration.init(); } return ( diff --git a/src/api/catalog/GetCatalogPageComposer.ts b/src/api/catalog/GetCatalogPageComposer.ts deleted file mode 100644 index 685112a8..00000000 --- a/src/api/catalog/GetCatalogPageComposer.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { CatalogPageComposer } from 'nitro-renderer'; - -export function GetCatalogPageComposer(...args: ConstructorParameters): CatalogPageComposer -{ - return new CatalogPageComposer(...args); -} diff --git a/src/api/core/GetConfigurationManager.ts b/src/api/core/GetConfigurationManager.ts new file mode 100644 index 00000000..f974b328 --- /dev/null +++ b/src/api/core/GetConfigurationManager.ts @@ -0,0 +1,7 @@ +import { IConfigurationManager } from 'nitro-renderer'; +import { GetNitroCore } from './GetNitroCore'; + +export function GetConfigurationManager(): IConfigurationManager +{ + return GetNitroCore().configuration; +} diff --git a/src/api/core/GetNitroCore.ts b/src/api/core/GetNitroCore.ts new file mode 100644 index 00000000..4972ef2d --- /dev/null +++ b/src/api/core/GetNitroCore.ts @@ -0,0 +1,7 @@ +import { INitroCore } from 'nitro-renderer'; +import { GetNitroInstance } from '../nitro'; + +export function GetNitroCore(): INitroCore +{ + return GetNitroInstance().core; +} diff --git a/src/api/core/index.ts b/src/api/core/index.ts new file mode 100644 index 00000000..3322c9cb --- /dev/null +++ b/src/api/core/index.ts @@ -0,0 +1,2 @@ +export * from './GetConfigurationManager'; +export * from './GetNitroCore'; diff --git a/src/api/index.ts b/src/api/index.ts index 85f5a489..e935bf12 100644 --- a/src/api/index.ts +++ b/src/api/index.ts @@ -1 +1,2 @@ +export * from './core'; export * from './nitro'; diff --git a/src/api/nitro/AddLinkEventTracker.ts b/src/api/nitro/AddLinkEventTracker.ts new file mode 100644 index 00000000..df1667de --- /dev/null +++ b/src/api/nitro/AddLinkEventTracker.ts @@ -0,0 +1,7 @@ +import { ILinkEventTracker } from 'nitro-renderer'; +import { GetNitroInstance } from './GetNitroInstance'; + +export function AddEventLinkTracker(tracker: ILinkEventTracker): void +{ + GetNitroInstance().addLinkEventTracker(tracker); +} diff --git a/src/api/nitro/GetCommunication.ts b/src/api/nitro/GetCommunication.ts new file mode 100644 index 00000000..696104fa --- /dev/null +++ b/src/api/nitro/GetCommunication.ts @@ -0,0 +1,7 @@ +import { INitroCommunicationManager } from 'nitro-renderer'; +import { GetNitroInstance } from './GetNitroInstance'; + +export function GetCommunication(): INitroCommunicationManager +{ + return GetNitroInstance().communication; +} diff --git a/src/api/nitro/GetConfiguration.ts b/src/api/nitro/GetConfiguration.ts index a70a82f2..2676d53f 100644 --- a/src/api/nitro/GetConfiguration.ts +++ b/src/api/nitro/GetConfiguration.ts @@ -1,6 +1,6 @@ -import { Nitro } from 'nitro-renderer'; +import { GetNitroInstance } from './GetNitroInstance'; export function GetConfiguration(key: string, value: T = null): T { - return Nitro.instance.getConfiguration(key, value); + return GetNitroInstance().getConfiguration(key, value); } diff --git a/src/api/nitro/GetConnection.ts b/src/api/nitro/GetConnection.ts index 03c13354..bf924a26 100644 --- a/src/api/nitro/GetConnection.ts +++ b/src/api/nitro/GetConnection.ts @@ -1,6 +1,7 @@ -import { IConnection, Nitro } from 'nitro-renderer'; +import { IConnection } from 'nitro-renderer'; +import { GetCommunication } from './GetCommunication'; export function GetConnection(): IConnection { - return Nitro.instance.communication.connection; + return GetCommunication().connection; } diff --git a/src/api/nitro/GetNitroInstance.ts b/src/api/nitro/GetNitroInstance.ts new file mode 100644 index 00000000..17735012 --- /dev/null +++ b/src/api/nitro/GetNitroInstance.ts @@ -0,0 +1,6 @@ +import { INitro, Nitro } from 'nitro-renderer'; + +export function GetNitroInstance(): INitro +{ + return Nitro.instance; +} diff --git a/src/api/nitro/GetTicker.ts b/src/api/nitro/GetTicker.ts index eaab9664..9d02551f 100644 --- a/src/api/nitro/GetTicker.ts +++ b/src/api/nitro/GetTicker.ts @@ -1,6 +1,6 @@ -import { Nitro } from 'nitro-renderer'; +import { GetNitroInstance } from './GetNitroInstance'; export function GetTicker() { - return Nitro.instance.ticker; + return GetNitroInstance().ticker; } diff --git a/src/api/nitro/RemoveLinkEventTracker.ts b/src/api/nitro/RemoveLinkEventTracker.ts new file mode 100644 index 00000000..8963dedc --- /dev/null +++ b/src/api/nitro/RemoveLinkEventTracker.ts @@ -0,0 +1,7 @@ +import { ILinkEventTracker } from 'nitro-renderer'; +import { GetNitroInstance } from './GetNitroInstance'; + +export function RemoveLinkEventTracker(tracker: ILinkEventTracker): void +{ + GetNitroInstance().removeLinkEventTracker(tracker); +} diff --git a/src/api/nitro/avatar/GetAvatarRenderManager.ts b/src/api/nitro/avatar/GetAvatarRenderManager.ts index c616c1a3..9f7547ab 100644 --- a/src/api/nitro/avatar/GetAvatarRenderManager.ts +++ b/src/api/nitro/avatar/GetAvatarRenderManager.ts @@ -1,6 +1,7 @@ -import { IAvatarRenderManager, Nitro } from 'nitro-renderer'; +import { IAvatarRenderManager } from 'nitro-renderer'; +import { GetNitroInstance } from '../GetNitroInstance'; export function GetAvatarRenderManager(): IAvatarRenderManager { - return Nitro.instance.avatar; + return GetNitroInstance().avatar; } diff --git a/src/api/nitro/camera/GetRoomCameraWidgetManager.ts b/src/api/nitro/camera/GetRoomCameraWidgetManager.ts index ca3e498f..90bfc45c 100644 --- a/src/api/nitro/camera/GetRoomCameraWidgetManager.ts +++ b/src/api/nitro/camera/GetRoomCameraWidgetManager.ts @@ -1,7 +1,7 @@ -import { Nitro } from 'nitro-renderer'; import { IRoomCameraWidgetManager } from 'nitro-renderer/src/nitro/camera/IRoomCameraWidgetManager'; +import { GetNitroInstance } from '../GetNitroInstance'; export function GetRoomCameraWidgetManager(): IRoomCameraWidgetManager { - return Nitro.instance.cameraManager; + return GetNitroInstance().cameraManager; } diff --git a/src/api/nitro/index.ts b/src/api/nitro/index.ts index 4c46e69f..3cc66155 100644 --- a/src/api/nitro/index.ts +++ b/src/api/nitro/index.ts @@ -1,7 +1,11 @@ +export * from './AddLinkEventTracker'; export * from './avatar'; export * from './camera'; +export * from './GetCommunication'; export * from './GetConfiguration'; export * from './GetConnection'; +export * from './GetNitroInstance'; export * from './GetTicker'; +export * from './RemoveLinkEventTracker'; export * from './room'; export * from './session'; diff --git a/src/api/nitro/room/GetRoomEngine.ts b/src/api/nitro/room/GetRoomEngine.ts index 153ab4a1..58ae4421 100644 --- a/src/api/nitro/room/GetRoomEngine.ts +++ b/src/api/nitro/room/GetRoomEngine.ts @@ -1,6 +1,7 @@ -import { IRoomEngine, Nitro } from 'nitro-renderer'; +import { IRoomEngine } from 'nitro-renderer'; +import { GetNitroInstance } from '../GetNitroInstance'; export function GetRoomEngine(): IRoomEngine { - return Nitro.instance.roomEngine; + return GetNitroInstance().roomEngine; } diff --git a/src/api/nitro/session/GetRoomSessionManager.ts b/src/api/nitro/session/GetRoomSessionManager.ts index cdba1b0e..830ba177 100644 --- a/src/api/nitro/session/GetRoomSessionManager.ts +++ b/src/api/nitro/session/GetRoomSessionManager.ts @@ -1,6 +1,7 @@ -import { IRoomSessionManager, Nitro } from 'nitro-renderer'; +import { IRoomSessionManager } from 'nitro-renderer'; +import { GetNitroInstance } from '../GetNitroInstance'; export function GetRoomSessionManager(): IRoomSessionManager { - return Nitro.instance.roomSessionManager; + return GetNitroInstance().roomSessionManager; } diff --git a/src/api/nitro/session/GetSessionDataManager.ts b/src/api/nitro/session/GetSessionDataManager.ts index d31e1a0c..6af8c5c7 100644 --- a/src/api/nitro/session/GetSessionDataManager.ts +++ b/src/api/nitro/session/GetSessionDataManager.ts @@ -1,6 +1,7 @@ -import { ISessionDataManager, Nitro } from 'nitro-renderer'; +import { ISessionDataManager } from 'nitro-renderer'; +import { GetNitroInstance } from '../GetNitroInstance'; export function GetSessionDataManager(): ISessionDataManager { - return Nitro.instance.sessionDataManager; + return GetNitroInstance().sessionDataManager; } diff --git a/src/hooks/events/nitro/communication/communication-event.tsx b/src/hooks/events/core/communication/communication-event.tsx similarity index 61% rename from src/hooks/events/nitro/communication/communication-event.tsx rename to src/hooks/events/core/communication/communication-event.tsx index 9049dcea..c9bcdd65 100644 --- a/src/hooks/events/nitro/communication/communication-event.tsx +++ b/src/hooks/events/core/communication/communication-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetCommunication } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useCommunicationEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.communication.events, handler); + CreateEventDispatcherHook(type, GetCommunication().events, handler); } diff --git a/src/hooks/events/nitro/communication/index.ts b/src/hooks/events/core/communication/index.ts similarity index 100% rename from src/hooks/events/nitro/communication/index.ts rename to src/hooks/events/core/communication/index.ts diff --git a/src/hooks/events/core/configuration/configuration-event.tsx b/src/hooks/events/core/configuration/configuration-event.tsx index 3e117dc7..6654fa23 100644 --- a/src/hooks/events/core/configuration/configuration-event.tsx +++ b/src/hooks/events/core/configuration/configuration-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetConfigurationManager } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useConfigurationEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.core.configuration.events, handler); + CreateEventDispatcherHook(type, GetConfigurationManager().events, handler); } diff --git a/src/hooks/events/core/index.ts b/src/hooks/events/core/index.ts index 75a11149..d344bc2c 100644 --- a/src/hooks/events/core/index.ts +++ b/src/hooks/events/core/index.ts @@ -1 +1,2 @@ +export * from './communication'; export * from './configuration'; diff --git a/src/hooks/events/nitro/avatar/avatar-event.tsx b/src/hooks/events/nitro/avatar/avatar-event.tsx index 2d9b065f..c41f721b 100644 --- a/src/hooks/events/nitro/avatar/avatar-event.tsx +++ b/src/hooks/events/nitro/avatar/avatar-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetAvatarRenderManager } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useAvatarEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.avatar.events, handler); + CreateEventDispatcherHook(type, GetAvatarRenderManager().events, handler); } diff --git a/src/hooks/events/nitro/camera/camera-event.tsx b/src/hooks/events/nitro/camera/camera-event.tsx index 499b162f..3a8e311f 100644 --- a/src/hooks/events/nitro/camera/camera-event.tsx +++ b/src/hooks/events/nitro/camera/camera-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetNitroInstance } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useCameraEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.cameraManager.events, handler); + CreateEventDispatcherHook(type, GetNitroInstance().cameraManager.events, handler); } diff --git a/src/hooks/events/nitro/index.ts b/src/hooks/events/nitro/index.ts index 8bf15d27..262c00cd 100644 --- a/src/hooks/events/nitro/index.ts +++ b/src/hooks/events/nitro/index.ts @@ -1,6 +1,5 @@ export * from './avatar'; export * from './camera'; -export * from './communication'; export * from './localization'; export * from './main-event'; export * from './room'; diff --git a/src/hooks/events/nitro/localization/localization-event.tsx b/src/hooks/events/nitro/localization/localization-event.tsx index 38d835ac..8fd273d8 100644 --- a/src/hooks/events/nitro/localization/localization-event.tsx +++ b/src/hooks/events/nitro/localization/localization-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetNitroInstance } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useLocalizationEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.localization.events, handler); + CreateEventDispatcherHook(type, GetNitroInstance().localization.events, handler); } diff --git a/src/hooks/events/nitro/main-event.tsx b/src/hooks/events/nitro/main-event.tsx index da4ef70c..1266e3fd 100644 --- a/src/hooks/events/nitro/main-event.tsx +++ b/src/hooks/events/nitro/main-event.tsx @@ -1,12 +1,13 @@ -import { Nitro, NitroEvent } from 'nitro-renderer'; +import { NitroEvent } from 'nitro-renderer'; +import { GetNitroInstance } from '../../../api'; import { CreateEventDispatcherHook, DispatchEventHook } from '../event-dispatcher.base'; export function useMainEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.events, handler); + CreateEventDispatcherHook(type, GetNitroInstance().events, handler); } export function dispatchMainEvent(event: NitroEvent): void { - DispatchEventHook(Nitro.instance.events, event); + DispatchEventHook(GetNitroInstance().events, event); } diff --git a/src/hooks/events/nitro/room/room-engine-event.tsx b/src/hooks/events/nitro/room/room-engine-event.tsx index c5e65d15..f4e4ce39 100644 --- a/src/hooks/events/nitro/room/room-engine-event.tsx +++ b/src/hooks/events/nitro/room/room-engine-event.tsx @@ -1,8 +1,8 @@ import { NitroEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; +import { GetRoomEngine } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useRoomEngineEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.roomEngine.events, handler); + CreateEventDispatcherHook(type, GetRoomEngine().events, handler); } diff --git a/src/hooks/events/nitro/session/room-session-manager-event.tsx b/src/hooks/events/nitro/session/room-session-manager-event.tsx index 518e90df..4335a72b 100644 --- a/src/hooks/events/nitro/session/room-session-manager-event.tsx +++ b/src/hooks/events/nitro/session/room-session-manager-event.tsx @@ -1,7 +1,8 @@ -import { Nitro, NitroEvent } from 'nitro-renderer'; +import { NitroEvent } from 'nitro-renderer'; +import { GetRoomSessionManager } from '../../../../api'; import { CreateEventDispatcherHook } from '../../event-dispatcher.base'; export function useRoomSessionManagerEvent(type: string, handler: (event: NitroEvent) => void): void { - CreateEventDispatcherHook(type, Nitro.instance.roomSessionManager.events, handler); + CreateEventDispatcherHook(type, GetRoomSessionManager().events, handler); } diff --git a/src/hooks/index.ts b/src/hooks/index.ts index 41928f94..0068322f 100644 --- a/src/hooks/index.ts +++ b/src/hooks/index.ts @@ -1,13 +1,6 @@ export * from './events'; export * from './events/core'; -export * from './events/core/configuration'; export * from './events/nitro'; -export * from './events/nitro/avatar'; -export * from './events/nitro/camera'; -export * from './events/nitro/communication'; -export * from './events/nitro/localization'; -export * from './events/nitro/room'; -export * from './events/nitro/session'; export * from './events/ui'; export * from './messages'; export * from './UseMountEffect'; diff --git a/src/hooks/messages/message-event.tsx b/src/hooks/messages/message-event.tsx index d81ab22d..c530586c 100644 --- a/src/hooks/messages/message-event.tsx +++ b/src/hooks/messages/message-event.tsx @@ -1,6 +1,6 @@ import { IMessageComposer, IMessageEvent, MessageEvent } from 'nitro-renderer'; -import { Nitro } from 'nitro-renderer/src/nitro/Nitro'; import { useEffect } from 'react'; +import { GetCommunication, GetConnection } from '../../api'; export function CreateMessageHook(eventType: typeof MessageEvent, handler: (event: IMessageEvent) => void): void { @@ -9,13 +9,13 @@ export function CreateMessageHook(eventType: typeof MessageEvent, handler: (even //@ts-ignore const event = new eventType(handler); - Nitro.instance.communication.registerMessageEvent(event); + GetCommunication().registerMessageEvent(event); - return () => Nitro.instance.communication.removeMessageEvent(event); + return () => GetCommunication().removeMessageEvent(event); }, [ eventType, handler ]); } export function SendMessageHook(event: IMessageComposer): void { - Nitro.instance.communication.connection.send(event); + GetConnection().send(event); } diff --git a/src/utils/LocalizeBageName.ts b/src/utils/LocalizeBageName.ts index cb5e6ef2..ad579262 100644 --- a/src/utils/LocalizeBageName.ts +++ b/src/utils/LocalizeBageName.ts @@ -1,6 +1,6 @@ -import { Nitro } from 'nitro-renderer'; +import { GetNitroInstance } from '../api'; export function LocalizeBadgeName(key: string): string { - return Nitro.instance.localization.getBadgeName(key); + return GetNitroInstance().localization.getBadgeName(key); } diff --git a/src/utils/LocalizeText.ts b/src/utils/LocalizeText.ts index defa078f..ed3c8b18 100644 --- a/src/utils/LocalizeText.ts +++ b/src/utils/LocalizeText.ts @@ -1,6 +1,6 @@ -import { Nitro } from 'nitro-renderer'; +import { GetNitroInstance } from '../api'; export function LocalizeText(key: string, parameters: string[] = null, replacements: string[] = null): string { - return Nitro.instance.getLocalizationWithParameters(key, parameters, replacements); + return GetNitroInstance().getLocalizationWithParameters(key, parameters, replacements); } From 936c9ee2b7c0cced0ddb17dc8290a3937b396251 Mon Sep 17 00:00:00 2001 From: Bill Date: Thu, 22 Jul 2021 01:10:13 -0400 Subject: [PATCH 72/72] Updates --- .../common/AvatarEditorUtilities.ts | 2 +- src/views/catalog/common/Purse.ts | 20 ++++----- .../item/CatalogNavigationItemView.tsx | 6 +-- src/views/hotel-view/HotelView.tsx | 16 +++---- src/views/inventory/common/FurnitureItem.ts | 5 ++- src/views/main/MainView.tsx | 5 ++- src/views/navigator/NavigatorView.tsx | 42 ++++++++++++++++++- .../views/room-link/NavigatorRoomLinkView.tsx | 5 +-- src/views/room/RoomColorView.tsx | 8 ++-- src/views/room/RoomView.tsx | 18 ++++---- .../handlers/RoomWidgetInfostandHandler.ts | 6 +-- .../AvatarInfoWidgetRentableBotView.tsx | 5 ++- .../widgets/context-menu/ContextMenuView.tsx | 8 ++-- .../mannequin/FurnitureMannequinView.tsx | 17 ++++---- .../object-location/ObjectLocationView.tsx | 7 ++-- .../room-previewer/RoomPreviewerView.tsx | 7 ++-- 16 files changed, 110 insertions(+), 67 deletions(-) diff --git a/src/views/avatar-editor/common/AvatarEditorUtilities.ts b/src/views/avatar-editor/common/AvatarEditorUtilities.ts index 224ce1f7..2977a315 100644 --- a/src/views/avatar-editor/common/AvatarEditorUtilities.ts +++ b/src/views/avatar-editor/common/AvatarEditorUtilities.ts @@ -162,7 +162,7 @@ export class AvatarEditorUtilities partItems.sort(this.clubItemsFirst ? this.clubSorter : this.noobSorter); - // if(this._forceSellableClothingVisibility || Nitro.instance.getConfiguration("avatareditor.support.sellablefurni", false)) + // if(this._forceSellableClothingVisibility || GetNitroInstance().getConfiguration("avatareditor.support.sellablefurni", false)) // { // _local_31 = (this._manager.windowManager.assets.getAssetByName("camera_zoom_in") as BitmapDataAsset); // _local_32 = (_local_31.content as BitmapData).clone(); diff --git a/src/views/catalog/common/Purse.ts b/src/views/catalog/common/Purse.ts index a044cd05..eebaacf8 100644 --- a/src/views/catalog/common/Purse.ts +++ b/src/views/catalog/common/Purse.ts @@ -1,4 +1,4 @@ -import { Nitro } from 'nitro-renderer'; +import { GetNitroInstance } from '../../../api'; import { IPurse } from './IPurse'; export class Purse implements IPurse @@ -22,7 +22,7 @@ export class Purse implements IPurse public set credits(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._credits = k; } @@ -33,7 +33,7 @@ export class Purse implements IPurse public set clubDays(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._clubDays = k; } @@ -44,7 +44,7 @@ export class Purse implements IPurse public set clubPeriods(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._clubPeriods = k; } @@ -80,7 +80,7 @@ export class Purse implements IPurse public set _Str_6288(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._pastClubDays = k; } @@ -91,7 +91,7 @@ export class Purse implements IPurse public set _Str_4605(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._pastVipDays = k; } @@ -102,7 +102,7 @@ export class Purse implements IPurse public set _Str_18527(k: Map) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._activityPoints = k; } @@ -113,14 +113,14 @@ export class Purse implements IPurse public set _Str_4458(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._minutesUntilExpiration = k; } public get _Str_4458(): number { - const k = ((Nitro.instance.time - this._lastUpdated) / (1000 * 60)); + const k = ((GetNitroInstance().time - this._lastUpdated) / (1000 * 60)); const _local_2 = (this._minutesUntilExpiration - k); return (_local_2 > 0) ? _local_2 : 0; @@ -128,7 +128,7 @@ export class Purse implements IPurse public set _Str_6312(k: number) { - this._lastUpdated = Nitro.instance.time; + this._lastUpdated = GetNitroInstance().time; this._minutesSinceLastModified = k; } diff --git a/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx b/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx index 4fcabb6b..302f7aed 100644 --- a/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx +++ b/src/views/catalog/views/navigation/item/CatalogNavigationItemView.tsx @@ -1,5 +1,5 @@ +import { CatalogPageComposer } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; -import { GetCatalogPageComposer } from '../../../../../api/catalog/GetCatalogPageComposer'; import { SendMessageHook } from '../../../../../hooks/messages/message-event'; import { CatalogMode } from '../../../CatalogView.types'; import { CatalogIconView } from '../../catalog-icon/CatalogIconView'; @@ -17,7 +17,7 @@ export const CatalogNavigationItemView: FC = pro setIsExpanded(true); - SendMessageHook(GetCatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL)); + SendMessageHook(new CatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL)); }, [ isActive, page ]); const select = useCallback(() => @@ -28,7 +28,7 @@ export const CatalogNavigationItemView: FC = pro { if(prevValue === page) { - SendMessageHook(GetCatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL)); + SendMessageHook(new CatalogPageComposer(page.pageId, -1, CatalogMode.MODE_NORMAL)); } return page; diff --git a/src/views/hotel-view/HotelView.tsx b/src/views/hotel-view/HotelView.tsx index 9222f3b8..f1f1c3b5 100644 --- a/src/views/hotel-view/HotelView.tsx +++ b/src/views/hotel-view/HotelView.tsx @@ -1,6 +1,6 @@ -import { Nitro, RoomSessionEvent } from 'nitro-renderer'; +import { RoomSessionEvent } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { GetConfiguration } from '../../api'; +import { GetConfiguration, GetNitroInstance } from '../../api'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; import { HotelViewProps } from './HotelView.types'; @@ -27,12 +27,12 @@ export const HotelView: FC = props => if(!isVisible) return null; const backgroundColor = GetConfiguration('hotelview')['images']['background.colour']; - const background = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['background']); - const sun = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['sun']); - const drape = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['drape']); - const left = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['left']); - const rightRepeat = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['right.repeat']); - const right = Nitro.instance.core.configuration.interpolate(GetConfiguration('hotelview')['images']['right']); + const background = GetNitroInstance().core.configuration.interpolate(GetConfiguration('hotelview')['images']['background']); + const sun = GetNitroInstance().core.configuration.interpolate(GetConfiguration('hotelview')['images']['sun']); + const drape = GetNitroInstance().core.configuration.interpolate(GetConfiguration('hotelview')['images']['drape']); + const left = GetNitroInstance().core.configuration.interpolate(GetConfiguration('hotelview')['images']['left']); + const rightRepeat = GetNitroInstance().core.configuration.interpolate(GetConfiguration('hotelview')['images']['right.repeat']); + const right = GetNitroInstance().core.configuration.interpolate(GetConfiguration('hotelview')['images']['right']); return (
    diff --git a/src/views/inventory/common/FurnitureItem.ts b/src/views/inventory/common/FurnitureItem.ts index e063c9f0..d82b22e0 100644 --- a/src/views/inventory/common/FurnitureItem.ts +++ b/src/views/inventory/common/FurnitureItem.ts @@ -1,4 +1,5 @@ -import { IFurnitureItemData, IObjectData, Nitro } from 'nitro-renderer'; +import { IFurnitureItemData, IObjectData } from 'nitro-renderer'; +import { GetNitroInstance } from '../../../api'; import { IFurnitureItem } from './IFurnitureItem'; export class FurnitureItem implements IFurnitureItem @@ -122,7 +123,7 @@ export class FurnitureItem implements IFurnitureItem if(this._hasRentPeriodStarted) { - time = (this._secondsToExpiration - ((Nitro.instance.time - this._expirationTimeStamp) / 1000)); + time = (this._secondsToExpiration - ((GetNitroInstance().time - this._expirationTimeStamp) / 1000)); if(time < 0) time = 0; } diff --git a/src/views/main/MainView.tsx b/src/views/main/MainView.tsx index 92f222f5..db7f79c4 100644 --- a/src/views/main/MainView.tsx +++ b/src/views/main/MainView.tsx @@ -1,5 +1,6 @@ -import { Nitro, RoomSessionEvent } from 'nitro-renderer'; +import { RoomSessionEvent } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; +import { GetCommunication } from '../../api'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; import { AchievementsView } from '../achievements/AchievementsView'; import { AvatarEditorView } from '../avatar-editor/AvatarEditorView'; @@ -41,7 +42,7 @@ export const MainView: FC = props => { setIsReady(true); - Nitro.instance.communication.connection.onReady(); + GetCommunication().connection.onReady(); }, []); return ( diff --git a/src/views/navigator/NavigatorView.tsx b/src/views/navigator/NavigatorView.tsx index 3b4d5c52..68560927 100644 --- a/src/views/navigator/NavigatorView.tsx +++ b/src/views/navigator/NavigatorView.tsx @@ -1,5 +1,6 @@ -import { NavigatorInitComposer, NavigatorSearchComposer, RoomSessionEvent } from 'nitro-renderer'; +import { ILinkEventTracker, NavigatorInitComposer, NavigatorSearchComposer, RoomSessionEvent } from 'nitro-renderer'; import { FC, useCallback, useEffect, useReducer, useState } from 'react'; +import { AddEventLinkTracker, RemoveLinkEventTracker } from '../../api'; import { NavigatorEvent } from '../../events'; import { useRoomSessionManagerEvent } from '../../hooks/events/nitro/session/room-session-manager-event'; import { useUiEvent } from '../../hooks/events/ui/ui-event'; @@ -73,6 +74,45 @@ export const NavigatorView: FC = props => SendMessageHook(new NavigatorSearchComposer(contextCode, searchValue)); }, []); + const linkReceived = useCallback((url: string) => + { + const parts = url.split('/'); + + if(parts.length < 2) return; + + switch(parts[1]) + { + case 'goto': + if(parts.length > 2) + { + switch(parts[2]) + { + case 'home': + //goToHomeRoom(); + break; + default: { + const roomId = parseInt(parts[2]); + + //if(roomId > 0) this.goToPrivateRoom(roomId); + } + } + } + return; + } + }, []); + + useEffect(() => + { + const linkTracker: ILinkEventTracker = { + linkReceived, + eventUrlPrefix: 'navigator' + }; + + AddEventLinkTracker(linkTracker); + + return () => RemoveLinkEventTracker(linkTracker); + }, [ linkReceived]); + useEffect(() => { if(!isVisible || !needsNavigatorUpdate) return; diff --git a/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx b/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx index cf697e19..38850aa7 100644 --- a/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx +++ b/src/views/navigator/views/room-link/NavigatorRoomLinkView.tsx @@ -1,6 +1,5 @@ -import { Nitro } from 'nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; -import { GetConfiguration } from '../../../../api'; +import { GetConfiguration, GetNitroInstance } from '../../../../api'; import { NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../../../layout'; import { LocalizeText } from '../../../../utils/LocalizeText'; import { useNavigatorContext } from '../../context/NavigatorContext'; @@ -26,7 +25,7 @@ export const NavigatorRoomLinkView: FC = props => setRoomThumbnail(GetConfiguration('image.library.url') + roomInfoData.enteredGuestRoom.officialRoomPicRef); } - const roomLinkRaw = Nitro.instance.core.configuration.interpolate(LocalizeText('navigator.embed.src', ['roomId'], [roomInfoData.enteredGuestRoom.roomId.toString()])); + const roomLinkRaw = GetNitroInstance().core.configuration.interpolate(LocalizeText('navigator.embed.src', ['roomId'], [roomInfoData.enteredGuestRoom.roomId.toString()])); setRoomLink(roomLinkRaw); }, [ roomInfoData ]); diff --git a/src/views/room/RoomColorView.tsx b/src/views/room/RoomColorView.tsx index b7616615..3ac8a8f0 100644 --- a/src/views/room/RoomColorView.tsx +++ b/src/views/room/RoomColorView.tsx @@ -1,6 +1,6 @@ -import { ColorConverter, Nitro, NitroAdjustmentFilter, NitroContainer, NitroSprite, NitroTexture, RoomBackgroundColorEvent, RoomEngineEvent, RoomId, RoomObjectHSLColorEnabledEvent } from 'nitro-renderer'; +import { ColorConverter, NitroAdjustmentFilter, NitroContainer, NitroSprite, NitroTexture, RoomBackgroundColorEvent, RoomEngineEvent, RoomId, RoomObjectHSLColorEnabledEvent } from 'nitro-renderer'; import { FC, useCallback, useState } from 'react'; -import { GetRoomEngine } from '../../api'; +import { GetNitroInstance, GetRoomEngine } from '../../api'; import { UseMountEffect } from '../../hooks'; import { CreateEventDispatcherHook, useRoomEngineEvent } from '../../hooks/events'; import { useRoomContext } from './context/RoomContext'; @@ -48,8 +48,8 @@ export const RoomColorView: FC<{}> = props => if(color === undefined) color = 0x000000; background.tint = color; - background.width = Nitro.instance.width; - background.height = Nitro.instance.height; + background.width = GetNitroInstance().width; + background.height = GetNitroInstance().height; }, [ getRoomBackground ]); const updateRoomBackgroundColor = useCallback((hue: number, saturation: number, lightness: number, original: boolean = false) => diff --git a/src/views/room/RoomView.tsx b/src/views/room/RoomView.tsx index 3c187e72..babde88d 100644 --- a/src/views/room/RoomView.tsx +++ b/src/views/room/RoomView.tsx @@ -1,7 +1,7 @@ -import { EventDispatcher, Nitro, NitroRectangle, RoomGeometry, RoomVariableEnum, Vector3d } from 'nitro-renderer'; +import { EventDispatcher, NitroRectangle, RoomGeometry, RoomVariableEnum, Vector3d } from 'nitro-renderer'; import { FC, useEffect, useState } from 'react'; import { createPortal } from 'react-dom'; -import { InitializeRoomInstanceRenderingCanvas } from '../../api'; +import { GetNitroInstance, InitializeRoomInstanceRenderingCanvas } from '../../api'; import { DispatchMouseEvent } from '../../api/nitro/room/DispatchMouseEvent'; import { DispatchTouchEvent } from '../../api/nitro/room/DispatchTouchEvent'; import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine'; @@ -47,11 +47,11 @@ export const RoomView: FC = props => setWidgetHandler(widgetHandlerManager); - Nitro.instance.renderer.resize(window.innerWidth, window.innerHeight); + GetNitroInstance().renderer.resize(window.innerWidth, window.innerHeight); const canvasId = 1; - const displayObject = GetRoomEngine().getRoomInstanceDisplay(roomSession.roomId, canvasId, Nitro.instance.width, Nitro.instance.height, RoomGeometry.SCALE_ZOOMED_IN); + const displayObject = GetRoomEngine().getRoomInstanceDisplay(roomSession.roomId, canvasId, GetNitroInstance().width, GetNitroInstance().height, RoomGeometry.SCALE_ZOOMED_IN); if(!displayObject) return; @@ -77,13 +77,13 @@ export const RoomView: FC = props => geometry.location = new Vector3d(x, y, z); } - const stage = Nitro.instance.stage; + const stage = GetNitroInstance().stage; if(!stage) return; stage.addChild(displayObject); - const canvas = Nitro.instance.renderer.view; + const canvas = GetNitroInstance().renderer.view; if(!canvas) return; @@ -99,16 +99,16 @@ export const RoomView: FC = props => window.onresize = () => { - Nitro.instance.renderer.resize(window.innerWidth, window.innerHeight); + GetNitroInstance().renderer.resize(window.innerWidth, window.innerHeight); - InitializeRoomInstanceRenderingCanvas(roomSession.roomId, canvasId, Nitro.instance.width, Nitro.instance.height); + InitializeRoomInstanceRenderingCanvas(roomSession.roomId, canvasId, GetNitroInstance().width, GetNitroInstance().height); const bounds = canvas.getBoundingClientRect(); const rectangle = new NitroRectangle((bounds.x || 0), (bounds.y || 0), (bounds.width || 0), (bounds.height || 0)); widgetHandlerManager.eventDispatcher.dispatchEvent(new RoomWidgetUpdateRoomViewEvent(RoomWidgetUpdateRoomViewEvent.SIZE_CHANGED, rectangle)); - Nitro.instance.render(); + GetNitroInstance().render(); } setRoomCanvas(canvas); diff --git a/src/views/room/handlers/RoomWidgetInfostandHandler.ts b/src/views/room/handlers/RoomWidgetInfostandHandler.ts index 53d4c86b..1a50e05e 100644 --- a/src/views/room/handlers/RoomWidgetInfostandHandler.ts +++ b/src/views/room/handlers/RoomWidgetInfostandHandler.ts @@ -1,5 +1,5 @@ -import { IFurnitureData, Nitro, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer'; -import { GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; +import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomAdsUpdateComposer, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, SecurityLevel, Vector3d } from 'nitro-renderer'; +import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../api'; import { InventoryTradeRequestEvent, WiredSelectObjectEvent } from '../../../events'; import { FriendListSendFriendRequestEvent } from '../../../events/friend-list/FriendListSendFriendRequestEvent'; import { dispatchUiEvent } from '../../../hooks/events'; @@ -400,7 +400,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler const expiryTime = model.getValue(RoomObjectVariable.FURNITURE_EXPIRY_TIME); const expiryTimestamp = model.getValue(RoomObjectVariable.FURNITURE_EXPIRTY_TIMESTAMP); - event.expiration = ((expiryTime < 0) ? expiryTime : Math.max(0, (expiryTime - ((Nitro.instance.time - expiryTimestamp) / 1000)))); + event.expiration = ((expiryTime < 0) ? expiryTime : Math.max(0, (expiryTime - ((GetNitroInstance().time - expiryTimestamp) / 1000)))); let roomObjectImage = GetRoomEngine().getRoomObjectImage(roomId, message.id, message.category, new Vector3d(180), 64, null); diff --git a/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx index 6f91a26b..16bb9a72 100644 --- a/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx +++ b/src/views/room/widgets/avatar-info/views/rentable-bot/AvatarInfoWidgetRentableBotView.tsx @@ -1,5 +1,6 @@ -import { BotCommandConfigurationEvent, BotRemoveComposer, BotSkillSaveComposer, Nitro, RequestBotCommandConfigurationComposer, RoomObjectCategory, RoomObjectType } from 'nitro-renderer'; +import { BotCommandConfigurationEvent, BotRemoveComposer, BotSkillSaveComposer, RequestBotCommandConfigurationComposer, RoomObjectCategory, RoomObjectType } from 'nitro-renderer'; import { FC, useCallback, useEffect, useState } from 'react'; +import { GetNitroInstance } from '../../../../../../api'; import { CreateMessageHook, SendMessageHook } from '../../../../../../hooks/messages'; import { LocalizeText } from '../../../../../../utils/LocalizeText'; import { useRoomContext } from '../../../../context/RoomContext'; @@ -119,7 +120,7 @@ export const AvatarInfoWidgetRentableBotView: FC = props => let x = (location.x - (elementRef.current.offsetWidth / 2)); let y = (deltaY + offset); - const maxLeft = ((Nitro.instance.width - elementRef.current.offsetWidth) - SPACE_AROUND_EDGES); - const maxTop = ((Nitro.instance.height - elementRef.current.offsetHeight) - SPACE_AROUND_EDGES); + const maxLeft = ((GetNitroInstance().width - elementRef.current.offsetWidth) - SPACE_AROUND_EDGES); + const maxTop = ((GetNitroInstance().height - elementRef.current.offsetHeight) - SPACE_AROUND_EDGES); if(x < SPACE_AROUND_EDGES) x = SPACE_AROUND_EDGES; else if(x > maxLeft) x = maxLeft; diff --git a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx b/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx index 151e0a3e..3c31b0a9 100644 --- a/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx +++ b/src/views/room/widgets/furniture/mannequin/FurnitureMannequinView.tsx @@ -1,5 +1,6 @@ -import { AvatarFigurePartType, FurnitureMannequinSaveLookComposer, FurnitureMannequinSaveNameComposer, FurnitureMultiStateComposer, IAvatarFigureContainer, Nitro, NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer'; +import { AvatarFigurePartType, FurnitureMannequinSaveLookComposer, FurnitureMannequinSaveNameComposer, FurnitureMultiStateComposer, IAvatarFigureContainer, NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer'; import { FC, KeyboardEvent, useCallback, useEffect, useState } from 'react'; +import { GetNitroInstance } from '../../../../../api'; import { GetRoomEngine } from '../../../../../api/nitro/room/GetRoomEngine'; import { GetRoomSession } from '../../../../../api/nitro/session/GetRoomSession'; import { GetSessionDataManager } from '../../../../../api/nitro/session/GetSessionDataManager'; @@ -49,7 +50,7 @@ export const FurnitureMannequinView: FC<{}> = props => { if(mannequinData && !mannequinData.renderedFigure) { - const figureContainer = Nitro.instance.avatar.createFigureContainer(mannequinData.figure); + const figureContainer = GetNitroInstance().avatar.createFigureContainer(mannequinData.figure); loadMannequinFigure(figureContainer); } }, [loadMannequinFigure, mannequinData]); @@ -59,8 +60,8 @@ export const FurnitureMannequinView: FC<{}> = props => if(!mannequinData) return; const userCanEdit = (GetRoomSession().isRoomOwner || GetSessionDataManager().isModerator); - const userGender = Nitro.instance.sessionDataManager.gender; - const userClubLevel = Nitro.instance.sessionDataManager.clubLevel; + const userGender = GetNitroInstance().sessionDataManager.gender; + const userClubLevel = GetNitroInstance().sessionDataManager.clubLevel; if(userCanEdit) { @@ -100,8 +101,8 @@ export const FurnitureMannequinView: FC<{}> = props => const gender = roomObject.model.getValue(RoomObjectVariable.FURNITURE_MANNEQUIN_GENDER); const name = roomObject.model.getValue(RoomObjectVariable.FURNITURE_MANNEQUIN_NAME); - const figureContainer = Nitro.instance.avatar.createFigureContainer(figure); - const clubLevel = Nitro.instance.avatar.getFigureClubLevel(figureContainer, gender, parts); + const figureContainer = GetNitroInstance().avatar.createFigureContainer(figure); + const clubLevel = GetNitroInstance().avatar.getFigureClubLevel(figureContainer, gender, parts); const mannequinData = new FurnitureMannequinData(widgetEvent.objectId, widgetEvent.category, name, figure, gender, clubLevel); @@ -137,11 +138,11 @@ export const FurnitureMannequinView: FC<{}> = props => setMannequinData(mannequinData => new FurnitureMannequinData(mannequinData.objectId, mannequinData.category, value, mannequinData.figure, mannequinData.gender, mannequinData.clubLevel, mannequinData.renderedFigure)); return; case 'load_figure': - loadMannequinFigure(Nitro.instance.avatar.createFigureContainer(Nitro.instance.sessionDataManager.figure)); + loadMannequinFigure(GetNitroInstance().avatar.createFigureContainer(GetNitroInstance().sessionDataManager.figure)); setViewMode(MannequinViewMode.SAVE); return; case 'back': - loadMannequinFigure(Nitro.instance.avatar.createFigureContainer(mannequinData.figure)); + loadMannequinFigure(GetNitroInstance().avatar.createFigureContainer(mannequinData.figure)); setViewMode(MannequinViewMode.EDIT); return; case 'save_name': diff --git a/src/views/room/widgets/object-location/ObjectLocationView.tsx b/src/views/room/widgets/object-location/ObjectLocationView.tsx index 04bf1f20..36a735c9 100644 --- a/src/views/room/widgets/object-location/ObjectLocationView.tsx +++ b/src/views/room/widgets/object-location/ObjectLocationView.tsx @@ -1,6 +1,5 @@ -import { Nitro } from 'nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; -import { GetRoomEngine, GetRoomSession } from '../../../../api'; +import { GetNitroInstance, GetRoomEngine, GetRoomSession } from '../../../../api'; import { ObjectLocationViewProps } from './ObjectLocationView.types'; export const ObjectLocationView: FC = props => @@ -41,12 +40,12 @@ export const ObjectLocationView: FC = props => { remove = true; - Nitro.instance.ticker.add(updatePosition); + GetNitroInstance().ticker.add(updatePosition); } return () => { - if(remove) Nitro.instance.ticker.remove(updatePosition); + if(remove) GetNitroInstance().ticker.remove(updatePosition); } }, [ updatePosition, noFollow ]); diff --git a/src/views/shared/room-previewer/RoomPreviewerView.tsx b/src/views/shared/room-previewer/RoomPreviewerView.tsx index b2e972a4..d7894d54 100644 --- a/src/views/shared/room-previewer/RoomPreviewerView.tsx +++ b/src/views/shared/room-previewer/RoomPreviewerView.tsx @@ -1,5 +1,6 @@ -import { ColorConverter, IRoomRenderingCanvas, Nitro, TextureUtils } from 'nitro-renderer'; +import { ColorConverter, IRoomRenderingCanvas, TextureUtils } from 'nitro-renderer'; import { FC, useCallback, useEffect, useRef, useState } from 'react'; +import { GetNitroInstance } from '../../../api'; import { RoomPreviewerViewProps } from './RoomPreviewerView.types'; export const RoomPreviewerView: FC = props => @@ -56,7 +57,7 @@ export const RoomPreviewerView: FC = props => if(!renderingCanvas) setupPreviewer(); - Nitro.instance.ticker.add(update); + GetNitroInstance().ticker.add(update); function resize(): void { @@ -76,7 +77,7 @@ export const RoomPreviewerView: FC = props => return () => { - Nitro.instance.ticker.remove(update); + GetNitroInstance().ticker.remove(update); window.removeEventListener('resize', resize); }