Merge remote-tracking branch 'origin/dev' into @feature/room-tools

This commit is contained in:
MyNameIsBatman 2021-07-03 22:38:54 -03:00
commit 8fe70d4c7e
59 changed files with 1483 additions and 448 deletions

View File

@ -87,7 +87,12 @@
"roomId": 2346
}
],
"hotelview.images": {
"hotelview": {
"widgets": {
"types": "news,",
"slot1": "news"
},
"images": {
"background": "${asset.url}/images/reception/stretch_blue.png",
"background.colour": "#6eadc8",
"sun": "${asset.url}/images/reception/sun.png",
@ -95,8 +100,11 @@
"left": "${asset.url}/images/reception/ts.png",
"right": "${asset.url}/images/reception/US_right.png",
"right.repeat": "${asset.url}/images/reception/US_top_right.png"
}
},
"achievements.unseen.ignored": ["ACH_AllTimeHotelPresence"],
"achievements.unseen.ignored": [
"ACH_AllTimeHotelPresence"
],
"avatareditor.show.clubitems.dimmed": true,
"avatareditor.show.clubitems.first": true,
"chat.history.max.items": 100,

View File

@ -1,6 +0,0 @@
import { GetRoomSession } from './GetRoomSession';
export function SendChatTypingMessage(isTyping: boolean): void
{
GetRoomSession().sendChatTypingMessage(isTyping);
}

View File

@ -11,5 +11,4 @@ export * from './HasHabboClub';
export * from './HasHabboVip';
export * from './IsOwnerOfFurniture';
export * from './IsRidingHorse';
export * from './SendChatTypingMessage';
export * from './StartRoomSession';

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

View File

@ -486,6 +486,24 @@ i {
height: 15px;
}
&.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;
}

View File

@ -60,6 +60,11 @@ export const DraggableWindow: FC<DraggableWindowProps> = props =>
element.style.left = `${ left }px`;
element.style.top = `${ top }px`;
}
else
{
element.style.left = `0px`;
element.style.top = `0px`;
}
element.style.visibility = 'visible';

View File

@ -3,4 +3,3 @@
}
@import './views//friend-bar/FriendBarView';
@import './views/friend-bar-item/FriendBarItemView';

View File

@ -0,0 +1,28 @@
.friend-bar-item {
width: 130px;
margin: 0 3px;
z-index: 0;
position: relative;
padding-left:38px;
text-align: left;
&.friend-bar-item-active {
margin-bottom:21px;
}
.friend-bar-item-head {
top: -30px;
left: -30px;
pointer-events: none;
}
&.friend-bar-search {
.friend-bar-item-head {
top: -3px;
left: 5px;
width: 31px;
height: 34px;
background-image: url('../../../../assets/images/toolbar/friend-search.png');
}
}
}

View File

@ -1,18 +1,66 @@
import { FC } from 'react';
import { FollowFriendComposer, MouseEventType, Nitro } from 'nitro-renderer';
import { FC, useEffect, useRef, useState } from 'react';
import { LocalizeText } from '../../../../utils/LocalizeText';
import { AvatarImageView } from '../../../shared/avatar-image/AvatarImageView';
import { FriendBarItemViewProps } from './FriendBarItemView.types';
export const FriendBarItemView: FC<FriendBarItemViewProps> = props =>
{
const { friend = null } = props;
const [isVisible, setVisible] = useState(false);
const toggleVisible = () => setVisible(prevCheck => !prevCheck);
const elementRef = useRef<HTMLDivElement>();
useEffect(() =>
{
function onClick(event: MouseEvent): void
{
const element = elementRef.current;
if((event.target !== element) && !element.contains((event.target as Node)))
{
setVisible(false);
}
}
document.addEventListener(MouseEventType.MOUSE_CLICK, onClick);
return () =>
{
document.removeEventListener(MouseEventType.MOUSE_CLICK, onClick);
}
}, [ elementRef, setVisible ]);
const followFriend = () =>
{
Nitro.instance.communication.connection.send(new FollowFriendComposer(friend.id));
}
if(!friend)
{
return (
<div>offline</div>
<div ref={ elementRef } className="btn btn-primary friend-bar-item friend-bar-search">
<div className="friend-bar-item-head position-absolute"/>
<div className="text-truncate">{ LocalizeText("friend.bar.find.title") }</div>
</div>
);
}
return (
<div>{ friend.name }</div>
<div ref={ elementRef } className={"btn btn-success friend-bar-item " + (isVisible ? "friend-bar-item-active" : "")} onClick={ event => toggleVisible()}>
<div className="friend-bar-item-head position-absolute">
<AvatarImageView headOnly={true} figure={friend.figure} direction={2} />
</div>
<div className="text-truncate">{friend.name}</div>
{isVisible && <div className="d-flex justify-content-between">
<i className="icon icon-fb-chat cursor-pointer" />
{friend.followingAllowed && <i onClick={ event => followFriend() } className="icon icon-fb-visit cursor-pointer" />}
<i className="icon icon-fb-profile cursor-pointer" />
</div>}
</div>
);
}

View File

@ -0,0 +1,7 @@
.friend-bar {
.friend-bar-button {
z-index: 2;
}
@import '../friend-bar-item/FriendBarItemView.scss';
}

View File

@ -24,12 +24,16 @@ export const FriendBarView: FC<FriendBarViewProps> = props =>
}, [ indexOffset, friends ]);
return (
<div className="d-flex">
<button type="button" className="btn btn-sm btn-primary" disabled={ !canDecreaseIndex } onClick={ event => setIndexOffset(indexOffset - 1) }>back</button>
<div className="d-flex friend-bar align-items-center">
<button type="button" className="btn btn-sm btn-black align-self-center friend-bar-button" disabled={!canDecreaseIndex} onClick={event => setIndexOffset(indexOffset - 1)}>
<i className="fas fa-chevron-left" />
</button>
<FriendBarItemView friend={ (friends[ indexOffset ] || null) } />
<FriendBarItemView friend={ (friends[ indexOffset + 1 ] || null) } />
<FriendBarItemView friend={ (friends[ indexOffset + 2 ] || null) } />
<button type="button" className="btn btn-sm btn-primary" disabled={ !canIncreaseIndex } onClick={ event => setIndexOffset(indexOffset + 1) }>forward</button>
<button type="button" className="btn btn-sm btn-black align-self-center friend-bar-button" disabled={!canIncreaseIndex} onClick={event => setIndexOffset(indexOffset + 1)}>
<i className="fas fa-chevron-right" />
</button>
</div>
);
}

View File

@ -2,7 +2,7 @@
display: block;
position: fixed;
width: 100%;
height: 100%;
height: calc(100% - 55px);
background: rgba($black, 1);
.avatar-image {
@ -39,6 +39,7 @@
right: 0;
margin: auto;
background-repeat: no-repeat;
background-position: top center;
}
.left {
@ -61,6 +62,7 @@
animation-name: slideUp;
animation-duration: 1s;
background-repeat: no-repeat;
background-position: right bottom;
}
.right-repeat {
@ -68,9 +70,7 @@
height: 100%;
right: 0;
top: 0;
animation-iteration-count: 1;
animation-name: slideRight;
animation-duration: 1s;
background-repeat: no-repeat;
background-position: right top;
}
}

View File

@ -26,13 +26,13 @@ export const HotelView: FC<HotelViewProps> = 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 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']);
return (
<div className="nitro-hotel-view" style={ (backgroundColor && backgroundColor) ? { background: backgroundColor } : {} }>
@ -40,8 +40,8 @@ export const HotelView: FC<HotelViewProps> = props =>
<div className="sun position-absolute" style={ (sun && sun.length) ? { backgroundImage: `url(${ sun })` } : {} } />
<div className="drape position-absolute" style={ (drape && drape.length) ? { backgroundImage: `url(${ drape })` } : {} } />
<div className="left position-absolute" style={ (left && left.length) ? { backgroundImage: `url(${ left })` } : {} } />
{/* <div className="right-repeat position-absolute" style={ (rightRepeat && rightRepeat.length) ? { backgroundImage: `url(${ rightRepeat })` } : {} } />
<div className="right position-absolute" style={ (right && right.length) ? { backgroundImage: `url(${ right })` } : {} } /> */}
<div className="right-repeat position-absolute" style={ (rightRepeat && rightRepeat.length) ? { backgroundImage: `url(${ rightRepeat })` } : {} } />
<div className="right position-absolute" style={ (right && right.length) ? { backgroundImage: `url(${ right })` } : {} } />
</div>
);
}

View File

@ -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, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers';
import { IRoomWidgetHandlerManager, RoomWidgetAvatarInfoHandler, RoomWidgetChatHandler, RoomWidgetChatInputHandler, RoomWidgetHandlerManager, RoomWidgetInfostandHandler } from './handlers';
import { RoomWidgetRoomToolsHandler } from './handlers/RoomWidgetRoomToolsHandler';
import { RoomViewProps } from './RoomView.types';
import { RoomWidgetsView } from './widgets/RoomWidgetsView';
@ -37,6 +37,8 @@ export const RoomView: FC<RoomViewProps> = props =>
widgetHandlerManager.registerHandler(new RoomWidgetAvatarInfoHandler());
widgetHandlerManager.registerHandler(new RoomWidgetInfostandHandler());
widgetHandlerManager.registerHandler(new RoomWidgetRoomToolsHandler());
widgetHandlerManager.registerHandler(new RoomWidgetChatInputHandler());
widgetHandlerManager.registerHandler(new RoomWidgetChatHandler());
setWidgetHandler(widgetHandlerManager);

View File

@ -0,0 +1,20 @@
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
export class RoomWidgetFloodControlEvent extends RoomWidgetUpdateEvent
{
public static FLOOD_CONTROL: string = 'RWFCE_FLOOD_CONTROL';
private _seconds: number = 0;
constructor(seconds: number)
{
super(RoomWidgetFloodControlEvent.FLOOD_CONTROL);
this._seconds = seconds;
}
public get seconds(): number
{
return this._seconds;
}
}

View File

@ -1,41 +0,0 @@
import { NitroPoint, NitroRectangle } from 'nitro-renderer';
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
export class RoomWidgetRoomViewUpdateEvent extends RoomWidgetUpdateEvent
{
public static SIZE_CHANGED: string = 'RWRVUE_ROOM_VIEW_SIZE_CHANGED';
public static SCALE_CHANGED: string = 'RWRVUE_ROOM_VIEW_SCALE_CHANGED';
public static POSITION_CHANGED: string = 'RWRVUE_ROOM_VIEW_POSITION_CHANGED';
private _roomViewRectangle: NitroRectangle;
private _positionDelta: NitroPoint;
private _scale: number;
constructor(type: string, view: NitroRectangle = null, position: NitroPoint = null, scale: number = 0)
{
super(type);
this._roomViewRectangle = view;
this._positionDelta = position;
this._scale = scale;
}
public get roomViewRectangle(): NitroRectangle
{
if(!this._roomViewRectangle) return null;
return this._roomViewRectangle.clone();
}
public get positionDelta(): NitroPoint
{
if(!this._positionDelta) return null;
return this._positionDelta.clone();
}
public get scale(): number
{
return this._scale;
}
}

View File

