This commit is contained in:
Bill 2021-06-13 04:13:48 -04:00
commit 976f70ed5b
38 changed files with 614 additions and 24 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 959 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

Before

Width:  |  Height:  |  Size: 183 B

After

Width:  |  Height:  |  Size: 183 B

View File

Before

Width:  |  Height:  |  Size: 154 B

After

Width:  |  Height:  |  Size: 154 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -3,3 +3,4 @@ export * from './catalog';
export * from './friend-list'; export * from './friend-list';
export * from './inventory'; export * from './inventory';
export * from './navigator'; export * from './navigator';
export * from './room-widgets';

View File

@ -0,0 +1,13 @@
import { NitroEvent } from 'nitro-renderer';
export class RoomWidgetCameraEvent extends NitroEvent
{
public static SHOW_CAMERA: string = 'NE_SHOW_CAMERA';
public static HIDE_CAMERA: string = 'NE_HIDE_CAMERA';
public static TOGGLE_CAMERA: string = 'NE_TOGGLE_CAMERA';
constructor(type: string)
{
super(type);
}
}

View File

@ -0,0 +1 @@
export * from './RoomWidgetCameraEvent';

View File

@ -0,0 +1 @@
export * from './camera';

View File

@ -8,10 +8,10 @@ export const CatalogLayoutPets3View: FC<CatalogLayoutPets3ViewProps> = props =>
return ( return (
<div className="row h-100 nitro-catalog-layout-pets3"> <div className="row h-100 nitro-catalog-layout-pets3">
<div className="col-7"> <div className="col-7 text-black">
<div className="" dangerouslySetInnerHTML={ {__html: GetCatalogPageText(pageParser, 1) } } /> <div dangerouslySetInnerHTML={ {__html: GetCatalogPageText(pageParser, 1) } } />
<div className="" dangerouslySetInnerHTML={ {__html: GetCatalogPageText(pageParser, 2) } } /> <div dangerouslySetInnerHTML={ {__html: GetCatalogPageText(pageParser, 2) } } />
<div className="" dangerouslySetInnerHTML={ {__html: GetCatalogPageText(pageParser, 3) } } /> <div dangerouslySetInnerHTML={ {__html: GetCatalogPageText(pageParser, 3) } } />
</div> </div>
<div className="position-relative d-flex flex-column col-5 justify-content-center align-items-center"> <div className="position-relative d-flex flex-column col-5 justify-content-center align-items-center">
<div className="d-block mb-2"> <div className="d-block mb-2">

View File

@ -7,6 +7,7 @@ import { DispatchTouchEvent } from '../../api/nitro/room/DispatchTouchEvent';
import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine'; import { GetRoomEngine } from '../../api/nitro/room/GetRoomEngine';
import { RoomViewProps } from './RoomView.types'; import { RoomViewProps } from './RoomView.types';
import { AvatarInfoWidgetView } from './widgets/avatar-info/AvatarInfoWidgetView'; import { AvatarInfoWidgetView } from './widgets/avatar-info/AvatarInfoWidgetView';
import { CameraWidgetView } from './widgets/camera/CameraWidgetView';
import { ChatInputView } from './widgets/chat-input/ChatInputView'; import { ChatInputView } from './widgets/chat-input/ChatInputView';
import { ChatWidgetView } from './widgets/chat/ChatWidgetView'; import { ChatWidgetView } from './widgets/chat/ChatWidgetView';
import { FurnitureWidgetsView } from './widgets/furniture/FurnitureWidgetsView'; import { FurnitureWidgetsView } from './widgets/furniture/FurnitureWidgetsView';
@ -92,6 +93,7 @@ export function RoomView(props: RoomViewProps): JSX.Element
createPortal(props.children, document.getElementById('room-view').appendChild(roomCanvas)) && createPortal(props.children, document.getElementById('room-view').appendChild(roomCanvas)) &&
<> <>
<AvatarInfoWidgetView events={ events } /> <AvatarInfoWidgetView events={ events } />
<CameraWidgetView />
<ChatWidgetView /> <ChatWidgetView />
<ChatInputView /> <ChatInputView />
<FurnitureWidgetsView events={ events } /> <FurnitureWidgetsView events={ events } />

View File

@ -1,3 +1,4 @@
@import './camera/CameraWidgetView';
@import './chat/ChatWidgetView'; @import './chat/ChatWidgetView';
@import './chat-input/ChatInputView'; @import './chat-input/ChatInputView';
@import './furniture/FurnitureWidgets'; @import './furniture/FurnitureWidgets';

View File

@ -0,0 +1,24 @@
.nitro-camera {
width: 340px;
height: 462px;
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
.camera-button {
width: 94px;
height: 94px;
cursor: pointer;
margin-top: 334px;
background-image: url('../../../../assets/images/room-widgets/camera-widget/camera-spritesheet.png');
background-position: -340px 0px;
&:hover {
background-position: -340px -94px;
}
&:active {
background-position: -340px -188px;
}
}
}

View File

@ -0,0 +1,57 @@
import { FC, useCallback, useState } from 'react';
import { RoomWidgetCameraEvent } from '../../../../events/room-widgets/camera/RoomWidgetCameraEvent';
import { DraggableWindow } from '../../../../hooks/draggable-window/DraggableWindow';
import { useUiEvent } from '../../../../hooks/events/ui/ui-event';
import { CameraWidgetViewProps } from './CameraWidgetView.types';
export const CameraWidgetView: FC<CameraWidgetViewProps> = props =>
{
const [ isVisible, setIsVisible ] = useState(false);
const onRoomWidgetCameraEvent = useCallback((event: RoomWidgetCameraEvent) =>
{
switch(event.type)
{
case RoomWidgetCameraEvent.SHOW_CAMERA:
setIsVisible(true);
return;
case RoomWidgetCameraEvent.HIDE_CAMERA:
setIsVisible(false);
return;
case RoomWidgetCameraEvent.TOGGLE_CAMERA:
setIsVisible(value => !value);
return;
}
}, []);
useUiEvent(RoomWidgetCameraEvent.SHOW_CAMERA, onRoomWidgetCameraEvent);
useUiEvent(RoomWidgetCameraEvent.HIDE_CAMERA, onRoomWidgetCameraEvent);
useUiEvent(RoomWidgetCameraEvent.TOGGLE_CAMERA, onRoomWidgetCameraEvent);
const processAction = useCallback((type: string, value: string = null) =>
{
switch(type)
{
case 'close':
setIsVisible(false);
return;
}
}, []);
if(!isVisible) return null;
return (
<DraggableWindow handle=".nitro-camera">
<div className="nitro-camera">
<div className="overflow-auto">
<div className="cursor-pointer float-end me-3 mt-2" onClick={ event => processAction('close') }>
<i className="fas fa-times"></i>
</div>
</div>
<div className="d-flex justify-content-center">
<div className="camera-button"></div>
</div>
</div>
</DraggableWindow>
);
}

View File

@ -0,0 +1,2 @@
export interface CameraWidgetViewProps
{}

View File

@ -1,3 +1,6 @@
@import './engraving-lock/FurnitureEngravingLockView';
@import './exchange-credit/FurnitureExchangeCreditView';
@import './manipulation-menu/FurnitureManipulationMenuView'; @import './manipulation-menu/FurnitureManipulationMenuView';
@import './mannequin/FurnitureMannequinView';
@import './stickie/FurnitureStickieView'; @import './stickie/FurnitureStickieView';
@import './trophy/FurnitureTrophyView'; @import './trophy/FurnitureTrophyView';

View File

@ -1,3 +1,4 @@
import { FurnitureEngravingLockView } from './engraving-lock/FurnitureEngravingLockView';
import { FurnitureExchangeCreditView } from './exchange-credit/FurnitureExchangeCreditView'; import { FurnitureExchangeCreditView } from './exchange-credit/FurnitureExchangeCreditView';
import { FurnitureWidgetsViewProps } from './FurnitureWidgetsView.types'; import { FurnitureWidgetsViewProps } from './FurnitureWidgetsView.types';
import { FurnitureHighScoreView } from './high-score/FurnitureHighScoreView'; import { FurnitureHighScoreView } from './high-score/FurnitureHighScoreView';
@ -13,6 +14,7 @@ export function FurnitureWidgetsView(props: FurnitureWidgetsViewProps): JSX.Elem
return ( return (
<div className="position-absolute nitro-room-widgets t-0 l-0"> <div className="position-absolute nitro-room-widgets t-0 l-0">
<FurnitureEngravingLockView events={ events } />
<FurnitureExchangeCreditView events={ events } /> <FurnitureExchangeCreditView events={ events } />
<FurnitureHighScoreView events={ events } /> <FurnitureHighScoreView events={ events } />
<FurnitureManipulationMenuView events={ events } /> <FurnitureManipulationMenuView events={ events } />

View File

@ -0,0 +1,10 @@
export class FurnitureEngravingLockData
{
constructor(
public objectId: number,
public category: number = 0,
public type: number = 0,
public usernames: string[] = [],
public figures: string[] = [],
public date: string = null) {}
}

View File

@ -0,0 +1,76 @@
.nitro-engraving-lock {
width: 300px;
.engraving-lock-stage-1 {
width: 31px;
height: 39px;
background-position: -380px -43px;
background-image: url('../../../../../assets/images/room-widgets/engraving-lock-widget/engraving-lock-spritesheet.png');
}
.engraving-lock-stage-2 {
width: 36px;
height: 43px;
background-position: -375px 0px;
background-image: url('../../../../../assets/images/room-widgets/engraving-lock-widget/engraving-lock-spritesheet.png');
}
}
.nitro-engraving-lock-view {
width: 375px;
height: 210px;
background-position: 0px 0px;
background-image: url('../../../../../assets/images/room-widgets/engraving-lock-widget/engraving-lock-spritesheet.png');
color: #622e54;
font-weight: bold;
font-size: 16px;
text-shadow: 0px 1px white;
&.engraving-lock-3 {
background-position: 0px -210px;
color: #614110;
}
&.engraving-lock-4 {
background-position: 0px -420px;
color: #f1dcc8;
text-shadow: 0px 2px rgba(0, 0, 0, .4);
.engraving-lock-avatar {
margin-bottom: 10px;
}
}
.engraving-lock-close {
position: absolute;
cursor: pointer;
width: 15px;
height: 15px;
top: 34px;
right: 27px;
}
.engraving-lock-avatar {
width: 70px;
height: 120px;
div {
position: absolute;
margin-top: -5px;
}
&:nth-child(1) {
div {
margin-left: -10px;
}
}
&:nth-child(2) {
div {
margin-left: -15px;
}
}
}
}

View File

@ -0,0 +1,149 @@
import { LoveLockFurniFinishedEvent, LoveLockFurniFriendConfirmedEvent, LoveLockFurniStartEvent, LoveLockStartConfirmComposer, NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { GetRoomSession } from '../../../../../api';
import { GetRoomEngine } from '../../../../../api/nitro/room/GetRoomEngine';
import { DraggableWindow } from '../../../../../hooks/draggable-window/DraggableWindow';
import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base';
import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event';
import { CreateMessageHook } from '../../../../../hooks/messages/message-event';
import { NitroCardContentView } from '../../../../../layout/card/content/NitroCardContentView';
import { NitroCardHeaderView } from '../../../../../layout/card/header/NitroCardHeaderView';
import { NitroCardView } from '../../../../../layout/card/NitroCardView';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { AvatarImageView } from '../../../../avatar-image/AvatarImageView';
import { RoomWidgetRoomObjectUpdateEvent } from '../../events/RoomWidgetRoomObjectUpdateEvent';
import { FurnitureEngravingLockData } from './FurnitureEngravingLockData';
import { FurnitureEngravingLockViewProps } from './FurnitureEngravingLockView.types';
export const FurnitureEngravingLockView: FC<FurnitureEngravingLockViewProps> = props =>
{
const [ engravingLockData, setEngravingLockData ] = useState<FurnitureEngravingLockData>(null);
const [ engravingStage, setEngravingStage ] = useState(0);
const onNitroEvent = (event: NitroEvent) =>
{
switch(event.type)
{
case RoomEngineTriggerWidgetEvent.REQUEST_FRIEND_FURNITURE_ENGRAVING: {
const widgetEvent = (event as RoomEngineTriggerWidgetEvent);
const roomObject = GetRoomEngine().getRoomObject(widgetEvent.roomId, widgetEvent.objectId, widgetEvent.category);
if(!roomObject) return;
const data = roomObject.model.getValue<string[]>(RoomObjectVariable.FURNITURE_DATA);
const type = roomObject.model.getValue<number>(RoomObjectVariable.FURNITURE_FRIENDFURNI_ENGRAVING)
if(data[0] === '1')
{
if(data.length !== 6) return;
setEngravingLockData(new FurnitureEngravingLockData(widgetEvent.objectId, widgetEvent.category, type, [ data[1], data[2] ], [ data[3], data[4] ], data[5]));
}
return;
}
case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: {
const widgetEvent = (event as RoomWidgetRoomObjectUpdateEvent);
setEngravingLockData(prevState =>
{
if(!prevState || (widgetEvent.id !== prevState.objectId) || (widgetEvent.category !== prevState.category)) return prevState;
return null;
});
return;
}
}
};
useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_FRIEND_FURNITURE_ENGRAVING, onNitroEvent);
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, props.events, onNitroEvent);
const onLoveLockFurniStartEvent = useCallback((event: LoveLockFurniStartEvent) =>
{
const parser = event.getParser();
setEngravingLockData(new FurnitureEngravingLockData(parser.furniId));
if(parser.start)
setEngravingStage(1);
else
setEngravingStage(2);
}, [ engravingStage ]);
const onLoveLockDoneEvent = useCallback((event: LoveLockFurniFinishedEvent | LoveLockFurniFriendConfirmedEvent) =>
{
processAction('close_request');
}, []);
CreateMessageHook(LoveLockFurniStartEvent, onLoveLockFurniStartEvent);
CreateMessageHook(LoveLockFurniFinishedEvent, onLoveLockDoneEvent);
CreateMessageHook(LoveLockFurniFriendConfirmedEvent, onLoveLockDoneEvent);
const processAction = useCallback((type: string, value: string = null) =>
{
switch(type)
{
case 'close_view':
setEngravingLockData(null);
return;
case 'accept_request':
GetRoomSession().connection.send(new LoveLockStartConfirmComposer(engravingLockData.objectId, true));
return;
case 'reject_request':
GetRoomSession().connection.send(new LoveLockStartConfirmComposer(engravingLockData.objectId, false));
processAction('close_request');
return;
case 'close_request':
setEngravingStage(0);
setEngravingLockData(null);
return;
}
}, [ engravingLockData ]);
return (
<>
{ engravingStage > 0 && <NitroCardView className="nitro-engraving-lock">
<NitroCardHeaderView headerText={ LocalizeText('friend.furniture.confirm.lock.caption') } onCloseClick={ event => processAction('close_request') } />
<NitroCardContentView>
<h5 className="text-black text-center fw-bold mt-2 mb-2">
{ LocalizeText('friend.furniture.confirm.lock.subtitle') }
</h5>
<div className="d-flex justify-content-center mb-2">
<div className={ "engraving-lock-stage-" + engravingStage }></div>
</div>
{ engravingStage === 2 && <div className="text-small text-black text-center mb-2">{ LocalizeText('friend.furniture.confirm.lock.other.locked') }</div> }
<div className="d-flex">
<button className="btn btn-primary w-100 me-2" onClick={ event => processAction('reject_request') }>{ LocalizeText('friend.furniture.confirm.lock.button.cancel') }</button>
<button className="btn btn-success w-100" onClick={ event => processAction('accept_request') }>{ LocalizeText('friend.furniture.confirm.lock.button.confirm') }</button>
</div>
</NitroCardContentView>
</NitroCardView> }
{ engravingLockData && engravingLockData.usernames.length > 0 && <DraggableWindow handle=".nitro-engraving-lock-view">
<div className={ "nitro-engraving-lock-view engraving-lock-" + engravingLockData.type }>
<div className="engraving-lock-close" onClick={ event => processAction('close_view') }></div>
<div className="d-flex justify-content-center">
<div className="engraving-lock-avatar">
<AvatarImageView figure={ engravingLockData.figures[0] } direction={ 2 } />
</div>
<div className="engraving-lock-avatar">
<AvatarImageView figure={ engravingLockData.figures[1] } direction={ 4 } />
</div>
</div>
<div className="text-center mt-1">
<div>
{ engravingLockData.type === 0 && LocalizeText('lovelock.engraving.caption') }
{ engravingLockData.type === 3 && LocalizeText('wildwest.engraving.caption') }
</div>
<div>{ engravingLockData.date }</div>
<div className="d-flex justify-content-center">
<div className="me-4">{ engravingLockData.usernames[0] }</div>
<div>{ engravingLockData.usernames[1] }</div>
</div>
</div>
</div>
</DraggableWindow> }
</>
);
}

View File

@ -0,0 +1,4 @@
import { FurnitureWidgetProps } from '../FurnitureWidget.types';
export interface FurnitureEngravingLockViewProps extends FurnitureWidgetProps
{}

View File

@ -0,0 +1,3 @@
.nitro-exchange-credit {
width: 250px;
}

View File

@ -23,6 +23,8 @@ export const FurnitureExchangeCreditView: FC<FurnitureExchangeCreditProps> = pro
const roomObject = GetRoomEngine().getRoomObject(widgetEvent.roomId, widgetEvent.objectId, widgetEvent.category); const roomObject = GetRoomEngine().getRoomObject(widgetEvent.roomId, widgetEvent.objectId, widgetEvent.category);
if(!roomObject) return;
const value = roomObject.model.getValue<number>(RoomObjectVariable.FURNITURE_CREDIT_VALUE); const value = roomObject.model.getValue<number>(RoomObjectVariable.FURNITURE_CREDIT_VALUE);
setExchangeCreditData(new FurnitureExchangeCreditData(widgetEvent.objectId, widgetEvent.category, value)); setExchangeCreditData(new FurnitureExchangeCreditData(widgetEvent.objectId, widgetEvent.category, value));
@ -63,7 +65,7 @@ export const FurnitureExchangeCreditView: FC<FurnitureExchangeCreditProps> = pro
if(!exchangeCreditData) return null; if(!exchangeCreditData) return null;
return ( return (
<NitroCardView className="nitro-friend-list"> <NitroCardView className="nitro-exchange-credit">
<NitroCardHeaderView headerText={ LocalizeText('catalog.redeem.dialog.title') } onCloseClick={ event => processAction('close') } /> <NitroCardHeaderView headerText={ LocalizeText('catalog.redeem.dialog.title') } onCloseClick={ event => processAction('close') } />
<NitroCardContentView> <NitroCardContentView>
<div className="text-black mb-2"> <div className="text-black mb-2">

View File

@ -1,17 +1,17 @@
import { RoomEngineObjectEvent, RoomEngineTriggerWidgetEvent } from 'nitro-renderer'; import { NitroEvent, RoomEngineTriggerWidgetEvent } from 'nitro-renderer';
import { FC } from 'react'; import { FC } from 'react';
import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event'; import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event';
import { FurnitureHighScoreViewProps } from './FurnitureHighScoreView.types'; import { FurnitureHighScoreViewProps } from './FurnitureHighScoreView.types';
export const FurnitureHighScoreView: FC<FurnitureHighScoreViewProps> = props => export const FurnitureHighScoreView: FC<FurnitureHighScoreViewProps> = props =>
{ {
const onRoomEngineObjectEvent = (event: RoomEngineObjectEvent) => const onNitroEvent = (event: NitroEvent) =>
{ {
console.log(event); console.log(event);
}; };
useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_HIGH_SCORE_DISPLAY, onRoomEngineObjectEvent); useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_HIGH_SCORE_DISPLAY, onNitroEvent);
useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_HIDE_HIGH_SCORE_DISPLAY, onRoomEngineObjectEvent); useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_HIDE_HIGH_SCORE_DISPLAY, onNitroEvent);
return null; return null;
} }

View File

@ -0,0 +1,11 @@
export class FurnitureMannequinData
{
constructor(
public objectId: number,
public category: number,
public name: string,
public figure: string,
public gender: string,
public clubLevel: number,
public renderedFigure: string = null) {}
}

View File

@ -0,0 +1,9 @@
.nitro-mannequin {
width: 350px;
.mannequin-preview {
width: 83px;
height: 130px;
background-image: url('../../../../../assets/images/room-widgets/mannequin-widget/mannequin-spritesheet.png');
}
}

View File

@ -1,16 +1,218 @@
import { RoomEngineObjectEvent, RoomEngineTriggerWidgetEvent } from 'nitro-renderer'; import { AvatarFigurePartType, FurnitureMannequinSaveLookComposer, FurnitureMannequinSaveNameComposer, FurnitureMultiStateComposer, IAvatarFigureContainer, Nitro, NitroEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer';
import { FC } from 'react'; import { FC, KeyboardEvent, useCallback, useEffect, useState } from 'react';
import { GetRoomEngine } from '../../../../../api/nitro/room/GetRoomEngine';
import { GetRoomSession } from '../../../../../api/nitro/session/GetRoomSession';
import { GetSessionDataManager } from '../../../../../api/nitro/session/GetSessionDataManager';
import { CreateEventDispatcherHook } from '../../../../../hooks/events/event-dispatcher.base';
import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event'; import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event';
import { FurnitureMannequinViewProps } from './FurnitureMannequinView.types'; import { NitroCardContentView } from '../../../../../layout/card/content/NitroCardContentView';
import { NitroCardHeaderView } from '../../../../../layout/card/header/NitroCardHeaderView';
import { NitroCardView } from '../../../../../layout/card/NitroCardView';
import { LocalizeText } from '../../../../../utils/LocalizeText';
import { AvatarImageView } from '../../../../avatar-image/AvatarImageView';
import { RoomWidgetRoomObjectUpdateEvent } from '../../events';
import { FurnitureMannequinData } from './FurnitureMannequinData';
import { FurnitureMannequinViewMode, FurnitureMannequinViewProps } from './FurnitureMannequinView.types';
export const FurnitureMannequinView: FC<FurnitureMannequinViewProps> = props => export const FurnitureMannequinView: FC<FurnitureMannequinViewProps> = props =>
{ {
const onRoomEngineObjectEvent = (event: RoomEngineObjectEvent) => const parts = [
AvatarFigurePartType.CHEST_ACCESSORY,
AvatarFigurePartType.COAT_CHEST,
AvatarFigurePartType.CHEST,
AvatarFigurePartType.LEGS,
AvatarFigurePartType.SHOES,
AvatarFigurePartType.WAIST_ACCESSORY
];
const baseAvatar = ['hd', 99999, 99998];
const [ mannequinData, setMannequinData ] = useState<FurnitureMannequinData>(null);
const [ viewMode, setViewMode ] = useState('');
useEffect(() =>
{ {
console.log(event); if(mannequinData && !mannequinData.renderedFigure)
{
const figureContainer = Nitro.instance.avatar.createFigureContainer(mannequinData.figure);
loadMannequinFigure(figureContainer);
}
}, [ mannequinData ]);
const onNitroEvent = useCallback((event: NitroEvent) =>
{
switch(event.type)
{
case RoomEngineTriggerWidgetEvent.REQUEST_MANNEQUIN: {
const widgetEvent = (event as RoomEngineTriggerWidgetEvent);
const roomObject = GetRoomEngine().getRoomObject(widgetEvent.roomId, widgetEvent.objectId, widgetEvent.category);
if(!roomObject) return;
const figure = roomObject.model.getValue<string>(RoomObjectVariable.FURNITURE_MANNEQUIN_FIGURE);
const gender = roomObject.model.getValue<string>(RoomObjectVariable.FURNITURE_MANNEQUIN_GENDER);
const name = roomObject.model.getValue<string>(RoomObjectVariable.FURNITURE_MANNEQUIN_NAME);
const figureContainer = Nitro.instance.avatar.createFigureContainer(figure);
const clubLevel = Nitro.instance.avatar.getFigureClubLevel(figureContainer, gender, parts);
const mannequinData = new FurnitureMannequinData(widgetEvent.objectId, widgetEvent.category, name, figure, gender, clubLevel);
setMannequinData(mannequinData);
loadViewMode(mannequinData);
return;
}
case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: {
const widgetEvent = (event as RoomWidgetRoomObjectUpdateEvent);
setMannequinData(prevState =>
{
if(!prevState || (widgetEvent.id !== prevState.objectId) || (widgetEvent.category !== prevState.category)) return prevState;
return null;
});
return;
}
}
}, []);
useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_MANNEQUIN, onNitroEvent);
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, props.events, onNitroEvent);
const loadMannequinFigure = useCallback((figureContainer: IAvatarFigureContainer) =>
{
for(const item of figureContainer.getPartTypeIds())
{
if(parts.indexOf(item) == -1)
{
figureContainer.removePart(item);
}
}
figureContainer.updatePart(baseAvatar[0].toString(), Number(baseAvatar[1]), [ Number(baseAvatar[2]) ]);
setMannequinData(mannequinData => new FurnitureMannequinData(mannequinData.objectId, mannequinData.category, mannequinData.name, mannequinData.figure, mannequinData.gender, mannequinData.clubLevel, figureContainer.getFigureString()));
}, []);
const loadViewMode = useCallback((mannequinData: FurnitureMannequinData) =>
{
if(!mannequinData) return;
const userCanEdit = (GetRoomSession().isRoomOwner || GetSessionDataManager().isModerator);
const userGender = Nitro.instance.sessionDataManager.gender;
const userClubLevel = Nitro.instance.sessionDataManager.clubLevel;
if(userCanEdit)
{
setViewMode(FurnitureMannequinViewMode.EDIT);
}
else
{
if(!mannequinData.figure || mannequinData.figure.length <= 1) return;
if(userGender.toUpperCase() !== mannequinData.gender.toUpperCase())
{
setViewMode(FurnitureMannequinViewMode.INCOMPATIBLE_GENDER);
}
else if(userClubLevel < mannequinData.clubLevel)
{
setViewMode(FurnitureMannequinViewMode.CLUB);
}
else
{
setViewMode(FurnitureMannequinViewMode.DEFAULT);
}
}
}, []);
const processAction = useCallback((type: string, value: string = null) =>
{
switch(type)
{
case 'close':
setMannequinData(null);
return;
case 'set_name':
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));
setViewMode(FurnitureMannequinViewMode.SAVE);
return;
case 'back':
loadMannequinFigure(Nitro.instance.avatar.createFigureContainer(mannequinData.figure));
setViewMode(FurnitureMannequinViewMode.EDIT);
return;
case 'save_name':
GetRoomSession().connection.send(new FurnitureMannequinSaveNameComposer(mannequinData.objectId, mannequinData.name));
return;
case 'save_figure':
GetRoomSession().connection.send(new FurnitureMannequinSaveLookComposer(mannequinData.objectId));
processAction('save_name');
processAction('close');
return;
case 'wear':
GetRoomSession().connection.send(new FurnitureMultiStateComposer(mannequinData.objectId));
processAction('close');
return;
}
}, [ mannequinData ]);
const handleKeyDown = (event: KeyboardEvent<HTMLInputElement>) =>
{
if(event.key !== 'Enter') return;
processAction('save_name');
}; };
useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_MANNEQUIN, onRoomEngineObjectEvent); if(!mannequinData) return null;
return null; return (
<NitroCardView className="nitro-mannequin">
<NitroCardHeaderView headerText={ LocalizeText('mannequin.widget.title') } onCloseClick={ event => processAction('close') } />
<NitroCardContentView>
<div className="row">
<div className="col-4">
<div className="mannequin-preview">
<AvatarImageView figure={ mannequinData.renderedFigure } direction={ 2 } />
</div>
</div>
<div className="col">
{ viewMode === FurnitureMannequinViewMode.EDIT && <>
<input type="text" className="form-control mb-2" value={ mannequinData.name } onChange={ event => processAction('set_name', event.target.value) } onKeyDown={ event => handleKeyDown(event) } />
<div className="btn btn-success mb-2 w-100" onClick={ event => processAction('load_figure') }>{ LocalizeText('mannequin.widget.style') }</div>
<div className="btn btn-success w-100" onClick={ event => processAction('wear') }>{ LocalizeText('mannequin.widget.wear') }</div>
</> }
{ viewMode === FurnitureMannequinViewMode.SAVE && <>
<div className="d-flex flex-column h-100">
<div className="h-100">
<div className="mb-2 text-black fw-bold">{ mannequinData.name }</div>
<div className="text-black">{ LocalizeText('mannequin.widget.savetext') }</div>
</div>
<div className="d-flex justify-content-between align-items-center">
<div className="text-black text-decoration-underline" onClick={ event => processAction('back') }>{ LocalizeText('mannequin.widget.back') }</div>
<div className="btn btn-success" onClick={ event => processAction('save_figure') }>{ LocalizeText('mannequin.widget.save') }</div>
</div>
</div>
</> }
{ viewMode === FurnitureMannequinViewMode.DEFAULT && <>
<div className="d-flex flex-column h-100">
<div className="h-100">
<div className="mb-2 text-black fw-bold">{ mannequinData.name }</div>
<div className="text-black">{ LocalizeText('mannequin.widget.weartext') }</div>
</div>
<div className="btn btn-success float-end" onClick={ event => processAction('wear') }>{ LocalizeText('mannequin.widget.wear') }</div>
</div>
</> }
{ viewMode === FurnitureMannequinViewMode.CLUB && <>
<div className="text-black">{ LocalizeText('mannequin.widget.clubnotification') }</div>
</> }
{ viewMode === FurnitureMannequinViewMode.INCOMPATIBLE_GENDER && <>
<div className="text-black">{ LocalizeText('mannequin.widget.wronggender') }</div>
</> }
</div>
</div>
</NitroCardContentView>
</NitroCardView>
);
} }

