diff --git a/package.json b/package.json
index 4b9c54ae..514fd216 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
"@fortawesome/fontawesome-svg-core": "^6.1.0",
"@fortawesome/free-solid-svg-icons": "^6.1.0",
"@fortawesome/react-fontawesome": "^0.1.17",
- "@nitrots/nitro-renderer": "^1.1.14",
+ "@nitrots/nitro-renderer": "^1.1.15",
"animate.css": "^4.1.1",
"classnames": "^2.3.1",
"cross-env": "^7.0.3",
diff --git a/public/ui-config.json.example b/public/ui-config.json.example
index 43902aab..d9934672 100644
--- a/public/ui-config.json.example
+++ b/public/ui-config.json.example
@@ -13,6 +13,7 @@
"user.badges.max.slots": 5,
"camera.publish.disabled": false,
"hc.disabled": false,
+ "badge.descriptions.enabled": true,
"hotelview": {
"show.avatar": true,
"widgets": {
diff --git a/src/App.tsx b/src/App.tsx
index ee5a8fc2..e2119242 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,11 +1,13 @@
import { ConfigurationEvent, HabboWebTools, LegacyExternalInterface, Nitro, NitroCommunicationDemoEvent, NitroEvent, NitroLocalizationEvent, NitroVersion, RoomEngineEvent, WebGL } from '@nitrots/nitro-renderer';
import { FC, useCallback, useState } from 'react';
-import { GetCommunication, GetConfiguration, GetNitroInstance } from './api';
+import { GetCommunication, GetConfiguration, GetNitroInstance, GetUIVersion } from './api';
import { Base, TransitionAnimation, TransitionAnimationTypes } from './common';
import { LoadingView } from './components/loading/LoadingView';
import { MainView } from './components/main/MainView';
import { DispatchUiEvent, UseConfigurationEvent, UseLocalizationEvent, UseMainEvent, UseRoomEngineEvent } from './hooks';
+NitroVersion.UI_VERSION = GetUIVersion();
+
export const App: FC<{}> = props =>
{
const [ isReady, setIsReady ] = useState(false);
@@ -16,11 +18,7 @@ export const App: FC<{}> = props =>
//@ts-ignore
if(!NitroConfig) throw new Error('NitroConfig is not defined!');
- if(!GetNitroInstance())
- {
- NitroVersion.UI_VERSION = '2.0.0';
- Nitro.bootstrap();
- }
+ if(!GetNitroInstance()) Nitro.bootstrap();
const getPreloadAssetUrls = useCallback(() =>
{
diff --git a/src/api/GetRendererVersion.ts b/src/api/GetRendererVersion.ts
new file mode 100644
index 00000000..bb9e4618
--- /dev/null
+++ b/src/api/GetRendererVersion.ts
@@ -0,0 +1,3 @@
+import { NitroVersion } from '@nitrots/nitro-renderer';
+
+export const GetRendererVersion = () => NitroVersion.RENDERER_VERSION;
diff --git a/src/api/GetUIVersion.ts b/src/api/GetUIVersion.ts
new file mode 100644
index 00000000..fb69e1ce
--- /dev/null
+++ b/src/api/GetUIVersion.ts
@@ -0,0 +1 @@
+export const GetUIVersion = () => '2.0.0';
diff --git a/src/api/index.ts b/src/api/index.ts
index f44592e6..7c98b2c5 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -1,6 +1,8 @@
export * from './common';
export * from './core';
export * from './friends';
+export * from './GetRendererVersion';
+export * from './GetUIVersion';
export * from './groups';
export * from './navigator';
export * from './nitro';
diff --git a/src/api/nitro/room/widgets/handlers/RoomWidgetChatInputHandler.ts b/src/api/nitro/room/widgets/handlers/RoomWidgetChatInputHandler.ts
index f9a01321..55a9c5ff 100644
--- a/src/api/nitro/room/widgets/handlers/RoomWidgetChatInputHandler.ts
+++ b/src/api/nitro/room/widgets/handlers/RoomWidgetChatInputHandler.ts
@@ -138,11 +138,14 @@ export class RoomWidgetChatInputHandler extends RoomWidgetHandler
newWindow.document.write(image.outerHTML);
return null;
case ':pickall':
- NotificationUtilities.confirm(LocalizeText('room.confirm.pick_all'), () =>
- {
- GetSessionDataManager().sendSpecialCommandMessage(':pickall');
- },
- null, null, null, LocalizeText('generic.alert.title'));
+ if(this.container.roomSession.isRoomOwner || GetSessionDataManager().isModerator)
+ {
+ NotificationUtilities.confirm(LocalizeText('room.confirm.pick_all'), () =>
+ {
+ GetSessionDataManager().sendSpecialCommandMessage(':pickall');
+ },
+ null, null, null, LocalizeText('generic.alert.title'));
+ }
return null;
case ':furni':
@@ -171,8 +174,7 @@ export class RoomWidgetChatInputHandler extends RoomWidgetHandler
case ':client':
case ':nitro':
case ':billsonnn':
- // this.container.notificationService.alertWithScrollableMessages([
- // '
Version: ' + Nitro.RELEASE_VERSION + 'This client is powered by Nitro HTML5
'], 'Nitro HTML5');
+ NotificationUtilities.showNitroAlert();
return null;
case ':settings':
if(this.container.roomSession.isRoomOwner || GetSessionDataManager().isModerator)
diff --git a/src/api/nitro/room/widgets/handlers/RoomWidgetInfostandHandler.ts b/src/api/nitro/room/widgets/handlers/RoomWidgetInfostandHandler.ts
index 5641e6e7..3928ed64 100644
--- a/src/api/nitro/room/widgets/handlers/RoomWidgetInfostandHandler.ts
+++ b/src/api/nitro/room/widgets/handlers/RoomWidgetInfostandHandler.ts
@@ -1,4 +1,4 @@
-import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomSessionUserFigureUpdateEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, Vector3d } from '@nitrots/nitro-renderer';
+import { IFurnitureData, NitroEvent, ObjectDataFactory, PetFigureData, PetRespectComposer, PetSupplementComposer, PetType, RoomControllerLevel, RoomModerationSettings, RoomObjectCategory, RoomObjectOperationType, RoomObjectType, RoomObjectVariable, RoomSessionFavoriteGroupUpdateEvent, RoomSessionPetInfoUpdateEvent, RoomSessionUserBadgesEvent, RoomSessionUserFigureUpdateEvent, RoomTradingLevelEnum, RoomUnitDropHandItemComposer, RoomUnitGiveHandItemComposer, RoomUnitGiveHandItemPetComposer, RoomUserData, RoomWidgetEnum, RoomWidgetEnumItemExtradataParameter, Vector3d } from '@nitrots/nitro-renderer';
import { SendMessageComposer } from '../../..';
import { GetNitroInstance, GetRoomEngine, GetSessionDataManager, IsOwnerOfFurniture } from '../../../..';
import { FriendsHelper } from '../../../../../components/friends/common/FriendsHelper';
@@ -23,7 +23,10 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
this.container.eventDispatcher.dispatchEvent(event);
return;
case RoomSessionUserFigureUpdateEvent.USER_FIGURE:
- this.processRoomSessionUserFigureUpdateEvent((event as RoomSessionUserFigureUpdateEvent));
+ this.container.eventDispatcher.dispatchEvent(event);
+ return;
+ case RoomSessionFavoriteGroupUpdateEvent.FAVOURITE_GROUP_UPDATE:
+ this.container.eventDispatcher.dispatchEvent(event);
return;
}
}
@@ -528,7 +531,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
// this._Str_16287(_local_12, _local_13);
}
- event.groupId = parseInt(userData.guildId);
+ event.groupId = userData.groupId;
event.groupBadgeId = GetSessionDataManager().getGroupBadge(event.groupId);
event.groupName = userData.groupName;
event.badges = this.container.roomSession.userDataManager.getUserBadges(userData.webID);
@@ -662,17 +665,6 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
this.container.eventDispatcher.dispatchEvent(infostandEvent);
}
- private processRoomSessionUserFigureUpdateEvent(event: RoomSessionUserFigureUpdateEvent): void
- {
- const userData = this.container.roomSession.userDataManager.getUserDataByIndex(event.userId);
-
- if(!userData) return;
-
- // update active infostand figure
- // update motto
- // update activity points
- }
-
private checkGuildSetting(event: RoomWidgetUpdateInfostandUserEvent): boolean
{
if(event.isGuildRoom) return (event.roomControllerLevel >= RoomControllerLevel.GUILD_ADMIN);
@@ -740,33 +732,7 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
if(moderation) flag = checkSetting(event, moderation);
- return (flag && (event.roomControllerLevel < RoomControllerLevel.ROOM_OWNER));
- }
-
- private getPetType(figure: string): number
- {
- return this.getPetFigurePart(figure, 0);
- }
-
- private getPetBreed(figure: string): number
- {
- return this.getPetFigurePart(figure, 1);
- }
-
- private getPetColor(figure: string): number
- {
- return this.getPetFigurePart(figure, 2);
- }
-
- private getPetFigurePart(figure: string, index: number): number
- {
- if(!figure || !figure.length) return -1;
-
- const parts = figure.split(' ');
-
- if(parts.length > 0) return parseInt(parts[index]);
-
- return -1;
+ return (flag && (event.targetRoomControllerLevel < RoomControllerLevel.ROOM_OWNER));
}
public get type(): string
@@ -779,7 +745,8 @@ export class RoomWidgetInfostandHandler extends RoomWidgetHandler
return [
RoomSessionPetInfoUpdateEvent.PET_INFO,
RoomSessionUserBadgesEvent.RSUBE_BADGES,
- RoomSessionUserFigureUpdateEvent.USER_FIGURE
+ RoomSessionUserFigureUpdateEvent.USER_FIGURE,
+ RoomSessionFavoriteGroupUpdateEvent.FAVOURITE_GROUP_UPDATE
];
}
diff --git a/src/api/notification/NotificationAlertItem.ts b/src/api/notification/NotificationAlertItem.ts
index b3432276..cbbf8f4a 100644
--- a/src/api/notification/NotificationAlertItem.ts
+++ b/src/api/notification/NotificationAlertItem.ts
@@ -1,4 +1,4 @@
-import { NotificationBubbleType } from './NotificationBubbleType';
+import { NotificationAlertType } from './NotificationAlertType';
export class NotificationAlertItem
{
@@ -12,7 +12,7 @@ export class NotificationAlertItem
private _title: string;
private _imageUrl: string;
- constructor(messages: string[], alertType: string = NotificationBubbleType.INFO, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null)
+ constructor(messages: string[], alertType: string = NotificationAlertType.DEFAULT, clickUrl: string = null, clickUrlText: string = null, title: string = null, imageUrl: string = null)
{
NotificationAlertItem.ITEM_ID += 1;
diff --git a/src/api/notification/NotificationAlertType.ts b/src/api/notification/NotificationAlertType.ts
index 9a4b192b..1ff90ebe 100644
--- a/src/api/notification/NotificationAlertType.ts
+++ b/src/api/notification/NotificationAlertType.ts
@@ -4,4 +4,5 @@ export class NotificationAlertType
public static MOTD: string = 'motd';
public static MODERATION: string = 'moderation';
public static EVENT: string = 'event';
+ public static NITRO: string = 'nitro';
}
diff --git a/src/api/notification/NotificationUtilities.ts b/src/api/notification/NotificationUtilities.ts
index 7aeda5eb..29dc8574 100644
--- a/src/api/notification/NotificationUtilities.ts
+++ b/src/api/notification/NotificationUtilities.ts
@@ -130,6 +130,11 @@ export class NotificationUtilities
DispatchUiEvent(new NotificationAlertEvent([ this.cleanText(message) ], type, clickUrl, clickUrlText, title, imageUrl));
}
+ public static showNitroAlert(): void
+ {
+ DispatchUiEvent(new NotificationAlertEvent(null, NotificationAlertType.NITRO));
+ }
+
public static showModeratorMessage(message: string, url: string = null, showHabboWay: boolean = true): void
{
this.simpleAlert(message, NotificationAlertType.MODERATION, url, LocalizeText('mod.alert.link'), LocalizeText('mod.alert.title'));
diff --git a/src/api/utils/CloneObject.ts b/src/api/utils/CloneObject.ts
new file mode 100644
index 00000000..6cd8d3eb
--- /dev/null
+++ b/src/api/utils/CloneObject.ts
@@ -0,0 +1,14 @@
+export const CloneObject = (object: T): T =>
+{
+ if((object == null) || ('object' != typeof object)) return object;
+
+ // @ts-ignore
+ const copy = new object.constructor();
+
+ for(const attr in object)
+ {
+ if(object.hasOwnProperty(attr)) copy[attr] = object[attr];
+ }
+
+ return copy;
+}
diff --git a/src/api/utils/index.ts b/src/api/utils/index.ts
index 6e223495..398758cb 100644
--- a/src/api/utils/index.ts
+++ b/src/api/utils/index.ts
@@ -1,3 +1,4 @@
+export * from './CloneObject';
export * from './ColorUtils';
export * from './LocalizeBadgeDescription';
export * from './LocalizeBageName';
diff --git a/src/common/Base.tsx b/src/common/Base.tsx
index 72ee2c27..8bffe170 100644
--- a/src/common/Base.tsx
+++ b/src/common/Base.tsx
@@ -1,9 +1,9 @@
-import { CSSProperties, DetailedHTMLProps, FC, HTMLAttributes, LegacyRef, useMemo } from 'react';
+import { CSSProperties, DetailedHTMLProps, FC, HTMLAttributes, MutableRefObject, useMemo } from 'react';
import { ColorVariantType, DisplayType, FloatType, OverflowType, PositionType } from './types';
export interface BaseProps extends DetailedHTMLProps, T>
{
- innerRef?: LegacyRef;
+ innerRef?: MutableRefObject;
display?: DisplayType;
fit?: boolean;
grow?: boolean;
diff --git a/src/common/layout/LayoutBadgeImageView.tsx b/src/common/layout/LayoutBadgeImageView.tsx
index 43a59f68..f5b4fadc 100644
--- a/src/common/layout/LayoutBadgeImageView.tsx
+++ b/src/common/layout/LayoutBadgeImageView.tsx
@@ -1,6 +1,6 @@
import { BadgeImageReadyEvent, NitroSprite, TextureUtils } from '@nitrots/nitro-renderer';
import { CSSProperties, FC, useEffect, useMemo, useState } from 'react';
-import { GetSessionDataManager, LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../api';
+import { GetConfiguration, GetSessionDataManager, LocalizeBadgeDescription, LocalizeBadgeName, LocalizeText } from '../../api';
import { Base, BaseProps } from '../Base';
export interface LayoutBadgeImageViewProps extends BaseProps
@@ -89,6 +89,8 @@ export const LayoutBadgeImageView: FC = props =>
{
const { title = null, description = null } = props;
+ if(!GetConfiguration('badge.descriptions.enabled', true)) return null;
+
return (
{ title }
diff --git a/src/components/inventory/reducers/InventoryBadgeReducer.tsx b/src/components/inventory/reducers/InventoryBadgeReducer.tsx
index b8de1d72..9589baeb 100644
--- a/src/components/inventory/reducers/InventoryBadgeReducer.tsx
+++ b/src/components/inventory/reducers/InventoryBadgeReducer.tsx
@@ -1,6 +1,6 @@
import { SetActivatedBadgesComposer } from '@nitrots/nitro-renderer';
import { Reducer } from 'react';
-import { SendMessageComposer } from '../../../api';
+import { GetConfiguration, SendMessageComposer } from '../../../api';
export interface IInventoryBadgeState
{
@@ -97,10 +97,7 @@ export const InventoryBadgeReducer: Reducer('user.badges.max.slots', 5); i++) composer.addActivatedBadge(activeBadges[i] || null);
SendMessageComposer(composer);
@@ -119,10 +116,7 @@ export const InventoryBadgeReducer: Reducer('user.badges.max.slots', 5); i++) composer.addActivatedBadge(activeBadges[i] || null);
SendMessageComposer(composer);
diff --git a/src/components/inventory/views/badge/InventoryBadgeView.tsx b/src/components/inventory/views/badge/InventoryBadgeView.tsx
index 8bf4f873..8471d39d 100644
--- a/src/components/inventory/views/badge/InventoryBadgeView.tsx
+++ b/src/components/inventory/views/badge/InventoryBadgeView.tsx
@@ -72,7 +72,7 @@ export const InventoryBadgeView: FC = props =>
return (
-
+
{ badges && (badges.length > 0) && badges.map((code, index) =>
{
if(activeBadges.indexOf(code) >= 0) return null;
diff --git a/src/components/nitropedia/NitropediaView.tsx b/src/components/nitropedia/NitropediaView.tsx
index 865a2acd..f9318563 100644
--- a/src/components/nitropedia/NitropediaView.tsx
+++ b/src/components/nitropedia/NitropediaView.tsx
@@ -1,3 +1,4 @@
+import { NitroLogger } from '@nitrots/nitro-renderer';
import { FC, useCallback, useEffect, useRef, useState } from 'react';
import { AddEventLinkTracker, GetConfiguration, NotificationUtilities, RemoveLinkEventTracker } from '../../api';
import { Base, NitroCardContentView, NitroCardHeaderView, NitroCardView } from '../../common';
@@ -13,19 +14,27 @@ export const NitropediaView: FC<{}> = props =>
const openPage = useCallback(async (link: string) =>
{
- const response = await fetch(link);
-
- if(!response) return;
-
- const text = await response.text();
-
- const splitData = text.split(NEW_LINE_REGEX);
-
- BatchUpdates(() =>
+ try
{
- setHeader(splitData.shift());
- setContent(splitData.join(''));
- });
+ const response = await fetch(link);
+
+ if(!response) return;
+
+ const text = await response.text();
+
+ const splitData = text.split(NEW_LINE_REGEX);
+
+ BatchUpdates(() =>
+ {
+ setHeader(splitData.shift());
+ setContent(splitData.join(''));
+ });
+ }
+
+ catch (error)
+ {
+ NitroLogger.error(`Failed to fetch ${ link }`);
+ }
}, []);
const onLinkReceived = useCallback((link: string) =>
diff --git a/src/components/notification-center/views/alert-layouts/GetAlertLayout.tsx b/src/components/notification-center/views/alert-layouts/GetAlertLayout.tsx
index 44b24271..844686d0 100644
--- a/src/components/notification-center/views/alert-layouts/GetAlertLayout.tsx
+++ b/src/components/notification-center/views/alert-layouts/GetAlertLayout.tsx
@@ -1,4 +1,5 @@
-import { NotificationAlertItem } from '../../../../api';
+import { NotificationAlertItem, NotificationAlertType } from '../../../../api';
+import { NitroSystemAlertView } from './NitroSystemAlertView';
import { NotificationDefaultAlertView } from './NotificationDefaultAlertView';
export const GetAlertLayout = (item: NotificationAlertItem, close: () => void) =>
@@ -7,5 +8,11 @@ export const GetAlertLayout = (item: NotificationAlertItem, close: () => void) =
const props = { key: item.id, item, close };
- return
+ switch(item.alertType)
+ {
+ case NotificationAlertType.NITRO:
+ return
+ default:
+ return
+ }
}
diff --git a/src/components/notification-center/views/alert-layouts/NitroSystemAlertView.tsx b/src/components/notification-center/views/alert-layouts/NitroSystemAlertView.tsx
new file mode 100644
index 00000000..8a45ce70
--- /dev/null
+++ b/src/components/notification-center/views/alert-layouts/NitroSystemAlertView.tsx
@@ -0,0 +1,39 @@
+import { FC } from 'react';
+import { GetRendererVersion, GetUIVersion, NotificationAlertItem } from '../../../../api';
+import { Button, Column, Flex, Grid, LayoutNotificationAlertView, LayoutNotificationAlertViewProps, Text } from '../../../../common';
+
+interface NotificationDefaultAlertViewProps extends LayoutNotificationAlertViewProps
+{
+ item: NotificationAlertItem;
+}
+
+export const NitroSystemAlertView: FC = props =>
+{
+ const { title = 'Nitro', close = null, ...rest } = props;
+
+ return (
+
+
+
+
+
+
+
+ Nitro React
+ v{ GetUIVersion() }
+
+
+ Renderer: v{ GetRendererVersion() }
+
+
+
+
+
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/notification-center/views/bubble-layouts/NotificationDefaultBubbleView.tsx b/src/components/notification-center/views/bubble-layouts/NotificationDefaultBubbleView.tsx
index b778ff58..cfa7d2ef 100644
--- a/src/components/notification-center/views/bubble-layouts/NotificationDefaultBubbleView.tsx
+++ b/src/components/notification-center/views/bubble-layouts/NotificationDefaultBubbleView.tsx
@@ -1,5 +1,5 @@
import { FC } from 'react';
-import { NotificationBubbleItem } from '../../../../api';
+import { NotificationBubbleItem, NotificationUtilities } from '../../../../api';
import { Flex, LayoutNotificationBubbleView, LayoutNotificationBubbleViewProps, Text } from '../../../../common';
export interface NotificationDefaultBubbleViewProps extends LayoutNotificationBubbleViewProps
@@ -14,7 +14,7 @@ export const NotificationDefaultBubbleView: FC');
return (
-
+ (item.linkUrl && item.linkUrl.length && NotificationUtilities.openUrl(item.linkUrl)) } { ...rest }>
{ (item.iconUrl && item.iconUrl.length) &&
}
diff --git a/src/components/room/RoomView.tsx b/src/components/room/RoomView.tsx
index ce2743f3..ccb1c1fd 100644
--- a/src/components/room/RoomView.tsx
+++ b/src/components/room/RoomView.tsx
@@ -121,7 +121,7 @@ export const RoomView: FC = props =>
GetNitroInstance().render();
}
- if(elementRef && elementRef.current) elementRef.current.appendChild(canvas);
+ if(elementRef && elementRef.current) elementRef.current.replaceChildren(canvas);
setCanvasId(canvasId);
}, [ roomSession ]);
diff --git a/src/components/room/widgets/RoomWidgetsView.tsx b/src/components/room/widgets/RoomWidgetsView.tsx
index c8bea4a2..55bdeaad 100644
--- a/src/components/room/widgets/RoomWidgetsView.tsx
+++ b/src/components/room/widgets/RoomWidgetsView.tsx
@@ -1,4 +1,4 @@
-import { RoomEngineEvent, RoomEngineObjectEvent, RoomEngineRoomAdEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomObjectVariable, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPetStatusUpdateEvent, RoomSessionPollEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent, RoomSessionUserFigureUpdateEvent, RoomSessionWordQuizEvent, RoomZoomEvent } from '@nitrots/nitro-renderer';
+import { RoomEngineEvent, RoomEngineObjectEvent, RoomEngineRoomAdEvent, RoomEngineTriggerWidgetEvent, RoomEngineUseProductEvent, RoomId, RoomObjectCategory, RoomObjectOperationType, RoomObjectVariable, RoomSessionChatEvent, RoomSessionDanceEvent, RoomSessionDimmerPresetsEvent, RoomSessionDoorbellEvent, RoomSessionErrorMessageEvent, RoomSessionEvent, RoomSessionFavoriteGroupUpdateEvent, RoomSessionFriendRequestEvent, RoomSessionPetInfoUpdateEvent, RoomSessionPetStatusUpdateEvent, RoomSessionPollEvent, RoomSessionPresentEvent, RoomSessionUserBadgesEvent, RoomSessionUserFigureUpdateEvent, RoomSessionWordQuizEvent, RoomZoomEvent } from '@nitrots/nitro-renderer';
import { FC, useCallback } from 'react';
import { CanManipulateFurniture, GetRoomEngine, GetSessionDataManager, IsFurnitureSelectionDisabled, LocalizeText, NotificationAlertType, NotificationUtilities, ProcessRoomObjectOperation, RoomWidgetFurniToWidgetMessage, RoomWidgetUpdateRoomEngineEvent, RoomWidgetUpdateRoomObjectEvent } from '../../../api';
import { FriendRequestEvent } from '../../../events';
@@ -263,6 +263,7 @@ export const RoomWidgetsView: FC<{}> = props =>
UseRoomSessionManagerEvent(RoomSessionDanceEvent.RSDE_DANCE, onRoomSessionEvent);
UseRoomSessionManagerEvent(RoomSessionUserBadgesEvent.RSUBE_BADGES, onRoomSessionEvent);
UseRoomSessionManagerEvent(RoomSessionUserFigureUpdateEvent.USER_FIGURE, onRoomSessionEvent);
+ UseRoomSessionManagerEvent(RoomSessionFavoriteGroupUpdateEvent.FAVOURITE_GROUP_UPDATE, onRoomSessionEvent);
UseRoomSessionManagerEvent(RoomSessionPetStatusUpdateEvent.PET_STATUS_UPDATE, onRoomSessionEvent);
UseRoomSessionManagerEvent(RoomSessionDoorbellEvent.DOORBELL, onRoomSessionEvent);
UseRoomSessionManagerEvent(RoomSessionDoorbellEvent.RSDE_REJECTED, onRoomSessionEvent);
diff --git a/src/components/room/widgets/avatar-info/AvatarInfoWidgetAvatarView.tsx b/src/components/room/widgets/avatar-info/AvatarInfoWidgetAvatarView.tsx
index a1ec2437..d7302ab4 100644
--- a/src/components/room/widgets/avatar-info/AvatarInfoWidgetAvatarView.tsx
+++ b/src/components/room/widgets/avatar-info/AvatarInfoWidgetAvatarView.tsx
@@ -199,7 +199,6 @@ export const AvatarInfoWidgetAvatarView: FC = p
break;
case 'rship_none':
messageType = RoomWidgetUserActionMessage.RELATIONSHIP_NONE;
- console.log('here')
break;
}
diff --git a/src/components/room/widgets/context-menu/ContextMenu.scss b/src/components/room/widgets/context-menu/ContextMenu.scss
index cb7351d7..e57027c4 100644
--- a/src/components/room/widgets/context-menu/ContextMenu.scss
+++ b/src/components/room/widgets/context-menu/ContextMenu.scss
@@ -1,6 +1,4 @@
.nitro-context-menu {
- width: 125px;
- max-width: 125px;
padding: 2px;
background-color: $gable-green;
border: 2px solid rgba($white, 0.5);
@@ -22,19 +20,23 @@
font-size: 18px;
}
- &:not(.name-only):after {
- content: "";
- position: absolute;
- bottom: -7px;
- left: 0;
- right: 0;
- margin: auto;
- height: 10px;
- width: 10px;
- transform: rotate(45deg);
- border-color: transparent rgba($white, 0.5) rgba($white, 0.5) transparent;
- border-style: solid;
- border-width: 5px;
+ &:not(.name-only) {
+ min-width: 125px;
+
+ &:after {
+ content: "";
+ position: absolute;
+ bottom: -7px;
+ left: 0;
+ right: 0;
+ margin: auto;
+ height: 10px;
+ width: 10px;
+ transform: rotate(45deg);
+ border-color: transparent rgba($white, 0.5) rgba($white, 0.5) transparent;
+ border-style: solid;
+ border-width: 5px;
+ }
}
.menu-header {
diff --git a/src/components/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx b/src/components/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx
index de6b1e54..a0b09924 100644
--- a/src/components/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx
+++ b/src/components/room/widgets/furniture/background-color/FurnitureBackgroundColorView.tsx
@@ -23,11 +23,7 @@ export const FurnitureBackgroundColorView: FC<{}> = props =>
const canOpenBackgroundToner = useCallback(() =>
{
- const isRoomOwner = roomSession.isRoomOwner;
- const hasLevel = (roomSession.controllerLevel >= RoomControllerLevel.GUEST);
- const isGodMode = GetSessionDataManager().isGodMode;
-
- return (isRoomOwner || hasLevel || isGodMode);
+ return (roomSession.isRoomOwner || (roomSession.controllerLevel >= RoomControllerLevel.GUEST) || GetSessionDataManager().isModerator);
}, [ roomSession ]);
const onRoomEngineObjectEvent = useCallback((event: RoomEngineObjectEvent) =>
diff --git a/src/components/room/widgets/infostand/InfoStandWidgetUserRelationshipsView.tsx b/src/components/room/widgets/infostand/InfoStandWidgetUserRelationshipsView.tsx
index ced56dd2..f7aa72fc 100644
--- a/src/components/room/widgets/infostand/InfoStandWidgetUserRelationshipsView.tsx
+++ b/src/components/room/widgets/infostand/InfoStandWidgetUserRelationshipsView.tsx
@@ -30,7 +30,7 @@ export const InfoStandWidgetUserRelationshipsView: FC
GetUserProfile(relationshipInfo.randomFriendId) }>
- { relationshipInfo.randomFriendName }
+ { relationshipInfo.randomFriendName }
{ (relationshipInfo.friendCount > 1) && (' ' + LocalizeText(`extendedprofile.relstatus.others.${ relationshipName }`, [ 'count' ], [ (relationshipInfo.friendCount - 1).toString() ])) }
diff --git a/src/components/room/widgets/infostand/InfoStandWidgetUserView.tsx b/src/components/room/widgets/infostand/InfoStandWidgetUserView.tsx
index a39d2f5b..60b97b31 100644
--- a/src/components/room/widgets/infostand/InfoStandWidgetUserView.tsx
+++ b/src/components/room/widgets/infostand/InfoStandWidgetUserView.tsx
@@ -1,7 +1,7 @@
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, RoomSessionUserBadgesEvent, UserRelationshipsComposer } from '@nitrots/nitro-renderer';
-import { FC, FocusEvent, KeyboardEvent, useCallback, useEffect, useState } from 'react';
-import { GetConfiguration, GetGroupInformation, LocalizeText, RoomWidgetChangeMottoMessage, RoomWidgetUpdateInfostandUserEvent, SendMessageComposer } from '../../../../api';
+import { RelationshipStatusInfoEvent, RelationshipStatusInfoMessageParser, RoomSessionFavoriteGroupUpdateEvent, RoomSessionUserBadgesEvent, RoomSessionUserFigureUpdateEvent, UserRelationshipsComposer } from '@nitrots/nitro-renderer';
+import { Dispatch, FC, FocusEvent, KeyboardEvent, SetStateAction, useCallback, useEffect, useState } from 'react';
+import { CloneObject, GetConfiguration, GetGroupInformation, GetSessionDataManager, LocalizeText, RoomWidgetChangeMottoMessage, RoomWidgetUpdateInfostandUserEvent, SendMessageComposer } from '../../../../api';
import { Base, Column, Flex, LayoutAvatarImageView, LayoutBadgeImageView, Text, UserProfileIconView } from '../../../../common';
import { BatchUpdates, UseEventDispatcherHook, UseMessageEventHook } from '../../../../hooks';
import { useRoomContext } from '../../RoomContext';
@@ -10,23 +10,22 @@ import { InfoStandWidgetUserRelationshipsView } from './InfoStandWidgetUserRelat
interface InfoStandWidgetUserViewProps
{
userData: RoomWidgetUpdateInfostandUserEvent;
+ setUserData: Dispatch>;
close: () => void;
}
export const InfoStandWidgetUserView: FC = props =>
{
- const { userData = null, close = null } = props;
- const { eventDispatcher = null, widgetHandler = null } = useRoomContext();
- const [ badges, setBadges ] = useState([]);
- const [ motto, setMotto ] = useState(null);
+ const { userData = null, setUserData = null, close = null } = props;
+ const [ motto, setMotto ] = useState(null);
const [ isEditingMotto, setIsEditingMotto ] = useState(false);
- const [ userRelationships, setUserRelationships ] = useState(null);
-
+ const [ relationships, setRelationships ] = useState(null);
+ const { eventDispatcher = null, widgetHandler = null } = useRoomContext();
const maxBadgeCount = GetConfiguration('user.badges.max.slots', 5);
const saveMotto = (motto: string) =>
{
- if(motto.length > 38) return;
+ if(!isEditingMotto || (motto.length > 38)) return;
widgetHandler.processWidgetMessage(new RoomWidgetChangeMottoMessage(motto));
@@ -51,18 +50,63 @@ export const InfoStandWidgetUserView: FC = props =
{
if(!userData || (userData.webID !== event.userId)) return;
- setBadges(event.badges);
- }, [ userData ]);
+ setUserData(prevValue =>
+ {
+ const newValue = CloneObject(prevValue);
+
+ newValue.badges = event.badges;
+
+ return newValue;
+ });
+ }, [ userData, setUserData ]);
UseEventDispatcherHook(RoomSessionUserBadgesEvent.RSUBE_BADGES, eventDispatcher, onRoomSessionUserBadgesEvent);
+ const onRoomSessionUserFigureUpdateEvent = useCallback((event: RoomSessionUserFigureUpdateEvent) =>
+ {
+ if(!userData || (userData.roomIndex !== event.roomIndex)) return;
+
+ setUserData(prevValue =>
+ {
+ const newValue = CloneObject(prevValue);
+
+ newValue.figure = event.figure;
+ newValue.motto = event.customInfo;
+ newValue.achievementScore = event.activityPoints;
+
+ return newValue;
+ });
+ }, [ userData, setUserData ]);
+
+ UseEventDispatcherHook(RoomSessionUserFigureUpdateEvent.USER_FIGURE, eventDispatcher, onRoomSessionUserFigureUpdateEvent);
+
+ const onRoomSessionFavoriteGroupUpdateEvent = useCallback((event: RoomSessionFavoriteGroupUpdateEvent) =>
+ {
+ if(!userData || (userData.roomIndex !== event.roomIndex)) return;
+
+ setUserData(prevValue =>
+ {
+ const newValue = CloneObject(prevValue);
+
+ const clearGroup = ((event.status === -1) || (event.habboGroupId <= 0));
+
+ newValue.groupId = clearGroup ? -1 : event.habboGroupId;
+ newValue.groupName = clearGroup ? null : event.habboGroupName
+ newValue.groupBadgeId = clearGroup ? null : GetSessionDataManager().getGroupBadge(event.habboGroupId);
+
+ return newValue;
+ });
+ }, [ userData, setUserData ]);
+
+ UseEventDispatcherHook(RoomSessionFavoriteGroupUpdateEvent.FAVOURITE_GROUP_UPDATE, eventDispatcher, onRoomSessionFavoriteGroupUpdateEvent);
+
const onUserRelationshipsEvent = useCallback((event: RelationshipStatusInfoEvent) =>
{
const parser = event.getParser();
if(!userData || (userData.webID !== parser.userId)) return;
-
- setUserRelationships(parser);
+
+ setRelationships(parser);
}, [ userData ]);
UseMessageEventHook(RelationshipStatusInfoEvent, onUserRelationshipsEvent);
@@ -71,7 +115,6 @@ export const InfoStandWidgetUserView: FC = props =
{
BatchUpdates(() =>
{
- setBadges(userData.badges);
setIsEditingMotto(false);
setMotto(userData.motto);
});
@@ -80,8 +123,12 @@ export const InfoStandWidgetUserView: FC = props =
return () =>
{
- setBadges([]);
- setUserRelationships(null);
+ BatchUpdates(() =>
+ {
+ setIsEditingMotto(false);
+ setMotto(null);
+ setRelationships(null);
+ });
}
}, [ userData ]);
@@ -108,7 +155,7 @@ export const InfoStandWidgetUserView: FC = props =
- { badges[0] && }
+ { userData.badges[0] && }
0) } className="badge-image" onClick={ event => GetGroupInformation(userData.groupId) }>
{ userData.groupId > 0 &&
@@ -117,18 +164,18 @@ export const InfoStandWidgetUserView: FC = props =
- { badges[1] && }
+ { userData.badges[1] && }
- { badges[2] && }
+ { userData.badges[2] && }
- { badges[3] && }
+ { userData.badges[3] && }
- { badges[4] && }
+ { userData.badges[4] && }
@@ -167,7 +214,7 @@ export const InfoStandWidgetUserView: FC = props =
> }
-
+
diff --git a/src/components/room/widgets/infostand/InfoStandWidgetView.tsx b/src/components/room/widgets/infostand/InfoStandWidgetView.tsx
index fae40a4e..b8122eb8 100644
--- a/src/components/room/widgets/infostand/InfoStandWidgetView.tsx
+++ b/src/components/room/widgets/infostand/InfoStandWidgetView.tsx
@@ -91,6 +91,7 @@ export const InfoStandWidgetView: FC<{}> = props =>
UseEventDispatcherHook(RoomWidgetUpdateInfostandUserEvent.BOT, eventDispatcher, onRoomWidgetUpdateEvent);
UseEventDispatcherHook(RoomWidgetUpdateInfostandRentableBotEvent.RENTABLE_BOT, eventDispatcher, onRoomWidgetUpdateEvent);
UseEventDispatcherHook(RoomWidgetUpdateInfostandPetEvent.PET_INFO, eventDispatcher, onRoomWidgetUpdateEvent);
+ UseEventDispatcherHook(RoomWidgetUpdateInfostandPetEvent.PET_INFO, eventDispatcher, onRoomWidgetUpdateEvent);
const getInfostandView = useCallback(() =>
{
@@ -102,7 +103,7 @@ export const InfoStandWidgetView: FC<{}> = props =>
return ;
case RoomWidgetUpdateInfostandUserEvent.OWN_USER:
case RoomWidgetUpdateInfostandUserEvent.PEER:
- return ;
+ return ;
case RoomWidgetUpdateInfostandUserEvent.BOT:
return ;
case RoomWidgetUpdateInfostandRentableBotEvent.RENTABLE_BOT:
diff --git a/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx b/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx
index 925300ef..b35cd7bd 100644
--- a/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx
+++ b/src/components/room/widgets/room-tools/RoomToolsWidgetView.tsx
@@ -65,11 +65,6 @@ export const RoomToolsWidgetView: FC<{}> = props =>
return () => clearTimeout(timeout);
}, [ roomName, roomOwner, roomTags ]);
-
- useEffect(() =>
- {
- console.log(navigatorData);
- }, [ navigatorData ]);
return (
diff --git a/src/index.tsx b/src/index.tsx
index fb56db9f..60a928c2 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -8,7 +8,4 @@ import './index.scss';
//@ts-ignore
library.add(fas);
-ReactDOM.render(
- ,
- document.getElementById('root')
-);
+ReactDOM.render(, document.getElementById('root'));
diff --git a/yarn.lock b/yarn.lock
index b50ab8e7..3f855dab 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1426,10 +1426,10 @@
"@jridgewell/resolve-uri" "^3.0.3"
"@jridgewell/sourcemap-codec" "^1.4.10"
-"@nitrots/nitro-renderer@^1.1.14":
- version "1.1.14"
- resolved "https://registry.yarnpkg.com/@nitrots/nitro-renderer/-/nitro-renderer-1.1.14.tgz#30c792572f4df26e85efab0342894bfeb10c3cfa"
- integrity sha512-P4ruZ7eJ169q/pzsTN/AYf5pqr4ZoTCefvsAGHON4VSFqUO1vIivqqNmTgWJlBHMukj2VqrbLZukYrbt0+cUCQ==
+"@nitrots/nitro-renderer@^1.1.15":
+ version "1.1.15"
+ resolved "https://registry.yarnpkg.com/@nitrots/nitro-renderer/-/nitro-renderer-1.1.15.tgz#cdb670680685a24ae8ca28a424ed3d00988cdc67"
+ integrity sha512-fXFWyaioHVTSbm6zsxKq8btVou8CXQ5gIPIxQbyJZVnBqZpkp7nFn3UPoTWnD6d/YPHbH1keyIsMEfTo6zztvg==
dependencies:
"@pixi/canvas-renderer" "^6.2.2"
"@pixi/extract" "^6.2.2"