@ -0,0 +1,124 @@
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
export class RoomWidgetUpdateChatEvent extends RoomWidgetUpdateEvent
{
public static CHAT_EVENT: string = 'RWUCE_CHAT_EVENT';
public static CHAT_TYPE_SPEAK: number = 0;
public static CHAT_TYPE_WHISPER: number = 1;
public static CHAT_TYPE_SHOUT: number = 2;
public static CHAT_TYPE_RESPECT: number = 3;
public static CHAT_TYPE_PETRESPECT: number = 4;
public static CHAT_TYPE_NOTIFY: number = 5;
public static CHAT_TYPE_PETTREAT: number = 6;
public static CHAT_TYPE_PETREVIVE: number = 7;
public static CHAT_TYPE_PET_REBREED_FERTILIZE: number = 8;
public static CHAT_TYPE_PET_SPEED_FERTILIZE: number = 9;
public static CHAT_TYPE_BOT_SPEAK: number = 10;
public static CHAT_TYPE_BOT_SHOUT: number = 11;
public static CHAT_TYPE_BOT_WHISPER: number = 12;
private _userId: number;
private _text: string;
private _chatType: number;
private _userName: string;
private _links: string[];
private _userX: number;
private _userY: number;
private _userImage: string;
private _userColor: number;
private _roomId: number;
private _userCategory: number;
private _userType: number;
private _petType: number;
private _styleId: number;
constructor(type: string, userId: number, text: string, userName: string, userCategory: number, userType: number, petType: number, userX: number, userY: number, userImage: string, userColor: number, roomId: number, chatType: number = 0, styleId: number = 0, links: string[] = null)
{
super(type);
this._userId = userId;
this._text = text;
this._chatType = chatType;
this._userName = userName;
this._userCategory = userCategory;
this._userType = userType;
this._petType = petType;
this._links = links;
this._userX = userX;
this._userY = userY;
this._userImage = userImage;
this._userColor = userColor;
this._roomId = roomId;
this._styleId = styleId;
}
public get userId(): number
{
return this._userId;
}
public get text(): string
{
return this._text;
}
public get chatType(): number
{
return this._chatType;
}
public get userName(): string
{
return this._userName;
}
public get userCategory(): number
{
return this._userCategory;
}
public get userType(): number
{
return this._userType;
}
public get petType(): number
{
return this._petType;
}
public get links(): string[]
{
return this._links;
}
public get userX(): number
{
return this._userX;
}
public get userY(): number
{
return this._userY;
}
public get userImage(): string
{
return this._userImage;
}
public get userColor(): number
{
return this._userColor;
}
public get roomId(): number
{
return this._roomId;
}
public get styleId(): number
{
return this._styleId;
}
}

View File

@ -0,0 +1,29 @@
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
export class RoomWidgetUpdateChatInputContentEvent extends RoomWidgetUpdateEvent
{
public static CHAT_INPUT_CONTENT: string = 'RWUCICE_CHAT_INPUT_CONTENT';
public static WHISPER: string = 'whisper';
public static SHOUT: string = 'shout';
private _chatMode: string = '';
private _userName: string = '';
constructor(chatMode: string, userName: string)
{
super(RoomWidgetUpdateChatInputContentEvent.CHAT_INPUT_CONTENT);
this._chatMode = chatMode;
this._userName = userName;
}
public get chatMode(): string
{
return this._chatMode;
}
public get userName(): string
{
return this._userName;
}
}

View File

@ -0,0 +1,62 @@
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
export class RoomWidgetUpdateRentableBotChatEvent extends RoomWidgetUpdateEvent
{
public static UPDATE_CHAT: string = 'RWURBCE_UPDATE_CHAT';
private _objectId: number;
private _category: number;
private _botId: number;
private _chat: string;
private _automaticChat: boolean;
private _chatDelay: number;
private _mixSentences: boolean;
constructor(objectId: number, category: number, botId: number, chat: string, automaticChat: boolean, chatDelay: number, mixSentences: boolean)
{
super(RoomWidgetUpdateRentableBotChatEvent.UPDATE_CHAT);
this._objectId = objectId;
this._category = category;
this._botId = botId;
this._chat = chat;
this._automaticChat = automaticChat;
this._chatDelay = chatDelay;
this._mixSentences = mixSentences;
}
public get objectId(): number
{
return this._objectId;
}
public get category(): number
{
return this._category;
}
public get botId(): number
{
return this._botId;
}
public get chat(): string
{
return this._chat;
}
public get automaticChat(): boolean
{
return this._automaticChat;
}
public get chatDelay(): number
{
return this._chatDelay;
}
public get mixSentences(): boolean
{
return this._mixSentences;
}
}

View File

@ -0,0 +1,11 @@
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
export class RoomWidgetUpdateUserDataEvent extends RoomWidgetUpdateEvent
{
public static USER_DATA_UPDATED: string = 'RWUUDE_USER_DATA_UPDATED';
constructor()
{
super(RoomWidgetUpdateUserDataEvent.USER_DATA_UPDATED);
}
}

View File

@ -1,11 +0,0 @@
import { RoomWidgetUpdateEvent } from './RoomWidgetUpdateEvent';
export class RoomWidgetUserDataUpdateEvent extends RoomWidgetUpdateEvent
{
public static USER_DATA_UPDATED: string = 'RWUDUE_USER_DATA_UPDATED';
constructor()
{
super(RoomWidgetUserDataUpdateEvent.USER_DATA_UPDATED);
}
}

View File

@ -1,8 +1,10 @@
export * from './RoomWidgetAvatarInfoEvent';
export * from './RoomWidgetFloodControlEvent';
export * from './RoomWidgetObjectNameEvent';
export * from './RoomWidgetRoomEngineUpdateEvent';
export * from './RoomWidgetRoomObjectUpdateEvent';
export * from './RoomWidgetRoomViewUpdateEvent';
export * from './RoomWidgetUpdateChatEvent';
export * from './RoomWidgetUpdateChatInputContentEvent';
export * from './RoomWidgetUpdateDanceStatusEvent';
export * from './RoomWidgetUpdateEvent';
export * from './RoomWidgetUpdateInfostandEvent';
@ -10,4 +12,5 @@ export * from './RoomWidgetUpdateInfostandFurniEvent';
export * from './RoomWidgetUpdateInfostandPetEvent';
export * from './RoomWidgetUpdateInfostandRentableBotEvent';
export * from './RoomWidgetUpdateInfostandUserEvent';
export * from './RoomWidgetUserDataUpdateEvent';
export * from './RoomWidgetUpdateRentableBotChatEvent';
export * from './RoomWidgetUpdateUserDataEvent';

View File

@ -1,13 +1,13 @@
import { IEventDispatcher, IRoomSession, NitroEvent } from 'nitro-renderer';
import { NitroEvent } from 'nitro-renderer';
import { RoomWidgetUpdateEvent } from '../events';
import { RoomWidgetMessage } from '../messages';
import { IRoomWidgetHandlerManager } from './IRoomWidgetHandlerManager';
export interface IRoomWidgetHandler
{
processEvent: (event: NitroEvent) => void;
processWidgetMessage: (message: RoomWidgetMessage) => RoomWidgetUpdateEvent;
roomSession: IRoomSession;
eventDispatcher: IEventDispatcher;
container: IRoomWidgetHandlerManager;
eventTypes: string[];
messageTypes: string[];
}

View File

@ -1,4 +1,4 @@
import { IEventDispatcher, NitroEvent } from 'nitro-renderer';
import { IEventDispatcher, IRoomSession, NitroEvent } from 'nitro-renderer';
import { RoomWidgetUpdateEvent } from '../events';
import { RoomWidgetMessage } from '../messages';
import { IRoomWidgetHandler } from './IRoomWidgetHandler';
@ -8,5 +8,6 @@ export interface IRoomWidgetHandlerManager
registerHandler(handler: IRoomWidgetHandler): void;
processEvent(event: NitroEvent): void;
processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent;
roomSession: IRoomSession;
eventDispatcher: IEventDispatcher;
}

View File

@ -1,6 +1,6 @@
import { NitroEvent, RoomSessionDanceEvent, RoomSessionUserDataUpdateEvent } from 'nitro-renderer';
import { GetRoomSession, GetSessionDataManager } from '../../../api';
import { RoomWidgetAvatarInfoEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateEvent, RoomWidgetUserDataUpdateEvent } from '../events';
import { RoomWidgetAvatarInfoEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateUserDataEvent } from '../events';
import { RoomWidgetAvatarExpressionMessage, RoomWidgetChangePostureMessage, RoomWidgetDanceMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages';
import { RoomWidgetHandler } from './RoomWidgetHandler';
@ -11,7 +11,7 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler
switch(event.type)
{
case RoomSessionUserDataUpdateEvent.USER_DATA_UPDATED:
this.eventDispatcher.dispatchEvent(new RoomWidgetUserDataUpdateEvent());
this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateUserDataEvent());
return;
case RoomSessionDanceEvent.RSDE_DANCE:
const danceEvent = (event as RoomSessionDanceEvent);
@ -22,7 +22,7 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler
if(userData && (userData.roomIndex === danceEvent.roomIndex)) isDancing = (danceEvent.danceId !== 0);
this.eventDispatcher.dispatchEvent(new RoomWidgetUpdateDanceStatusEvent(isDancing));
this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateDanceStatusEvent(isDancing));
return;
}
}
@ -68,7 +68,7 @@ export class RoomWidgetAvatarInfoHandler extends RoomWidgetHandler
const allowNameChange = GetSessionDataManager().canChangeName;
const userData = GetRoomSession().userDataManager.getUserData(userId);
if(userData) this.eventDispatcher.dispatchEvent(new RoomWidgetAvatarInfoEvent(userId, userName, userData.type, userData.roomIndex, allowNameChange));
if(userData) this.container.eventDispatcher.dispatchEvent(new RoomWidgetAvatarInfoEvent(userId, userName, userData.type, userData.roomIndex, allowNameChange));
}
public get eventTypes(): string[]

View File