View File

@ -1,6 +1,13 @@
import { FurnitureWidgetProps } from '../FurnitureWidget.types'; import { FurnitureWidgetProps } from '../FurnitureWidget.types';
export interface FurnitureMannequinViewProps extends FurnitureWidgetProps export interface FurnitureMannequinViewProps extends FurnitureWidgetProps
{ {}
export class FurnitureMannequinViewMode
{
public static readonly EDIT: string = 'edit';
public static readonly SAVE: string = 'save';
public static readonly CLUB: string = 'club';
public static readonly DEFAULT: string = 'default';
public static readonly INCOMPATIBLE_GENDER: string = 'incompatible_gender';
} }

View File

@ -1,16 +1,16 @@
import { RoomEngineObjectEvent, RoomEngineTriggerWidgetEvent } from 'nitro-renderer'; import { NitroEvent, RoomEngineTriggerWidgetEvent } from 'nitro-renderer';
import { FC } from 'react'; import { FC } from 'react';
import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event'; import { useRoomEngineEvent } from '../../../../../hooks/events/nitro/room/room-engine-event';
import { FurniturePresentViewProps } from './FurniturePresentView.types'; import { FurniturePresentViewProps } from './FurniturePresentView.types';
export const FurniturePresentView: FC<FurniturePresentViewProps> = props => export const FurniturePresentView: FC<FurniturePresentViewProps> = props =>
{ {
const onRoomEngineObjectEvent = (event: RoomEngineObjectEvent) => const onNitroEvent = (event: NitroEvent) =>
{ {
console.log(event); console.log(event);
}; };
useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_PRESENT, onRoomEngineObjectEvent); useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_PRESENT, onNitroEvent);
return null; return null;
} }

