useNavigatorStore.ts 16.6 Ko
Télécharger le fichier
import {
CanCreateRoomEventEvent,
CantConnectMessageParser,
CategoriesWithVisitorCountEvent,
CreateLinkEvent,
FavouriteChangedEvent,
FavouritesEvent,
FlatCreatedEvent,
FollowFriendMessageComposer,
GenericErrorEvent,
GetGuestRoomMessageComposer,
GetGuestRoomResultEvent,
GetRoomSessionManager,
GetSessionDataManager,
GetUserEventCatsMessageComposer,
GetUserFlatCatsMessageComposer,
HabboWebTools,
LegacyExternalInterface,
NavigatorCategoryDataParser,
NavigatorEventCategoryDataParser,
NavigatorHomeRoomEvent,
NavigatorLiftedEvent,
NavigatorMetadataEvent,
NavigatorOpenRoomCreatorEvent,
NavigatorSavedSearch,
NavigatorSearchesEvent,
NavigatorTopLevelContext,
OctaneEventType,
RoomDataParser,
RoomEnterErrorEvent,
RoomEntryInfoMessageEvent,
RoomForwardEvent,
RoomScoreEvent,
SecurityLevel,
UserEventCatsEvent,
UserFlatCatsEvent,
UserInfoEvent,
UserPermissionsEvent
} from '@octane/renderer';
import { useCallback, useRef, useState } from 'react';
import {
CreateRoomSession,
GenericErrorCode,
GetConfigurationValue,
INavigatorData,
INavigatorLiftedRoom,
LocalizeText,
NotificationAlertType,
SendMessageComposer,
toNavigatorLiftedRooms,
TryVisitRoom,
VisitDesktop,
IsAnyRoomController
} from '../../api';
import { useMessageEvent, useOctaneEvent } from '../events';
import { useNotification } from '../notification';
import { useNavigatorFavouritesStore } from './navigatorFavouritesStore';
import { useNavigatorUiStore } from './navigatorUiStore';
/**
* Whether a {@link GetGuestRoomResultEvent} carrying roomEnter may become the current
* room's data.
*
* The server answers roomEnter for any request that is not exactly
* `(roomId, false, true)`, so an answer about a different room - the furni room link
* asking about the room it points at, say - used to point room info, settings, the word
* filter and favourites at a room the user is not in.
*/
export const adoptsEnteredRoom = (currentRoomId: number, answeredRoomId: number): boolean =>
!currentRoomId || currentRoomId === answeredRoomId;
export const useNavigatorStore = () => {
const [categories, setCategories] = useState<NavigatorCategoryDataParser[]>(null);
const [eventCategories, setEventCategories] = useState<NavigatorEventCategoryDataParser[]>(null);
const [topLevelContext, setTopLevelContext] = useState<NavigatorTopLevelContext>(null);
const [topLevelContexts, setTopLevelContexts] = useState<NavigatorTopLevelContext[]>(null);
const [navigatorSearches, setNavigatorSearches] = useState<NavigatorSavedSearch[]>(null);
const [categoryVisitorCounts, setCategoryVisitorCounts] = useState<Map<number, number>>(null);
const [categoryMaxVisitorCounts, setCategoryMaxVisitorCounts] = useState<Map<number, number>>(null);
const [liftedRooms, setLiftedRooms] = useState<INavigatorLiftedRoom[]>([]);
const [navigatorData, setNavigatorData] = useState<INavigatorData>({
settingsReceived: false,
homeRoomId: 0,
enteredGuestRoom: null,
currentRoomOwner: false,
currentRoomId: 0,
currentRoomIsStaffPick: false,
createdFlatId: 0,
avatarId: 0,
roomPicker: false,
eventMod: false,
currentRoomRating: 0,
canRate: true
});
// Whether the navigator settings of this connection have arrived; the first ones forward the user to a room.
const settingsReceivedRef = useRef(false);
const { simpleAlert = null } = useNotification();
useMessageEvent<FavouritesEvent>(
FavouritesEvent,
useCallback((event) => {
const parser = event.getParser();
useNavigatorFavouritesStore.getState().setAll(parser.favoriteRoomIds || [], parser.limit);
}, [])
);
useMessageEvent<FavouriteChangedEvent>(
FavouriteChangedEvent,
useCallback((event) => {
const parser = event.getParser();
useNavigatorFavouritesStore.getState().apply(parser.flatId, !!parser.added);
}, [])
);
useMessageEvent<CanCreateRoomEventEvent>(
CanCreateRoomEventEvent,
useCallback(
(event) => {
const parser = event.getParser();
if (parser.canCreate) return;
simpleAlert(
LocalizeText(`navigator.cannotcreateevent.error.${parser.errorCode}`),
null,
null,
null,
LocalizeText('navigator.cannotcreateevent.title')
);
},
[simpleAlert]
)
);
useMessageEvent<UserInfoEvent>(
UserInfoEvent,
useCallback((event) => {
SendMessageComposer(new GetUserFlatCatsMessageComposer());
SendMessageComposer(new GetUserEventCatsMessageComposer());
}, [])
);
useMessageEvent<UserPermissionsEvent>(
UserPermissionsEvent,
useCallback((event) => {
const parser = event.getParser();
setNavigatorData((prev) => ({
...prev,
eventMod: parser.securityLevel >= SecurityLevel.MODERATOR,
roomPicker: parser.permissions.size ? parser.permissions.get('acc_staff_pick') === 1 : parser.securityLevel >= SecurityLevel.COMMUNITY
}));
}, [])
);
useMessageEvent<RoomForwardEvent>(
RoomForwardEvent,
useCallback((event) => {
const parser = event.getParser();
TryVisitRoom(parser.roomId);
}, [])
);
useMessageEvent<RoomEntryInfoMessageEvent>(
RoomEntryInfoMessageEvent,
useCallback((event) => {
const parser = event.getParser();
setNavigatorData((prev) => ({
...prev,
enteredGuestRoom: null,
currentRoomOwner: parser.isOwner,
currentRoomId: parser.roomId
}));
SendMessageComposer(new GetGuestRoomMessageComposer(parser.roomId, true, false));
if (LegacyExternalInterface.available) LegacyExternalInterface.call('legacyTrack', 'navigator', 'private', [parser.roomId]);
}, [])
);
useMessageEvent<GetGuestRoomResultEvent>(
GetGuestRoomResultEvent,
useCallback((event) => {
const parser = event.getParser();
if (parser.roomEnter) {
setNavigatorData((prev) => {
if (!adoptsEnteredRoom(prev.currentRoomId, parser.data.roomId)) return prev;
const next = { ...prev };
next.enteredGuestRoom = parser.data;
next.currentRoomIsStaffPick = parser.staffPick;
const isCreated = next.createdFlatId === parser.data.roomId;
if (!isCreated && parser.data.displayRoomEntryAd) {
if (GetConfigurationValue<boolean>('roomenterad.habblet.enabled', false)) HabboWebTools.openRoomEnterAd();
}
next.createdFlatId = 0;
return next;
});
return;
}
if (parser.roomForward) {
// Door-mode branches (DOORBELL_STATE / PASSWORD_STATE) are handled by useDoorState — skip them here.
const isOwner = parser.data.ownerName === GetSessionDataManager().userName;
if (!isOwner && !parser.isGroupMember) {
if (parser.data.doorMode === RoomDataParser.DOORBELL_STATE) return;
if (parser.data.doorMode === RoomDataParser.PASSWORD_STATE) return;
}
if (
parser.data.doorMode === RoomDataParser.NOOB_STATE &&
!GetSessionDataManager().isAmbassador &&
!GetSessionDataManager().isRealNoob &&
!IsAnyRoomController()
)
return;
CreateRoomSession(parser.data.roomId);
return;
}
setNavigatorData((prev) => ({
...prev,
enteredGuestRoom: parser.data,
currentRoomIsStaffPick: parser.staffPick
}));
}, [])
);
useMessageEvent<RoomScoreEvent>(
RoomScoreEvent,
useCallback((event) => {
const parser = event.getParser();
setNavigatorData((prev) => ({
...prev,
currentRoomRating: parser.totalLikes,
canRate: parser.canLike
}));
}, [])
);
useMessageEvent<GenericErrorEvent>(
GenericErrorEvent,
useCallback(
(event) => {
const parser = event.getParser();
// -100002 (wrong password) is handled by useDoorState — skip it here.
switch (parser.errorCode) {
case GenericErrorCode.VIP_REQUIRED:
simpleAlert(
LocalizeText('navigator.alert.need.to.be.vip'),
NotificationAlertType.DEFAULT,
null,
null,
LocalizeText('generic.alert.title')
);
return;
case GenericErrorCode.ROOM_NAME_UNACCEPTABLE:
simpleAlert(
LocalizeText('navigator.alert.invalid_room_name'),
NotificationAlertType.DEFAULT,
null,
null,
LocalizeText('generic.alert.title')
);
return;
case 4011:
simpleAlert(
LocalizeText('navigator.alert.cannot_perm_ban'),
NotificationAlertType.DEFAULT,
null,
null,
LocalizeText('generic.alert.title')
);
return;
case 4013:
simpleAlert(
LocalizeText('navigator.alert.room_in_maintenance'),
NotificationAlertType.DEFAULT,
null,
null,
LocalizeText('generic.alert.title')
);
return;
}
},
[simpleAlert]
)
);
useMessageEvent<NavigatorMetadataEvent>(
NavigatorMetadataEvent,
useCallback((event) => {
const parser = event.getParser();
setTopLevelContexts(parser.topLevelContexts);
setTopLevelContext(parser.topLevelContexts.length ? parser.topLevelContexts[0] : null);
// Seed the query's tab code so useNavigatorSearch activates immediately
useNavigatorUiStore.getState().setTab(parser.topLevelContexts[0]?.code ?? '');
}, [])
);
useMessageEvent<UserFlatCatsEvent>(
UserFlatCatsEvent,
useCallback((event) => {
const parser = event.getParser();
setCategories(parser.categories);
}, [])
);
useMessageEvent<UserEventCatsEvent>(
UserEventCatsEvent,
useCallback((event) => {
const parser = event.getParser();
setEventCategories(parser.categories);
}, [])
);
useMessageEvent<FlatCreatedEvent>(
FlatCreatedEvent,
useCallback((event) => {
const parser = event.getParser();
CreateRoomSession(parser.roomId);
}, [])
);
useOctaneEvent(
OctaneEventType.SOCKET_RECONNECTING,
useCallback(() => {
settingsReceivedRef.current = false;
setNavigatorData((prev) => ({ ...prev, settingsReceived: false }));
}, [])
);
useMessageEvent<NavigatorHomeRoomEvent>(
NavigatorHomeRoomEvent,
useCallback((event) => {
const parser = event.getParser();
// Read from a ref: a value copied out of an updater is stale when React runs the updater later.
const firstSettings = !settingsReceivedRef.current;
settingsReceivedRef.current = true;
setNavigatorData((prev) => ({ ...prev, homeRoomId: parser.homeRoomId, settingsReceived: true }));
if (!firstSettings) return;
if (GetRoomSessionManager().viewerSession) return;
let forwardType = -1;
let forwardId = -1;
if (GetConfigurationValue<string>('friend.id') !== undefined && parseInt(GetConfigurationValue<string>('friend.id')) > 0) {
forwardType = 0;
SendMessageComposer(new FollowFriendMessageComposer(parseInt(GetConfigurationValue<string>('friend.id'))));
}
if (GetConfigurationValue<number>('forward.type') !== undefined && GetConfigurationValue<number>('forward.id') !== undefined) {
forwardType = parseInt(GetConfigurationValue<string>('forward.type'));
forwardId = parseInt(GetConfigurationValue<string>('forward.id'));
}
if (forwardType === 2) {
TryVisitRoom(forwardId);
} else if (forwardType === -1 && parser.roomIdToEnter > 0) {
CreateLinkEvent('navigator/close');
CreateRoomSession(parser.roomIdToEnter !== parser.homeRoomId ? parser.roomIdToEnter : parser.homeRoomId);
}
}, [])
);
useMessageEvent<RoomEnterErrorEvent>(
RoomEnterErrorEvent,
useCallback(
(event) => {
const parser = event.getParser();
switch (parser.reason) {
case CantConnectMessageParser.REASON_FULL:
simpleAlert(
LocalizeText('navigator.guestroomfull.text'),
NotificationAlertType.DEFAULT,
null,
null,
LocalizeText('navigator.guestroomfull.title')
);
break;
case CantConnectMessageParser.REASON_QUEUE_ERROR:
simpleAlert(
LocalizeText(`room.queue.error.${parser.parameter}`),
NotificationAlertType.DEFAULT,
null,
null,
LocalizeText('room.queue.error.title')
);
break;
case CantConnectMessageParser.REASON_BANNED:
simpleAlert(LocalizeText('navigator.banned.text'), NotificationAlertType.DEFAULT, null, null, LocalizeText('navigator.banned.title'));
break;
default:
simpleAlert(LocalizeText('room.queue.error.title'), NotificationAlertType.DEFAULT, null, null, LocalizeText('room.queue.error.title'));
break;
}
if (GetRoomSessionManager().isReconnecting) return;
VisitDesktop();
},
[simpleAlert]
)
);
useMessageEvent<NavigatorOpenRoomCreatorEvent>(
NavigatorOpenRoomCreatorEvent,
useCallback((_event) => {
CreateLinkEvent('navigator/show');
}, [])
);
useMessageEvent<NavigatorSearchesEvent>(
NavigatorSearchesEvent,
useCallback((event) => {
const parser = event.getParser();
if (!parser) return;
setNavigatorSearches(parser.searches);
}, [])
);
useMessageEvent<CategoriesWithVisitorCountEvent>(
CategoriesWithVisitorCountEvent,
useCallback((event) => {
const data = event.getParser()?.data;
if (!data) return;
setCategoryVisitorCounts(new Map(data.categoryToCurrentUserCountMap));
setCategoryMaxVisitorCounts(new Map(data.categoryToMaxUserCountMap));
}, [])
);
// AIR HabboNewNavigator: NavigatorLifted replaces the LiftDataContainer's rooms and refreshes the view.
useMessageEvent<NavigatorLiftedEvent>(
NavigatorLiftedEvent,
useCallback((event) => {
const parser = event.getParser();
if (!parser) return;
setLiftedRooms(toNavigatorLiftedRooms(parser.rooms));
}, [])
);
return {
categories,
eventCategories,
topLevelContext,
topLevelContexts,
navigatorSearches,
categoryVisitorCounts,
categoryMaxVisitorCounts,
navigatorData,
liftedRooms
};
};