@ -0,0 +1,205 @@
import { AvatarFigurePartType, AvatarScaleType, AvatarSetType, IAvatarImageListener, INitroPoint, IVector3D, NitroEvent, NitroPoint, PetFigureData, RoomObjectCategory, RoomObjectType, RoomObjectVariable, RoomSessionChatEvent, SystemChatStyleEnum, TextureUtils, Vector3d } from 'nitro-renderer';
import { GetAvatarRenderManager, GetRoomEngine } from '../../../api';
import { LocalizeText } from '../../../utils/LocalizeText';
import { RoomWidgetUpdateChatEvent, RoomWidgetUpdateEvent } from '../events';
import { RoomWidgetMessage } from '../messages';
import { RoomWidgetHandler } from './RoomWidgetHandler';
export class RoomWidgetChatHandler extends RoomWidgetHandler implements IAvatarImageListener
{
private _avatarColorCache: Map<string, number> = new Map();
private _avatarImageCache: Map<string, string> = new Map();
private _petImageCache: Map<string, string> = new Map();
public processEvent(event: NitroEvent): void
{
switch(event.type)
{
case RoomSessionChatEvent.CHAT_EVENT: {
const chatEvent = (event as RoomSessionChatEvent);
const roomObject = GetRoomEngine().getRoomObject(chatEvent.session.roomId, chatEvent.objectId, RoomObjectCategory.UNIT);
if(!roomObject) return;
const objectLocation = roomObject.getLocation();
const bubbleLocation = this.getBubbleLocation(chatEvent.session.roomId, objectLocation);
const userData = this.container.roomSession.userDataManager.getUserDataByIndex(chatEvent.objectId);
let username = '';
let avatarColor = 0;
let imageUrl: string = null;
let chatType = chatEvent.chatType;
let styleId = chatEvent.style;
let userType = 0;
let petType = -1;
let text = chatEvent.message;
if(userData)
{
userType = userData.type;
const figure = userData.figure;
switch(userType)
{
case RoomObjectType.PET:
imageUrl = this.getPetImage(figure, 2, true, 64, roomObject.model.getValue<string>(RoomObjectVariable.FIGURE_POSTURE));
petType = new PetFigureData(figure).typeId;
break;
case RoomObjectType.USER:
imageUrl = this.getUserImage(figure);
break;
case RoomObjectType.RENTABLE_BOT:
case RoomObjectType.BOT:
styleId = SystemChatStyleEnum.BOT;
break;
}
avatarColor = this._avatarColorCache.get(figure);
username = userData.name;
}
switch(chatType)
{
case RoomSessionChatEvent.CHAT_TYPE_RESPECT:
text = LocalizeText('widgets.chatbubble.respect', [ 'username' ], [ username ]);
break;
case RoomSessionChatEvent.CHAT_TYPE_PETRESPECT:
text = LocalizeText('widget.chatbubble.petrespect', [ 'petname' ], [ username ]);
break;
case RoomSessionChatEvent.CHAT_TYPE_PETTREAT:
text = LocalizeText('widget.chatbubble.pettreat', [ 'petname' ], [ username ]);
break;
case RoomSessionChatEvent.CHAT_TYPE_HAND_ITEM_RECEIVED:
text = LocalizeText('widget.chatbubble.handitem', [ 'username', 'handitem' ], [ username, LocalizeText(('handitem' + chatEvent.extraParam))]);
break;
case RoomSessionChatEvent.CHAT_TYPE_MUTE_REMAINING: {
const hours = ((chatEvent.extraParam > 0) ? Math.floor((chatEvent.extraParam / 3600)) : 0).toString();
const minutes = ((chatEvent.extraParam > 0) ? Math.floor((chatEvent.extraParam % 3600) / 60) : 0).toString();
const seconds = (chatEvent.extraParam % 60).toString();
text = LocalizeText('widget.chatbubble.mutetime', [ 'hours', 'minutes', 'seconds' ], [ hours, minutes, seconds ]);
break;
}
}
this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateChatEvent(RoomWidgetUpdateChatEvent.CHAT_EVENT, userData.roomIndex, text, username, RoomObjectCategory.UNIT, userType, petType, bubbleLocation.x, bubbleLocation.y, imageUrl, avatarColor, chatEvent.session.roomId, chatType, styleId, []));
return;
}
}
}
public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent
{
return null;
}
private getBubbleLocation(roomId: number, userLocation: IVector3D, canvasId = 1): INitroPoint
{
const geometry = GetRoomEngine().getRoomInstanceGeometry(roomId, canvasId);
const scale = GetRoomEngine().getRoomInstanceRenderingCanvasScale(roomId, canvasId);
let x = ((document.body.offsetWidth * scale) / 2);
let y = ((document.body.offsetHeight * scale) / 2);
if(geometry && userLocation)
{
const screenPoint = geometry.getScreenPoint(userLocation);
if(screenPoint)
{
x = (x + (screenPoint.x * scale));
y = (y + (screenPoint.y * scale));
const offsetPoint = GetRoomEngine().getRoomInstanceRenderingCanvasOffset(roomId, canvasId);
if(offsetPoint)
{
x = (x + offsetPoint.x);
y = (y + offsetPoint.y);
}
}
}
return new NitroPoint(x, y);
}
public getUserImage(figure: string): string
{
let existing = this._avatarImageCache.get(figure);
if(!existing)
{
existing = this.setFigureImage(figure);
}
return existing;
}
private setFigureImage(figure: string): string
{
const avatarImage = GetAvatarRenderManager().createAvatarImage(figure, AvatarScaleType.LARGE, null, this);
if(!avatarImage) return;
const image = avatarImage.getCroppedImage(AvatarSetType.HEAD);
const color = avatarImage.getPartColor(AvatarFigurePartType.CHEST);
this._avatarColorCache.set(figure, ((color && color.rgb) || 16777215));
avatarImage.dispose();
this._avatarImageCache.set(figure, image.src);
return image.src;
}
private getPetImage(figure: string, direction: number, _arg_3: boolean, scale: number = 64, posture: string = null): string
{
let existing = this._petImageCache.get((figure + posture));
if(existing) return existing;
const figureData = new PetFigureData(figure);
const typeId = figureData.typeId;
const image = GetRoomEngine().getRoomObjectPetImage(typeId, figureData.paletteId, figureData.color, new Vector3d((direction * 45)), scale, null, false, 0, figureData.customParts, posture);
if(image)
{
existing = TextureUtils.generateImageUrl(image.data);
this._petImageCache.set((figure + posture), existing);
}
return existing;
}
public resetFigure(figure: string): void
{
this.setFigureImage(figure);
}
public dispose(): void
{
}
public get disposed(): boolean
{
return false;
}
public get eventTypes(): string[]
{
return [
RoomSessionChatEvent.CHAT_EVENT
];
}
public get messageTypes(): string[]
{
return [];
}
}

View File

@ -0,0 +1,198 @@
import { AvatarExpressionEnum, HabboClubLevelEnum, NitroEvent, RoomControllerLevel, RoomSessionChatEvent, RoomSettingsComposer, RoomZoomEvent } from 'nitro-renderer';
import { GetConnection, GetRoomEngine, GetSessionDataManager } from '../../../api';
import { RoomWidgetFloodControlEvent, RoomWidgetUpdateEvent } from '../events';
import { RoomWidgetChatMessage, RoomWidgetChatSelectAvatarMessage, RoomWidgetChatTypingMessage, RoomWidgetMessage, RoomWidgetRequestWidgetMessage } from '../messages';
import { RoomWidgetHandler } from './RoomWidgetHandler';
export class RoomWidgetChatInputHandler extends RoomWidgetHandler
{
public processEvent(event: NitroEvent): void
{
switch(event.type)
{
case RoomSessionChatEvent.FLOOD_EVENT: {
const floodEvent = (event as RoomSessionChatEvent);
this.container.eventDispatcher.dispatchEvent(new RoomWidgetFloodControlEvent(parseInt(floodEvent.message)));
}
}
}
public processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent
{
switch(message.type)
{
case RoomWidgetChatTypingMessage.TYPING_STATUS: {
const typingMessage = (message as RoomWidgetChatTypingMessage);
this.container.roomSession.sendChatTypingMessage(typingMessage.isTyping);
break;
}
case RoomWidgetChatMessage.MESSAGE_CHAT: {
const chatMessage = (message as RoomWidgetChatMessage);
if(chatMessage.text === '') return null;
let text = chatMessage.text;
const parts = text.split(' ');
if(parts.length > 0)
{
const firstPart = parts[0];
let secondPart = '';
if(parts.length > 1) secondPart = parts[1];
if((firstPart.charAt(0) === ':') && (secondPart === 'x'))
{
const selectedAvatarId = GetRoomEngine().selectedAvatarId;
if(selectedAvatarId > -1)
{
const userData = this.container.roomSession.userDataManager.getUserDataByIndex(selectedAvatarId);
if(userData)
{
secondPart = userData.name;
text = chatMessage.text.replace(' x', (' ' + userData.name));
}
}
}
switch(firstPart.toLowerCase())
{
case ':d':
case ';d':
if(GetSessionDataManager().clubLevel === HabboClubLevelEnum.VIP)
{
this.container.roomSession.sendExpressionMessage(AvatarExpressionEnum.LAUGH.ordinal);
}
break;
case 'o/':
case '_o/':
this.container.roomSession.sendExpressionMessage(AvatarExpressionEnum.WAVE.ordinal);
return null;
case ':kiss':
if(GetSessionDataManager().clubLevel === HabboClubLevelEnum.VIP)
{
this.container.roomSession.sendExpressionMessage(AvatarExpressionEnum.BLOW.ordinal);
return null;
}
break;
case ':jump':
if(GetSessionDataManager().clubLevel === HabboClubLevelEnum.VIP)
{
this.container.roomSession.sendExpressionMessage(AvatarExpressionEnum.JUMP.ordinal);
return null;
}
break;
case ':idle':
this.container.roomSession.sendExpressionMessage(AvatarExpressionEnum.IDLE.ordinal);
return null;
case '_b':
this.container.roomSession.sendExpressionMessage(AvatarExpressionEnum.RESPECT.ordinal);
return null;
case ':sign':
this.container.roomSession.sendSignMessage(parseInt(secondPart));
return null;
case ':iddqd':
GetRoomEngine().events.dispatchEvent(new RoomZoomEvent(this.container.roomSession.roomId, -1, true));
return null;
case ':zoom':
GetRoomEngine().events.dispatchEvent(new RoomZoomEvent(this.container.roomSession.roomId, parseInt(secondPart), false));
return null;
case ':screenshot':
GetRoomEngine().createRoomScreenshot(this.container.roomSession.roomId, 1);
return null;
case ':pickall':
// this.container.notificationService.alertWithConfirm('${room.confirm.pick_all}', '${generic.alert.title}', () =>
// {
// GetSessionDataManager().sendSpecialCommandMessage(':pickall');
// });
return null;
case ':furni':
this.container.processWidgetMessage(new RoomWidgetRequestWidgetMessage(RoomWidgetRequestWidgetMessage.FURNI_CHOOSER));
return null;
case ':chooser':
this.container.processWidgetMessage(new RoomWidgetRequestWidgetMessage(RoomWidgetRequestWidgetMessage.USER_CHOOSER));
return null;
case ':floor':
case ':bcfloor':
if(this.container.roomSession.controllerLevel >= RoomControllerLevel.ROOM_OWNER)
{
this.container.processWidgetMessage(new RoomWidgetRequestWidgetMessage(RoomWidgetRequestWidgetMessage.FLOOR_EDITOR));
}
return null;
case ':client':
case ':nitro':
case ':billsonnn':
// this.container.notificationService.alertWithScrollableMessages([
// '<div class="d-flex flex-column justify-content-center align-items-center"><div class="nitro-info-box"></div><b>Version: ' + Nitro.RELEASE_VERSION + '</b><br />This client is powered by Nitro HTML5<br /><br /><div class="d-flex"><a class="btn btn-primary" href="https://discord.gg/66UR68FPgy" target="_blank">Discord</a><a class="btn btn-primary" href="https://git.krews.org/nitro" target="_blank">Git</a></div><br /></div>'], 'Nitro HTML5');
return null;
case ':settings':
if(this.container.roomSession.isRoomOwner || GetSessionDataManager().isModerator)
{
GetConnection().send(new RoomSettingsComposer(this.container.roomSession.roomId));
}
return null;
}
}
const styleId = chatMessage.styleId;
if(this.container && this.container.roomSession)
{
switch(chatMessage.chatType)
{
case RoomWidgetChatMessage.CHAT_DEFAULT:
this.container.roomSession.sendChatMessage(text, styleId);
break;
case RoomWidgetChatMessage.CHAT_SHOUT:
this.container.roomSession.sendShoutMessage(text, styleId);
break;
case RoomWidgetChatMessage.CHAT_WHISPER:
this.container.roomSession.sendWhisperMessage(chatMessage.recipientName, text, styleId);
break;
}
}
break;
}
}
return null;
}
public get eventTypes(): string[]
{
return [
RoomSessionChatEvent.FLOOD_EVENT
];
}
public get messageTypes(): string[]
{
return [
RoomWidgetChatTypingMessage.TYPING_STATUS,
RoomWidgetChatMessage.MESSAGE_CHAT,
RoomWidgetChatSelectAvatarMessage.MESSAGE_SELECT_AVATAR
];
}
}