View File

@ -1,7 +1,8 @@
import { UserInfoEvent } from 'nitro-renderer/src/nitro/communication/messages/incoming/user/data/UserInfoEvent'; 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 { UserInfoDataParser } from 'nitro-renderer/src/nitro/communication/messages/parser/user/data/UserInfoDataParser';
import { useCallback, useState } from 'react'; import { FC, useCallback, useState } from 'react';
import { AvatarEditorEvent, CatalogEvent, FriendListEvent, InventoryEvent, NavigatorEvent } from '../../events'; import { AvatarEditorEvent, CatalogEvent, FriendListEvent, InventoryEvent, NavigatorEvent } from '../../events';
import { RoomWidgetCameraEvent } from '../../events/room-widgets/camera/RoomWidgetCameraEvent';
import { dispatchUiEvent } from '../../hooks/events/ui/ui-event'; import { dispatchUiEvent } from '../../hooks/events/ui/ui-event';
import { CreateMessageHook } from '../../hooks/messages/message-event'; import { CreateMessageHook } from '../../hooks/messages/message-event';
import { TransitionAnimation } from '../../transitions/TransitionAnimation'; import { TransitionAnimation } from '../../transitions/TransitionAnimation';
@ -10,7 +11,7 @@ import { AvatarImageView } from '../avatar-image/AvatarImageView';
import { ToolbarMeView } from './me/ToolbarMeView'; import { ToolbarMeView } from './me/ToolbarMeView';
import { ToolbarViewItems, ToolbarViewProps } from './ToolbarView.types'; import { ToolbarViewItems, ToolbarViewProps } from './ToolbarView.types';
export function ToolbarView(props: ToolbarViewProps): JSX.Element export const ToolbarView: FC<ToolbarViewProps> = props =>
{ {
const { isInRoom } = props; const { isInRoom } = props;
@ -44,8 +45,12 @@ export function ToolbarView(props: ToolbarViewProps): JSX.Element
case ToolbarViewItems.FRIEND_LIST_ITEM: case ToolbarViewItems.FRIEND_LIST_ITEM:
dispatchUiEvent(new CatalogEvent(FriendListEvent.TOGGLE_FRIEND_LIST)); dispatchUiEvent(new CatalogEvent(FriendListEvent.TOGGLE_FRIEND_LIST));
return; return;
case ToolbarViewItems.CAMERA_ITEM:
dispatchUiEvent(new RoomWidgetCameraEvent(RoomWidgetCameraEvent.TOGGLE_CAMERA));
return;
case ToolbarViewItems.CLOTHING_ITEM: case ToolbarViewItems.CLOTHING_ITEM:
dispatchUiEvent(new AvatarEditorEvent(AvatarEditorEvent.TOGGLE_EDITOR)); dispatchUiEvent(new AvatarEditorEvent(AvatarEditorEvent.TOGGLE_EDITOR));
setMeExpanded(false);
return; return;
} }
}, []); }, []);
@ -100,6 +105,10 @@ export function ToolbarView(props: ToolbarViewProps): JSX.Element
{ (unseenFriendListCount > 0) && ( { (unseenFriendListCount > 0) && (
<div className="position-absolute bg-danger px-1 py-0 rounded shadow count">{ unseenFriendListCount }</div>) } <div className="position-absolute bg-danger px-1 py-0 rounded shadow count">{ unseenFriendListCount }</div>) }
</div> </div>
{ isInRoom && (
<div className="navigation-item" onClick={ event => handleToolbarItemClick(ToolbarViewItems.CAMERA_ITEM) }>
<i className="icon icon-camera"></i>
</div>) }
</div> </div>
<div id="toolbar-chat-input-container" className="d-flex align-items-center" /> <div id="toolbar-chat-input-container" className="d-flex align-items-center" />
</div> </div>