View File

@ -1,35 +1,25 @@
import { IEventDispatcher, IRoomSession, NitroEvent } from 'nitro-renderer';
import { NitroEvent } from 'nitro-renderer';
import { RoomWidgetUpdateEvent } from '../events';
import { RoomWidgetMessage } from '../messages';
import { IRoomWidgetHandler } from './IRoomWidgetHandler';
import { IRoomWidgetHandlerManager } from './IRoomWidgetHandlerManager';
export abstract class RoomWidgetHandler implements IRoomWidgetHandler
{
private _roomSession: IRoomSession = null;
private _eventDispatcher: IEventDispatcher = null;
private _container: IRoomWidgetHandlerManager = null;
public abstract processEvent(event: NitroEvent): void;
public abstract processWidgetMessage(message: RoomWidgetMessage): RoomWidgetUpdateEvent;
public get roomSession(): IRoomSession
public get container(): IRoomWidgetHandlerManager
{
return this._roomSession;
return this._container;
}
public set roomSession(roomSession: IRoomSession)
public set container(container: IRoomWidgetHandlerManager)
{
this._roomSession = roomSession;
}
public get eventDispatcher(): IEventDispatcher
{
return this._eventDispatcher;
}
public set eventDispatcher(eventDispatcher: IEventDispatcher)
{
this._eventDispatcher = eventDispatcher;
this._container = container;
}
public abstract get eventTypes(): string[];

View File

@ -62,8 +62,7 @@ export class RoomWidgetHandlerManager implements IRoomWidgetHandlerManager
}
}
handler.roomSession = this._roomSession;
handler.eventDispatcher = this._eventDispatcher;
handler.container = this;
this._handlers.push(handler);
}

View File

@ -3,7 +3,7 @@ import { GetConnection, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture
import { WiredSelectObjectEvent } from '../../../events';
import { dispatchUiEvent } from '../../../hooks/events';
import { LocalizeText } from '../../../utils/LocalizeText';
import { RoomWidgetObjectNameEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events';
import { RoomWidgetObjectNameEvent, RoomWidgetUpdateChatInputContentEvent, RoomWidgetUpdateEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../events';
import { RoomWidgetChangeMottoMessage, RoomWidgetFurniActionMessage, RoomWidgetMessage, RoomWidgetRoomObjectMessage, RoomWidgetUserActionMessage } from '../messages';
import { RoomWidgetHandler } from './RoomWidgetHandler';
@ -17,7 +17,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
this.processPetInfoEvent((event as RoomSessionPetInfoUpdateEvent));
return;
case RoomSessionUserBadgesEvent.RSUBE_BADGES:
this.eventDispatcher.dispatchEvent(event);
this.container.eventDispatcher.dispatchEvent(event);
return;
}
}
@ -50,11 +50,11 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
if(petMessages.indexOf(message.type) >= 0)
{
userData = this.roomSession.userDataManager.getPetData(userId);
userData = this.container.roomSession.userDataManager.getPetData(userId);
}
else
{
userData = this.roomSession.userDataManager.getUserData(userId);
userData = this.container.roomSession.userDataManager.getUserData(userId);
}
if(!userData) return null;
@ -82,7 +82,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
GetSessionDataManager().givePetRespect(userId);
break;
case RoomWidgetUserActionMessage.WHISPER_USER:
//this.eventDispatcher.dispatchEvent(new RoomWidgetChatInputContentUpdateEvent(RoomWidgetChatInputContentUpdateEvent.WHISPER, userData.name));
this.container.eventDispatcher.dispatchEvent(new RoomWidgetUpdateChatInputContentEvent(RoomWidgetUpdateChatInputContentEvent.WHISPER, userData.name));
break;
case RoomWidgetUserActionMessage.IGNORE_USER:
GetSessionDataManager().ignoreUser(userData.name);
@ -91,27 +91,27 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
GetSessionDataManager().unignoreUser(userData.name);
break;
case RoomWidgetUserActionMessage.KICK_USER:
this.roomSession.sendKickMessage((message as RoomWidgetUserActionMessage).userId);
this.container.roomSession.sendKickMessage((message as RoomWidgetUserActionMessage).userId);
break;
case RoomWidgetUserActionMessage.BAN_USER_DAY:
case RoomWidgetUserActionMessage.BAN_USER_HOUR:
case RoomWidgetUserActionMessage.BAN_USER_PERM:
this.roomSession.sendBanMessage((message as RoomWidgetUserActionMessage).userId, message.type);
this.container.roomSession.sendBanMessage((message as RoomWidgetUserActionMessage).userId, message.type);
break;
case RoomWidgetUserActionMessage.MUTE_USER_2MIN:
this.roomSession.sendMuteMessage((message as RoomWidgetUserActionMessage).userId, 2);
this.container.roomSession.sendMuteMessage((message as RoomWidgetUserActionMessage).userId, 2);
break;
case RoomWidgetUserActionMessage.MUTE_USER_5MIN:
this.roomSession.sendMuteMessage((message as RoomWidgetUserActionMessage).userId, 5);
this.container.roomSession.sendMuteMessage((message as RoomWidgetUserActionMessage).userId, 5);
break;
case RoomWidgetUserActionMessage.MUTE_USER_10MIN:
this.roomSession.sendMuteMessage((message as RoomWidgetUserActionMessage).userId, 10);
this.container.roomSession.sendMuteMessage((message as RoomWidgetUserActionMessage).userId, 10);
break;
case RoomWidgetUserActionMessage.GIVE_RIGHTS:
this.roomSession.sendGiveRightsMessage((message as RoomWidgetUserActionMessage).userId);
this.container.roomSession.sendGiveRightsMessage((message as RoomWidgetUserActionMessage).userId);
break;
case RoomWidgetUserActionMessage.TAKE_RIGHTS:
this.roomSession.sendTakeRightsMessage((message as RoomWidgetUserActionMessage).userId);
this.container.roomSession.sendTakeRightsMessage((message as RoomWidgetUserActionMessage).userId);
break;
case RoomWidgetUserActionMessage.START_TRADING:
//if(userData) this._widget.inventoryTrading.startTrade(userData.roomIndex, userData.name);
@ -156,29 +156,29 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
GetConnection().send(new RoomUnitDropHandItemComposer());
break;
case RoomWidgetUserActionMessage.REQUEST_PET_UPDATE:
this.roomSession.userDataManager.requestPetInfo(userId);
this.container.roomSession.userDataManager.requestPetInfo(userId);
return;
case RoomWidgetUserActionMessage.REPORT:
return;
case RoomWidgetUserActionMessage.REPORT_CFH_OTHER:
return;
case RoomWidgetUserActionMessage.AMBASSADOR_ALERT_USER:
this.roomSession.sendAmbassadorAlertMessage(userId);
this.container.roomSession.sendAmbassadorAlertMessage(userId);
return;
case RoomWidgetUserActionMessage.AMBASSADOR_KICK_USER:
this.roomSession.sendKickMessage(userId);
this.container.roomSession.sendKickMessage(userId);
return;
case RoomWidgetUserActionMessage.AMBASSADOR_MUTE_USER_2MIN:
this.roomSession.sendMuteMessage(userId, 2);
this.container.roomSession.sendMuteMessage(userId, 2);
return;
case RoomWidgetUserActionMessage.AMBASSADOR_MUTE_USER_10MIN:
this.roomSession.sendMuteMessage(userId, 10);
this.container.roomSession.sendMuteMessage(userId, 10);
return;
case RoomWidgetUserActionMessage.AMBASSADOR_MUTE_USER_60MIN:
this.roomSession.sendMuteMessage(userId, 60);
this.container.roomSession.sendMuteMessage(userId, 60);
return;
case RoomWidgetUserActionMessage.AMBASSADOR_MUTE_USER_18HOUR:
this.roomSession.sendMuteMessage(userId, 1080);
this.container.roomSession.sendMuteMessage(userId, 1080);
return;
case RoomWidgetFurniActionMessage.ROTATE:
GetRoomEngine().processRoomObjectOperation(objectId, category, RoomObjectOperationType.OBJECT_ROTATE_POSITIVE);
@ -226,7 +226,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
return;
}
case RoomWidgetChangeMottoMessage.CHANGE_MOTTO:
this.roomSession.sendMottoMessage((message as RoomWidgetChangeMottoMessage).motto);
this.container.roomSession.sendMottoMessage((message as RoomWidgetChangeMottoMessage).motto);
return;
}
@ -243,7 +243,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
{
case RoomObjectCategory.FLOOR:
case RoomObjectCategory.WALL: {
const roomObject = GetRoomEngine().getRoomObject(this.roomSession.roomId, message.id, message.category);
const roomObject = GetRoomEngine().getRoomObject(this.container.roomSession.roomId, message.id, message.category);
if(!roomObject) break;
@ -275,7 +275,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
break;
}
case RoomObjectCategory.UNIT: {
const userData = this.roomSession.userDataManager.getUserDataByIndex(message.id);
const userData = this.container.roomSession.userDataManager.getUserDataByIndex(message.id);
if(!userData) break;
@ -286,14 +286,14 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
}
}
if(name) this.eventDispatcher.dispatchEvent(new RoomWidgetObjectNameEvent(message.id, message.category, id, name, userType));
if(name) this.container.eventDispatcher.dispatchEvent(new RoomWidgetObjectNameEvent(message.id, message.category, id, name, userType));
return null;
}
private processObjectInfoMessage(message: RoomWidgetRoomObjectMessage): RoomWidgetUpdateEvent
{
const roomId = this.roomSession.roomId;
const roomId = this.container.roomSession.roomId;
switch(message.category)
{
@ -302,14 +302,14 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
this.processFurniInfoMessage(message, roomId);
break;
case RoomObjectCategory.UNIT: {
const userData = this.roomSession.userDataManager.getUserDataByIndex(message.id);
const userData = this.container.roomSession.userDataManager.getUserDataByIndex(message.id);
if(!userData) break;
switch(userData.type)
{
case RoomObjectType.PET:
this.roomSession.userDataManager.requestPetInfo(userData.webID);
this.container.roomSession.userDataManager.requestPetInfo(userData.webID);
break;
case RoomObjectType.USER:
this.processUserInfoMessage(message, roomId, userData);
@ -408,8 +408,8 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
event.image = roomObjectImage.getImage();
event.isWallItem = (message.category === RoomObjectCategory.WALL);
event.isRoomOwner = this.roomSession.isRoomOwner;
event.roomControllerLevel = this.roomSession.controllerLevel;
event.isRoomOwner = this.container.roomSession.isRoomOwner;
event.roomControllerLevel = this.container.roomSession.controllerLevel;
event.isAnyRoomController = GetSessionDataManager().isModerator;
event.ownerId = model.getValue<number>(RoomObjectVariable.FURNITURE_OWNER_ID);
event.ownerName = model.getValue<string>(RoomObjectVariable.FURNITURE_OWNER_NAME);
@ -425,7 +425,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
if(IsOwnerOfFurniture(roomObject)) event.isOwner = true;
this.eventDispatcher.dispatchEvent(event);
this.container.eventDispatcher.dispatchEvent(event);
}
private processUserInfoMessage(message: RoomWidgetRoomObjectMessage, roomId: number, userData: RoomUserData): void
@ -436,7 +436,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
const event = new RoomWidgetUpdateInfostandUserEvent(eventType);
event.isSpectatorMode = this.roomSession.isSpectator;
event.isSpectatorMode = this.container.roomSession.isSpectator;
event.name = userData.name;
event.motto = userData.custom;
event.achievementScore = userData.activityPoints;
@ -454,9 +454,9 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
event.allowNameChange = GetSessionDataManager().canChangeName;
}
event.amIOwner = this.roomSession.isRoomOwner;
event.isGuildRoom = this.roomSession.isGuildRoom;
event.roomControllerLevel = this.roomSession.controllerLevel;
event.amIOwner = this.container.roomSession.isRoomOwner;
event.isGuildRoom = this.container.roomSession.isGuildRoom;
event.roomControllerLevel = this.container.roomSession.controllerLevel;
event.amIAnyRoomController = GetSessionDataManager().isModerator;
event.isAmbassador = GetSessionDataManager().isAmbassador;
@ -487,7 +487,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
event.respectLeft = GetSessionDataManager().respectsLeft;
const isShuttingDown = GetSessionDataManager().isSystemShutdown;
const tradeMode = this.roomSession.tradeMode;
const tradeMode = this.container.roomSession.tradeMode;
if(isShuttingDown)
{
@ -527,14 +527,14 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
event.groupId = parseInt(userData.guildId);
//event._Str_5235 = GetSessionDataManager()._Str_17173(int(userData._Str_4592));
event.groupName = userData.groupName;
event.badges = this.roomSession.userDataManager.getUserBadges(userData.webID);
event.badges = this.container.roomSession.userDataManager.getUserBadges(userData.webID);
event.figure = userData.figure;
//var _local_8:Array = GetSessionDataManager()._Str_18437(userData.webID);
//this._Str_16287(userData._Str_2394, _local_8);
//this._container._Str_8097._Str_14387(userData.webID);
//this._container.connection.send(new _Str_8049(userData._Str_2394));
this.eventDispatcher.dispatchEvent(event);
this.container.eventDispatcher.dispatchEvent(event);
}
private processBotInfoMessage(message: RoomWidgetRoomObjectMessage, roomId: number, userData: RoomUserData): void
@ -551,15 +551,15 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
if(roomObject) event.carryItem = (roomObject.model.getValue<number>(RoomObjectVariable.FIGURE_CARRY_OBJECT) || 0);
event.amIOwner = this.roomSession.isRoomOwner;
event.isGuildRoom = this.roomSession.isGuildRoom;
event.roomControllerLevel = this.roomSession.controllerLevel;
event.amIOwner = this.container.roomSession.isRoomOwner;
event.isGuildRoom = this.container.roomSession.isGuildRoom;
event.roomControllerLevel = this.container.roomSession.controllerLevel;
event.amIAnyRoomController = GetSessionDataManager().isModerator;
event.isAmbassador = GetSessionDataManager().isAmbassador;
event.badges = [ RoomWidgetUpdateInfostandUserEvent.DEFAULT_BOT_BADGE_ID ];
event.figure = userData.figure;
this.eventDispatcher.dispatchEvent(event);
this.container.eventDispatcher.dispatchEvent(event);
}
private processRentableBotInfoMessage(message: RoomWidgetRoomObjectMessage, roomId: number, userData: RoomUserData): void
@ -578,13 +578,13 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
if(roomObject) event.carryItem = (roomObject.model.getValue<number>(RoomObjectVariable.FIGURE_CARRY_OBJECT) || 0);
event.amIOwner = this.roomSession.isRoomOwner;
event.roomControllerLevel = this.roomSession.controllerLevel;
event.amIOwner = this.container.roomSession.isRoomOwner;
event.roomControllerLevel = this.container.roomSession.controllerLevel;
event.amIAnyRoomController = GetSessionDataManager().isModerator;
event.badges = [ RoomWidgetUpdateInfostandUserEvent.DEFAULT_BOT_BADGE_ID ];
event.figure = userData.figure;
this.eventDispatcher.dispatchEvent(event);
this.container.eventDispatcher.dispatchEvent(event);
}
private processPetInfoEvent(event: RoomSessionPetInfoUpdateEvent): void
@ -593,7 +593,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
if(!petData) return;
const roomPetData = this.roomSession.userDataManager.getPetData(petData.id);
const roomPetData = this.container.roomSession.userDataManager.getPetData(petData.id);
if(!roomPetData) return;
@ -652,10 +652,10 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
}
else
{
if(this.roomSession.isRoomOwner || GetSessionDataManager().isModerator || (this.roomSession.controllerLevel >= RoomControllerLevel.GUEST)) infostandEvent.canRemovePet = true;
if(this.container.roomSession.isRoomOwner || GetSessionDataManager().isModerator || (this.container.roomSession.controllerLevel >= RoomControllerLevel.GUEST)) infostandEvent.canRemovePet = true;
}
this.eventDispatcher.dispatchEvent(infostandEvent);
this.container.eventDispatcher.dispatchEvent(infostandEvent);
}
private checkGuildSetting(event: RoomWidgetUpdateInfostandUserEvent): boolean
@ -717,9 +717,9 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
private isValidSetting(event: RoomWidgetUpdateInfostandUserEvent, checkSetting: (event: RoomWidgetUpdateInfostandUserEvent, moderation: RoomModerationSettings) => boolean): boolean
{
if(!this.roomSession._Str_7411) return false;
if(!this.container.roomSession._Str_7411) return false;
const moderation = this.roomSession.moderationSettings;
const moderation = this.container.roomSession.moderationSettings;
let flag = false;

View File

@ -1,6 +1,8 @@
export * from './IRoomWidgetHandler';
export * from './IRoomWidgetHandlerManager';
export * from './RoomWidgetAvatarInfoHandler';
export * from './RoomWidgetChatHandler';
export * from './RoomWidgetChatInputHandler';
export * from './RoomWidgetHandler';
export * from './RoomWidgetHandlerManager';
export * from './RoomWidgetInfostandHandler';

View File

@ -0,0 +1,44 @@
import { RoomWidgetMessage } from './RoomWidgetMessage';
export class RoomWidgetChatMessage extends RoomWidgetMessage
{
public static MESSAGE_CHAT: string = 'RWCM_MESSAGE_CHAT';
public static CHAT_DEFAULT: number = 0;
public static CHAT_WHISPER: number = 1;
public static CHAT_SHOUT: number = 2;
private _chatType: number;
private _text: string;
private _recipientName: string;
private _styleId: number;
constructor(type: string, text: string, chatType: number, recipientName: string, styleId: number)
{
super(type);
this._text = text;
this._chatType = chatType;
this._recipientName = recipientName;
this._styleId = styleId;
}
public get text(): string
{
return this._text;
}
public get chatType(): number
{
return this._chatType;
}
public get recipientName(): string
{
return this._recipientName;
}
public get styleId(): number
{
return this._styleId;
}
}

View File

@ -0,0 +1,34 @@
import { RoomWidgetMessage } from './RoomWidgetMessage';
export class RoomWidgetChatSelectAvatarMessage extends RoomWidgetMessage
{
public static MESSAGE_SELECT_AVATAR: string = 'RWCSAM_MESSAGE_SELECT_AVATAR';
private _objectId: number;
private _userName: string;
private _roomId: number;
constructor(type: string, objectId: number, userName: string, roomId: number)
{
super(type);
this._objectId = objectId;
this._userName = userName;
this._roomId = roomId;
}
public get objectId(): number
{
return this._objectId;
}
public get userName(): string
{
return this._userName;
}
public get roomId(): number
{
return this._roomId;
}
}

View File

@ -0,0 +1,20 @@
import { RoomWidgetMessage } from './RoomWidgetMessage';
export class RoomWidgetChatTypingMessage extends RoomWidgetMessage
{
public static TYPING_STATUS: string = 'RWCTM_TYPING_STATUS';
private _isTyping: boolean;
constructor(isTyping: boolean)
{
super(RoomWidgetChatTypingMessage.TYPING_STATUS);
this._isTyping = isTyping;
}
public get isTyping(): boolean
{
return this._isTyping;
}
}

View File

@ -0,0 +1,10 @@
import { RoomWidgetMessage } from './RoomWidgetMessage';
export class RoomWidgetRequestWidgetMessage extends RoomWidgetMessage
{
public static USER_CHOOSER: string = 'RWRWM_USER_CHOOSER';
public static FURNI_CHOOSER: string = 'RWRWM_FURNI_CHOOSER';
public static ME_MENU: string = 'RWRWM_ME_MENU';
public static EFFECTS: string = 'RWRWM_EFFECTS';
public static FLOOR_EDITOR: string = 'RWRWM_FLOOR_EDITOR';
}

View File

@ -1,9 +1,13 @@
export * from './RoomWidgetAvatarExpressionMessage';
export * from './RoomWidgetChangeMottoMessage';
export * from './RoomWidgetChangePostureMessage';
export * from './RoomWidgetChatMessage';
export * from './RoomWidgetChatSelectAvatarMessage';
export * from './RoomWidgetChatTypingMessage';
export * from './RoomWidgetDanceMessage';
export * from './RoomWidgetFurniActionMessage';
export * from './RoomWidgetMessage';
export * from './RoomWidgetRequestWidgetMessage';
export * from './RoomWidgetRoomObjectMessage';
export * from './RoomWidgetUserActionMessage';
export * from './RoomWidgetZoomToggleMessage';

View File

@ -3,7 +3,7 @@ import { FC, useCallback, useMemo, useState } from 'react';
import { GetRoomSession, GetSessionDataManager } from '../../../../api';
import { CreateEventDispatcherHook } from '../../../../hooks/events/event-dispatcher.base';
import { useRoomContext } from '../../context/RoomContext';
import { RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent } from '../../events';
import { RoomWidgetObjectNameEvent, RoomWidgetRoomEngineUpdateEvent, RoomWidgetRoomObjectUpdateEvent, RoomWidgetUpdateDanceStatusEvent, RoomWidgetUpdateInfostandEvent, RoomWidgetUpdateInfostandFurniEvent, RoomWidgetUpdateInfostandPetEvent, RoomWidgetUpdateInfostandRentableBotEvent, RoomWidgetUpdateInfostandUserEvent, RoomWidgetUpdateRentableBotChatEvent } from '../../events';
import { RoomWidgetRoomObjectMessage } from '../../messages';
import { AvatarInfoWidgetViewProps } from './AvatarInfoWidgetView.types';
import { AvatarInfoWidgetAvatarView } from './views/avatar/AvatarInfoWidgetAvatarView';
@ -12,6 +12,7 @@ import { AvatarInfoWidgetNameView } from './views/name/AvatarInfoWidgetNameView'
import { AvatarInfoWidgetOwnAvatarView } from './views/own-avatar/AvatarInfoWidgetOwnAvatarView';
import { AvatarInfoWidgetOwnPetView } from './views/own-pet/AvatarInfoWidgetOwnPetView';
import { AvatarInfoWidgetPetView } from './views/pet/AvatarInfoWidgetPetView';
import { AvatarInfoRentableBotChatView } from './views/rentable-bot-chat/AvatarInfoRentableBotChatView';
import { AvatarInfoWidgetRentableBotView } from './views/rentable-bot/AvatarInfoWidgetRentableBotView';
export const AvatarInfoWidgetView: FC<AvatarInfoWidgetViewProps> = props =>
@ -22,6 +23,7 @@ export const AvatarInfoWidgetView: FC<AvatarInfoWidgetViewProps> = props =>
const [ isGameMode, setGameMode ] = useState(false);
const [ isDancing, setIsDancing ] = useState(false);
const [ isDecorating, setIsDecorating ] = useState(GetRoomSession().isDecorating);
const [ rentableBotChatEvent, setRentableBotChatEvent ] = useState<RoomWidgetUpdateRentableBotChatEvent>(null);
const onRoomWidgetRoomEngineUpdateEvent = useCallback((event: RoomWidgetRoomEngineUpdateEvent) =>
{
@ -160,6 +162,13 @@ export const AvatarInfoWidgetView: FC<AvatarInfoWidgetViewProps> = props =>
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.USER_ADDED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent);
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_SELECTED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent);
const onRoomWidgetUpdateRentableBotChatEvent = useCallback((event: RoomWidgetUpdateRentableBotChatEvent) =>
{
setRentableBotChatEvent(event);
}, []);
CreateEventDispatcherHook(RoomWidgetUpdateRentableBotChatEvent.UPDATE_CHAT, eventDispatcher, onRoomWidgetUpdateRentableBotChatEvent);
const decorateView = useMemo(() =>
{
GetRoomSession().isDecorating = isDecorating;
@ -237,6 +246,7 @@ export const AvatarInfoWidgetView: FC<AvatarInfoWidgetViewProps> = props =>
return (
<>
{ currentView }
{ rentableBotChatEvent && <AvatarInfoRentableBotChatView chatEvent={ rentableBotChatEvent } /> }
</>
)
}

View File

@ -0,0 +1,19 @@
import { FC } from 'react';
import { DraggableWindow } from '../../../../../../layout';
import { ObjectLocationView } from '../../../object-location/ObjectLocationView';
import { AvatarInfoRentableBotChatViewProps } from './AvatarInfoRentableBotChatView.types';
export const AvatarInfoRentableBotChatView: FC<AvatarInfoRentableBotChatViewProps> = props =>
{
const { chatEvent = null } = props;
return (
<DraggableWindow noCenter={ true } handle=".drag-handler">
<ObjectLocationView objectId={ chatEvent.objectId } category={ chatEvent.category } noFollow={ true }>
<div className="nitro-context-menu">
<div className="drag-handler">test!!!!!</div>
</div>
</ObjectLocationView>
</DraggableWindow>
);
}

View File

@ -0,0 +1,6 @@
import { RoomWidgetUpdateRentableBotChatEvent } from '../../../../events';
export interface AvatarInfoRentableBotChatViewProps
{
chatEvent: RoomWidgetUpdateRentableBotChatEvent;
}

View File

@ -1,19 +1,19 @@
import { BotCommandConfigurationEvent, BotRemoveComposer, BotSkillSaveComposer, Nitro, RequestBotCommandConfigurationComposer, RoomObjectCategory } from 'nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { FC, useCallback, useEffect, useState } from 'react';
import { GetConnection } from '../../../../../../api';
import { CreateMessageHook } from '../../../../../../hooks/messages';
import { LocalizeText } from '../../../../../../utils/LocalizeText';
import { useRoomContext } from '../../../../context/RoomContext';
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 { AvatarInfoWidgetRentableBotViewProps, BotChatOptions } from './AvatarInfoWidgetRentableBotView.types';
import { AvatarInfoWidgetRentableBotViewProps } from './AvatarInfoWidgetRentableBotView.types';
const MODE_NORMAL = 0;
const MODE_CHANGE_NAME = 1;
const MODE_CHANGE_MOTTO = 2;
const MODE_CHANGE_SPEECH = 3;
export const AvatarInfoWidgetRentableBotView: FC<AvatarInfoWidgetRentableBotViewProps> = props =>
{
@ -21,9 +21,12 @@ export const AvatarInfoWidgetRentableBotView: FC<AvatarInfoWidgetRentableBotView
const [ mode, setMode ] = useState(MODE_NORMAL);
const [ newName, setNewName ] = useState('');
const [ newMotto, setNewMotto ] = useState('');
const [ newChat, setNewChat ] = useState('');
const [ chatOptions, setChatOptions ] = useState<BotChatOptions>({ automaticChat: false, chatDelay: 0, mixSentences: false });
const { widgetHandler = null } = useRoomContext();
const { eventDispatcher = null } = useRoomContext();
useEffect(() =>
{
setMode(MODE_NORMAL);
}, [ rentableBotData ]);
const onBotCommandConfigurationEvent = useCallback((event: BotCommandConfigurationEvent) =>
{
@ -49,20 +52,22 @@ export const AvatarInfoWidgetRentableBotView: FC<AvatarInfoWidgetRentableBotView
if((pieces.length === 3) || (pieces.length === 4))
{
setNewChat(pieces[0]);
setChatOptions({
automaticChat: ((pieces[1].toLowerCase() === 'true') || (pieces[1] === '1')),
chatDelay: parseInt(pieces[2]),
mixSentences: ((pieces[3]) ? ((pieces[3].toLowerCase() === 'true') || (pieces[3] === '1')) : false)
});
}
eventDispatcher.dispatchEvent(new RoomWidgetUpdateRentableBotChatEvent(
rentableBotData.roomIndex,
RoomObjectCategory.UNIT,
rentableBotData.webID,
pieces[0],
((pieces[1].toLowerCase() === 'true') || (pieces[1] === '1')),
parseInt(pieces[2]),
((pieces[3]) ? ((pieces[3].toLowerCase() === 'true') || (pieces[3] === '1')) : false)));
setMode(MODE_CHANGE_SPEECH);
close();
}
return;
}
}
}, [ rentableBotData ]);
}, [ rentableBotData, eventDispatcher, close ]);
CreateMessageHook(BotCommandConfigurationEvent, onBotCommandConfigurationEvent);
@ -176,14 +181,23 @@ export const AvatarInfoWidgetRentableBotView: FC<AvatarInfoWidgetRentableBotView
</ContextMenuListItemView> }
</> }
{ (mode === MODE_CHANGE_NAME) &&
<ContextMenuListItemView className="flex-column" onClick={ null }>
<div className="d-flex flex-column menu-item" onClick={ null }>
<p className="mb-1">{ LocalizeText('bot.skill.name.configuration.new.name') }</p>
<input type="text" className="form-control form-control-sm mb-2" value={ newName } onChange={ event => setNewName(event.target.value) } />
<div className="d-flex justify-content-between align-items-center">
<button type="button" className="btn btn-secondary btn-sm" onClick={ event => processAction(null) }>{ LocalizeText('cancel') }</button>
<button type="button" className="btn btn-success btn-sm" onClick={ event => processAction('save_bot_name') }>{ LocalizeText('save') }</button>
</div>
</ContextMenuListItemView> }
</div> }
{ (mode === MODE_CHANGE_MOTTO) &&
<div className="d-flex flex-column menu-item" onClick={ null }>
<p className="mb-1">{ LocalizeText('bot.skill.name.configuration.new.motto') }</p>
<input type="text" className="form-control form-control-sm mb-2" value={ newMotto } onChange={ event => setNewMotto(event.target.value) } />
<div className="d-flex justify-content-between align-items-center">
<button type="button" className="btn btn-secondary btn-sm" onClick={ event => processAction(null) }>{ LocalizeText('cancel') }</button>
<button type="button" className="btn btn-success btn-sm" onClick={ event => processAction('save_bot_motto') }>{ LocalizeText('save') }</button>
</div>
</div> }
</ContextMenuView>
);
}