View File

@ -10,4 +10,5 @@ export class ToolbarViewItems
public static CATALOG_ITEM: string = 'TVI_CATALOG_ITEM'; public static CATALOG_ITEM: string = 'TVI_CATALOG_ITEM';
public static FRIEND_LIST_ITEM: string = 'TVI_FRIEND_LIST_ITEM'; public static FRIEND_LIST_ITEM: string = 'TVI_FRIEND_LIST_ITEM';
public static CLOTHING_ITEM: string = 'TVI_CLOTHING_ITEM'; public static CLOTHING_ITEM: string = 'TVI_CLOTHING_ITEM';
public static CAMERA_ITEM: string = 'TVI_CAMERA_ITEM';
} }

View File

@ -1,9 +1,9 @@
import { MouseEventType } from 'nitro-renderer'; import { MouseEventType } from 'nitro-renderer';
import { useEffect, useRef } from 'react'; import { FC, useEffect, useRef } from 'react';
import { ToolbarViewItems } from '../ToolbarView.types'; import { ToolbarViewItems } from '../ToolbarView.types';
import { ToolbarMeViewProps } from './ToolbarMeView.types'; import { ToolbarMeViewProps } from './ToolbarMeView.types';
export function ToolbarMeView(props: ToolbarMeViewProps): JSX.Element export const ToolbarMeView: FC<ToolbarMeViewProps> = props =>
{ {
const { setMeExpanded = null, handleToolbarItemClick = null } = props; const { setMeExpanded = null, handleToolbarItemClick = null } = props;