View File

@ -4,60 +4,22 @@
left: 50%;
transform: translateX(-50%);
bottom: 65px !important;
}
}
.nitro-chat-input {
pointer-events: none;
z-index: $chatinput-zindex;
}
}
.chatinput-container {
.nitro-chat-input-container {
display: flex;
justify-content: center;
align-items: center;
position: relative;
height: 40px;
border-radius: 8px;
border: 2px solid rgb(0, 0, 0);
background: #EDEDED;
pointer-events: all;
padding-right: 30px;
width: 100%;
.input-sizer {
display: inline-grid;
vertical-align: top;
align-items: center;
position: relative;
height: 100%;
padding: 0 10px;
&::after,
input,
textarea {
width: auto;
min-width: 1em;
grid-area: 1 / 2;
margin: 0;
resize: none;
background: none;
appearance: none;
border: none;
}
&::after {
content: attr(data-value) ' ';
visibility: hidden;
white-space: pre-wrap;
}
}
.chat-input {
height: 100%;
font-size: 16px;
outline: 0;
border: 0;
position: relative;
background: transparent;
}
&:before {
content: "";
position: absolute;
@ -71,5 +33,33 @@
background: rgb(255, 255, 255);
z-index: 1;
}
.input-sizer {
display: inline-grid;
vertical-align: top;
height: 100%;
padding: 0 10px;
&::after,
input,
textarea {
width: auto;
min-width: 1em;
grid-area: 1 / 2;
margin: 0;
resize: none;
background: none;
appearance: none;
border: none;
outline: none;
}
&::after {
content: attr(data-value) ' ';
visibility: hidden;
white-space: pre-wrap;
}
}
}
@import './style-selector/ChatInputStyleSelectorView';

View File

@ -1,18 +1,24 @@
import { FC, MouseEvent, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { createPortal } from 'react-dom';
import { GetConfiguration, GetRoomSession, SendChatTypingMessage } from '../../../../api';
import { GetConfiguration, GetSessionDataManager } from '../../../../api';
import { CreateEventDispatcherHook } from '../../../../hooks/events';
import { LocalizeText } from '../../../../utils/LocalizeText';
import { useRoomContext } from '../../context/RoomContext';
import { ChatInputMessageType, ChatInputViewProps } from './ChatInputView.types';
let lastContent = '';
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<ChatInputViewProps> = props =>
{
const { eventDispatcher = null, widgetHandler = null } = useRoomContext();
const [ chatValue, setChatValue ] = useState<string>('');
const [ selectedUsername, setSelectedUsername ] = useState('');
const [ isTyping, setIsTyping ] = useState(false);
const [ typingStartedSent, setTypingStartedSent ] = useState(false);
const [ isIdle, setIsIdle ] = useState(false);
const [ chatStyleId, setChatStyleId ] = useState(GetSessionDataManager().chatStyle);
const [ needsChatStyleUpdate, setNeedsChatStyleUpdate ] = useState(false);
const { eventDispatcher = null, widgetHandler = null } = useRoomContext();
const inputRef = useRef<HTMLInputElement>();
const chatModeIdWhisper = useMemo(() =>
@ -59,35 +65,24 @@ export const ChatInputView: FC<ChatInputViewProps> = props =>
{
setChatValue(prevValue =>
{
if((prevValue !== LocalizeText('widgets.chatinput.mode.whisper')) || !selectedUsername.length) return prevValue;
if((prevValue !== chatModeIdWhisper) || !selectedUsername.length) return prevValue;
return (`${ prevValue } ${ selectedUsername }`);
});
}, [ selectedUsername ]);
}, [ selectedUsername, chatModeIdWhisper ]);
const sendChat = useCallback((text: string, chatType: number, recipientName: string = '', styleId: number = 0) =>
{
setChatValue('');
switch(chatType)
{
case ChatInputMessageType.CHAT_DEFAULT:
GetRoomSession().sendChatMessage(text, styleId);
return;
case ChatInputMessageType.CHAT_WHISPER:
GetRoomSession().sendWhisperMessage(recipientName, text, styleId);
return;
case ChatInputMessageType.CHAT_SHOUT:
GetRoomSession().sendShoutMessage(text, styleId);
return;
}
}, []);
widgetHandler.processWidgetMessage(new RoomWidgetChatMessage(RoomWidgetChatMessage.MESSAGE_CHAT, text, chatType, recipientName, styleId));
}, [ widgetHandler ]);
const sendChatValue = useCallback((value: string, shiftKey: boolean = false) =>
{
if(!value || (value === '')) return;
let chatType = (shiftKey ? ChatInputMessageType.CHAT_SHOUT : ChatInputMessageType.CHAT_DEFAULT);
let chatType = (shiftKey ? RoomWidgetChatMessage.CHAT_SHOUT : RoomWidgetChatMessage.CHAT_DEFAULT);
let text = value;
const parts = text.split(' ');
@ -98,7 +93,7 @@ export const ChatInputView: FC<ChatInputViewProps> = props =>
switch(parts[0])
{
case chatModeIdWhisper:
chatType = ChatInputMessageType.CHAT_WHISPER;
chatType = RoomWidgetChatMessage.CHAT_WHISPER;
recipientName = parts[1];
append = (chatModeIdWhisper + ' ' + recipientName + ' ');
@ -106,12 +101,12 @@ export const ChatInputView: FC<ChatInputViewProps> = props =>
parts.shift();
break;
case chatModeIdShout:
chatType = ChatInputMessageType.CHAT_SHOUT;
chatType = RoomWidgetChatMessage.CHAT_SHOUT;
parts.shift();
break;
case chatModeIdSpeak:
chatType = ChatInputMessageType.CHAT_DEFAULT;
chatType = RoomWidgetChatMessage.CHAT_DEFAULT;
parts.shift();
break;
@ -119,20 +114,38 @@ export const ChatInputView: FC<ChatInputViewProps> = props =>
text = parts.join(' ');
setIsTyping(false);
setIsIdle(false);
if(text.length <= maxChatLength)
{
// if(this.needsStyleUpdate)
// {
// Nitro.instance.sessionDataManager.sendChatStyleUpdate(this.currentStyle);
if(needsChatStyleUpdate)
{
GetSessionDataManager().sendChatStyleUpdate(chatStyleId);
// this.needsStyleUpdate = false;
// }
let currentStyle = 1;
sendChat(text, chatType, recipientName, currentStyle);
setNeedsChatStyleUpdate(false);
}
}, [ chatModeIdWhisper, chatModeIdShout, chatModeIdSpeak, maxChatLength, sendChat ]);
sendChat(text, chatType, recipientName, chatStyleId);
}
setChatValue(append);
}, [ chatModeIdWhisper, chatModeIdShout, chatModeIdSpeak, maxChatLength, chatStyleId, needsChatStyleUpdate, sendChat ]);
const updateChatInput = useCallback((value: string) =>
{
if(!value || !value.length)
{
setIsTyping(false);
}
else
{
setIsTyping(true);
setIsIdle(true);
}
setChatValue(value);
}, []);
const onKeyDownEvent = useCallback((event: KeyboardEvent) =>
{
@ -140,24 +153,106 @@ export const ChatInputView: FC<ChatInputViewProps> = props =>
if(document.activeElement !== inputRef.current) setInputFocus();
switch(event.key)
const value = (event.target as HTMLInputElement).value;
switch(event.code)
{
case 'Space':
checkSpecialKeywordForInput();
return;
case 'NumpadEnter':
case 'Enter':
sendChatValue((event.target as HTMLInputElement).value, event.shiftKey);
sendChatValue(value, event.shiftKey);
return;
case 'Backspace':
if(value)
{
const parts = value.split(' ');
if((parts[0] === chatModeIdWhisper) && (parts.length === 3) && (parts[2] === ''))
{
setChatValue('');
}
}
return;
}
}, [ inputRef, anotherInputHasFocus, setInputFocus, checkSpecialKeywordForInput, sendChatValue ]);
}, [ inputRef, chatModeIdWhisper, anotherInputHasFocus, setInputFocus, checkSpecialKeywordForInput, sendChatValue ]);
const onInputMouseDownEvent = useCallback((event: MouseEvent<HTMLInputElement>) =>
const onStyleSelected = useCallback((styleId: number) =>
{
setInputFocus();
}, [ setInputFocus ]);
setChatStyleId(styleId);
setNeedsChatStyleUpdate(true);
}, []);
const onRoomWidgetRoomObjectUpdateEvent = useCallback((event: RoomWidgetRoomObjectUpdateEvent) =>
{
setSelectedUsername('');
}, []);
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.OBJECT_DESELECTED, eventDispatcher, onRoomWidgetRoomObjectUpdateEvent);
const onRoomWidgetUpdateInfostandUserEvent = useCallback((event: RoomWidgetUpdateInfostandUserEvent) =>
{
setSelectedUsername(event.name);
}, []);
CreateEventDispatcherHook(RoomWidgetUpdateInfostandUserEvent.PEER, eventDispatcher, onRoomWidgetUpdateInfostandUserEvent);
const onRoomWidgetChatInputContentUpdateEvent = useCallback((event: RoomWidgetUpdateChatInputContentEvent) =>
{
switch(event.chatMode)
{
case RoomWidgetUpdateChatInputContentEvent.WHISPER: {
setChatValue(`${ chatModeIdWhisper } ${ event.userName } `);
return;
}
case RoomWidgetUpdateChatInputContentEvent.SHOUT:
return;
}
}, [ chatModeIdWhisper ]);
CreateEventDispatcherHook(RoomWidgetUpdateChatInputContentEvent.CHAT_INPUT_CONTENT, eventDispatcher, onRoomWidgetChatInputContentUpdateEvent);
useEffect(() =>
{
if(isTyping)
{
if(!typingStartedSent)
{
setTypingStartedSent(true);
widgetHandler.processWidgetMessage(new RoomWidgetChatTypingMessage(isTyping));
}
}
else
{
if(typingStartedSent)
{
setTypingStartedSent(false);
widgetHandler.processWidgetMessage(new RoomWidgetChatTypingMessage(isTyping));
}
}
}, [ widgetHandler, isTyping, typingStartedSent ]);
useEffect(() =>
{
if(!isIdle) return;
let timeout: ReturnType<typeof setTimeout> = null;
if(isIdle)
{
timeout = setTimeout(() =>
{
setIsIdle(false);
setIsTyping(false)
}, 10000);
}
return () => clearTimeout(timeout);
}, [ isIdle ]);
useEffect(() =>
{
@ -169,59 +264,13 @@ export const ChatInputView: FC<ChatInputViewProps> = props =>
}
}, [ onKeyDownEvent ]);
useEffect(() =>
{
let idleTimer: ReturnType<typeof setTimeout> = null;
if(!chatValue || !chatValue.length)
{
setIsTyping(prevValue =>
{
if(!prevValue) return prevValue;
if(prevValue) SendChatTypingMessage(false);
return false;
});
}
else
{
setIsTyping(prevValue =>
{
if(prevValue) return prevValue;
if(!prevValue) SendChatTypingMessage(true);
return true;
});
lastContent = chatValue;
idleTimer = setTimeout(() =>
{
setIsTyping(prevValue =>
{
if(prevValue) SendChatTypingMessage(false);
return false;
});
}, 3000);
}
return () =>
{
if(idleTimer) clearTimeout(idleTimer);
}
}, [ chatValue ]);
return (
createPortal(
<div className="nitro-chat-input">
<div className="chatinput-container">
<div className="nitro-chat-input-container">
<div className="input-sizer">
<input ref={ inputRef } type="text" className="chat-input" placeholder={ LocalizeText('widgets.chatinput.default') } value={ chatValue } maxLength={ maxChatLength } onChange={ event => { event.target.parentElement.dataset.value = event.target.value; setChatValue(event.target.value) } } onMouseDown={ onInputMouseDownEvent } />
</div>
<input ref={ inputRef } type="text" className="chat-input" placeholder={ LocalizeText('widgets.chatinput.default') } value={ chatValue } maxLength={ maxChatLength } onChange={ event => { event.target.parentElement.dataset.value = event.target.value; updateChatInput(event.target.value) } } onMouseDown={ event => setInputFocus() } />
</div>
<ChatInputStyleSelectorView onStyleSelected={ onStyleSelected } />
</div>, document.getElementById('toolbar-chat-input-container'))
);
}

View File

@ -4,10 +4,3 @@ export interface ChatInputViewProps extends RoomWidgetProps
{
}
export class ChatInputMessageType
{
public static CHAT_DEFAULT: number = 0;
public static CHAT_WHISPER: number = 1;
public static CHAT_SHOUT: number = 2;
}

View File

@ -0,0 +1,61 @@
.nitro-chat-style-selector-button {
position: absolute;
display: flex;
justify-content: center;
align-items: center;
height: 100%;
right: 7px;
}
.nitro-chat-style-selector-test {
display: flex;
position: relative;
right: 30px;
pointer-events: all;
height: 100%;
i.icon {
cursor: pointer;
align-self: center;
}
.nitro-chatstyle-selector {
position: absolute;
width: 250px;
top: -4px;
transition: transform 0.22s ease-in-out;
transform: translate(-81px, -50%) scale(0);
&.active {
visibility: visible;
transform: translate(-160px, -100%) scale(1);
}
.grid-container {
.grid-items {
margin-top: -7px;
.item-detail {
height: 30px;
max-height: 30px;
width: calc(1 / 3 * 100% - (1 - 1 / 3) * 7px);
margin: 7px 7px 0 0;
overflow: visible;
&:hover {
cursor: pointer;
}
.detail-info {
.bubble-container {
visibility: visible;
width: 75%;
}
}
}
}
}
}
}

View File

@ -0,0 +1,20 @@
import { FC, useState } from 'react';
import { ChatInputStyleSelectorViewProps } from './ChatInputStyleSelectorView.types';
export const ChatInputStyleSelectorView: FC<ChatInputStyleSelectorViewProps> = props =>
{
const { onStyleSelected = null } = props;
const [ selectorVisible, setSelectorVisible ] = useState(false);
return (
<>
<div className="nitro-chat-style-selector-button">
<i className="icon chatstyles-icon" />
</div>
{ selectorVisible &&
<div className="nitro-chat-style-selector-container">
</div> }
</>
)
}

View File

@ -0,0 +1,4 @@
export interface ChatInputStyleSelectorViewProps
{
onStyleSelected: (styleId: number) => void;
}

View File

@ -1,36 +1,25 @@
import { RoomDragEvent, RoomObjectCategory, RoomSessionChatEvent } from 'nitro-renderer';
import { NitroPoint, RoomDragEvent } from 'nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { GetRoomEngine, GetRoomSession } from '../../../../api';
import { useRoomEngineEvent } from '../../../../hooks/events';
import { useRoomSessionManagerEvent } from '../../../../hooks/events/nitro/session/room-session-manager-event';
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';
import { GetBubbleLocation } from './utils/ChatWidgetUtilities';
export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
{
const [ chatMessages, setChatMessages ] = useState<ChatBubbleMessage[]>([]);
const { roomSession = null } = useRoomContext();
const { roomSession = null, eventDispatcher = null } = useRoomContext();
const elementRef = useRef<HTMLDivElement>();
const removeFirstHiddenChat = useCallback(() =>
const removeHiddenChats = useCallback(() =>
{
if(!chatMessages.length) return;
const lastChat = chatMessages[0];
const newMessages = chatMessages.filter(chat => ((chat.top > (-(chat.height) * 2))));
if((lastChat.top > (-(lastChat.height) * 2))) return;
setChatMessages(prevValue =>
{
const newMessages = [ ...prevValue ];
newMessages.shift();
return newMessages;
});
if(newMessages.length !== chatMessages.length) setChatMessages(newMessages);
}, [ chatMessages ]);
const moveChatUp = useCallback((chat: ChatBubbleMessage, amount: number) =>
@ -42,8 +31,8 @@ export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
{
chatMessages.forEach(chat => moveChatUp(chat, amount));
removeFirstHiddenChat();
}, [ chatMessages, moveChatUp, removeFirstHiddenChat ]);
removeHiddenChats();
}, [ chatMessages, moveChatUp, removeHiddenChats ]);
const makeRoom = useCallback((chat: ChatBubbleMessage) =>
{
@ -72,65 +61,21 @@ export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
});
}, []);
const onRoomSessionChatEvent = useCallback((event: RoomSessionChatEvent) =>
const onRoomWidgetUpdateChatEvent = useCallback((event: RoomWidgetUpdateChatEvent) =>
{
const roomObject = GetRoomEngine().getRoomObject(event.session.roomId, event.objectId, RoomObjectCategory.UNIT);
if(!roomObject) return;
const canvasId = 1;
const objectLocation = roomObject.getLocation();
const bubbleLocation = GetBubbleLocation(event.session.roomId, objectLocation, canvasId);
const userData = GetRoomSession().userDataManager.getUserDataByIndex(event.objectId);
let username = '';
let avatarColor = '';
let imageUrl: string = null;
let chatType = event.chatType;
let styleId = event.style;
let userType = 0;
let petType = -1;
let text = event.message;
if(userData)
{
userType = userData.type;
const figure = userData.figure;
// switch(userType)
// {
// case RoomObjectType.PET:
// image = this.getPetImage(figure, 2, true, 64, roomObject.model.getValue<string>(RoomObjectVariable.FIGURE_POSTURE));
// petType = new PetFigureData(figure).typeId;
// break;
// case RoomObjectType.USER:
// image = this.getUserImage(figure);
// break;
// case RoomObjectType.RENTABLE_BOT:
// case RoomObjectType.BOT:
// styleId = SystemChatStyleEnum.BOT;
// break;
// }
//avatarColor = this._avatarColorCache.get(figure);
username = userData.name;
}
const chatMessage = new ChatBubbleMessage(
text,
username,
bubbleLocation,
chatType,
styleId,
imageUrl,
avatarColor
);
event.text,
event.userName,
new NitroPoint(event.userX, event.userY),
event.chatType,
event.styleId,
event.userImage,
(event.userColor && (('#' + (event.userColor.toString(16).padStart(6, '0'))) || null)));
addChat(chatMessage);
}, [ addChat ]);
useRoomSessionManagerEvent(RoomSessionChatEvent.CHAT_EVENT, onRoomSessionChatEvent);
CreateEventDispatcherHook(RoomWidgetUpdateChatEvent.CHAT_EVENT, eventDispatcher, onRoomWidgetUpdateChatEvent);
const onRoomDragEvent = useCallback((event: RoomDragEvent) =>
{
@ -142,7 +87,7 @@ export const ChatWidgetView: FC<ChatWidgetViewProps> = props =>
{
if(!chat.elementRef) return;
chat.left = (chat.elementRef.offsetLeft + event.offsetX);
chat.left += event.offsetX;
});
}, [ roomSession, chatMessages ]);

View File

@ -96,7 +96,7 @@ export const ChatWidgetMessageView: FC<ChatWidgetMessageViewProps> = props =>
{ (chat.imageUrl && (chat.imageUrl !== '')) && <div className="user-image" style={ { backgroundImage: 'url(' + chat.imageUrl + ')' } } /> }
</div>
<div className="chat-content">
<b className="username mr-1">{ chat.username }</b>
<b className="username mr-1" dangerouslySetInnerHTML={ {__html: `${ chat.username }: ` } } />
{ chat.text }
<span className="message"> {
messageParts && messageParts.map((part, index) =>

View File

@ -39,7 +39,7 @@ export class ChatBubbleMessage
public get left(): number
{
return this._top;
return this._left;
}
public set left(value: number)

View File

@ -1,6 +1,6 @@
.nitro-context-menu {
width: 150px;
max-width: 150px;
width: 125px;
max-width: 125px;
padding: 2px;
background-color: #1c323f;
border: 2px solid rgba($white, 0.5);
@ -9,16 +9,14 @@
z-index: $context-menu-zindex;
&.name-only {
background-color: rgba($black, 0.7);
background-color: rgba($black, 0.5);
padding: 1px 8px;
min-width: 60px;
width: unset;
max-width: unset;
text-align: center;
font-size: 18px;
}
&:after {
&:not(.name-only):after {
content: "";
position: absolute;
bottom: -7px;
@ -39,11 +37,12 @@
height: 25px;
max-height: 25px;
font-size: 16px;
margin-bottom: 2px;
}
.menu-list-split-3 {
.menu-list-item {
.menu-item {
margin-right: 2px;
&:nth-child(3n+3) {
@ -52,19 +51,30 @@
}
}
.menu-list-item {
.menu-item {
position: relative;
height: 24px;
max-height: 24px;
margin-top: 2px;
margin-bottom: 2px;
padding: 3px;
background: $bg-mirage-split-background;
cursor: pointer;
overflow: hidden;
&:last-child {
margin-bottom: 0;
}
&.disabled {
filter: brightness(0.7);
cursor: not-allowed;
cursor: not-allowed !important;
}
&.list-item {
height: 24px;
max-height: 24px;
padding: 3px;
background: $bg-mirage-split-background;
cursor: pointer;
&:not(.disabled):hover {
background: $bg-cello-split-background;
}
.fas,
@ -77,9 +87,6 @@
right: unset;
}
}
&:not(.disabled):hover {
background: $bg-cello-split-background;
}
}
}

View File

@ -1,10 +1,11 @@
import { FixedSizeStack } from 'nitro-renderer';
import { FixedSizeStack, Nitro } from 'nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { GetRoomObjectBounds, GetRoomSession, GetTicker } from '../../../../api';
import { ContextMenuViewProps } from './ContextMenuView.types';
const fadeDelay = 3000;
const fadeLength = 75;
const SPACE_AROUND_EDGES = 10;
export const ContextMenuView: FC<ContextMenuViewProps> = props =>
{
@ -46,9 +47,21 @@ export const ContextMenuView: FC<ContextMenuViewProps> = 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);
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(top < SPACE_AROUND_EDGES) top = SPACE_AROUND_EDGES;
else if(top > maxTop) top = maxTop;
setPos({
x: Math.round(((bounds.left + (bounds.width / 2)) - (elementRef.current.offsetWidth / 2))),
y: Math.round((bounds.top - elementRef.current.offsetHeight) + 10)
x: left,
y: top
});
}, [ objectId, category, isFading, close ]);

View File

@ -13,7 +13,7 @@ export const ContextMenuListItemView: FC<ContextMenuListItemViewProps> = props =
}, [ canSelect, onClick ]);
return (
<div className={ `d-flex justify-content-center align-items-center w-100 menu-list-item ${ !canSelect ? 'disabled ' : '' }${ className }` } onClick={ handleClick }>
<div className={ `d-flex justify-content-center align-items-center w-100 menu-item list-item ${ !canSelect ? 'disabled ' : '' }${ className }` } onClick={ handleClick }>
{ children }
</div>
)

View File

@ -1,4 +1,5 @@
import { FC } from 'react';
import { FurnitureBackgroundColorView } from './background-color/FurnitureBackgroundColorView';
import { FurnitureDimmerView } from './dimmer/FurnitureDimmerView';
import { FurnitureEngravingLockView } from './engraving-lock/FurnitureEngravingLockView';
import { FurnitureExchangeCreditView } from './exchange-credit/FurnitureExchangeCreditView';
@ -14,6 +15,7 @@ export const FurnitureWidgetsView: FC<FurnitureWidgetsViewProps> = props =>
{
return (
<div className="position-absolute nitro-room-widgets t-0 l-0">
<FurnitureBackgroundColorView />
<FurnitureDimmerView />
<FurnitureEngravingLockView />
<FurnitureExchangeCreditView />

View File

@ -0,0 +1,74 @@
import { NitroEvent, RoomControllerLevel, RoomEngineObjectEvent, RoomEngineTriggerWidgetEvent, RoomObjectVariable } from 'nitro-renderer';
import { FC, useCallback, useState } from 'react';
import { GetRoomEngine, GetSessionDataManager } from '../../../../../api';
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';
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 { roomSession = null, eventDispatcher = null } = useRoomContext();
const canOpenBackgroundToner = useCallback(() =>
{
const isRoomOwner = roomSession.isRoomOwner;
const hasLevel = (roomSession.controllerLevel >= RoomControllerLevel.GUEST);
const isGodMode = GetSessionDataManager().isGodMode;
return (isRoomOwner || hasLevel || isGodMode);
}, [ roomSession ]);
const onNitroEvent = useCallback((event: NitroEvent) =>
{
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 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)));
return;
}
case RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED: {
const widgetEvent = (event as RoomWidgetRoomObjectUpdateEvent);
setObjectId(prevValue =>
{
if(prevValue === widgetEvent.id) return null;
return prevValue;
});
return;
}
}
}, [ canOpenBackgroundToner ]);
useRoomEngineEvent(RoomEngineTriggerWidgetEvent.REQUEST_BACKGROUND_COLOR, onNitroEvent);
CreateEventDispatcherHook(RoomWidgetRoomObjectUpdateEvent.FURNI_REMOVED, eventDispatcher, onNitroEvent);
if(objectId === -1) return null;
return (
<NitroCardView simple={ true }>
<NitroCardHeaderView headerText={ LocalizeText('widget.backgroundcolor.title') } onCloseClick={ event => setObjectId(-1) } />
<NitroCardContentView>
background toner
</NitroCardContentView>
</NitroCardView>
);
}

View File

@ -5,7 +5,7 @@ import { ObjectLocationViewProps } from './ObjectLocationView.types';
export const ObjectLocationView: FC<ObjectLocationViewProps> = props =>
{
const { objectId = -1, category = -1, children = null } = props;
const { objectId = -1, category = -1, noFollow = false, children = null } = props;
const [ pos, setPos ] = useState<{ x: number, y: number }>({ x: -1, y: -1});
const elementRef = useRef<HTMLDivElement>();
@ -31,13 +31,24 @@ export const ObjectLocationView: FC<ObjectLocationViewProps> = props =>
useEffect(() =>
{
let remove = false;
if(noFollow)
{
updatePosition();
}
else
{
remove = true;
Nitro.instance.ticker.add(updatePosition);
}
return () =>
{
Nitro.instance.ticker.remove(updatePosition);
if(remove) Nitro.instance.ticker.remove(updatePosition);
}
}, [ updatePosition ]);
}, [ updatePosition, noFollow ]);
return (
<div ref={ elementRef } className={ 'object-location position-absolute ' + (pos.x > -1 ? 'visible' : 'invisible') } style={ { left: pos.x, top: pos.y } }>

View File

@ -2,4 +2,5 @@ export interface ObjectLocationViewProps
{
objectId: number;
category: number;
noFollow?: boolean;
}