mirror of
https://github.com/duckietm/Nitro-V3.git
synced 2026-06-19 15:06:20 +00:00
493 lines
17 KiB
TypeScript
493 lines
17 KiB
TypeScript
import { CanCreateRoomEventEvent, CantConnectMessageParser, CreateLinkEvent, DoorbellMessageEvent, FavouriteChangedEvent, FavouritesEvent, FlatAccessDeniedMessageEvent, FlatCreatedEvent, FollowFriendMessageComposer, GenericErrorEvent, GetGuestRoomMessageComposer, GetGuestRoomResultEvent, GetRoomSessionManager, GetSessionDataManager, GetUserEventCatsMessageComposer, GetUserFlatCatsMessageComposer, HabboWebTools, LegacyExternalInterface, NavigatorCategoryDataParser, NavigatorEventCategoryDataParser, NavigatorHomeRoomEvent, NavigatorMetadataEvent, NavigatorOpenRoomCreatorEvent, NavigatorSavedSearch, NavigatorSearchesEvent, NavigatorSearchEvent, NavigatorSearchResultSet, NavigatorTopLevelContext, NitroEventType, RoomDataParser, RoomDoorbellAcceptedEvent, RoomEnterErrorEvent, RoomEntryInfoMessageEvent, RoomForwardEvent, RoomScoreEvent, RoomSettingsUpdatedEvent, SecurityLevel, UserEventCatsEvent, UserFlatCatsEvent, UserInfoEvent, UserPermissionsEvent } from '@nitrots/nitro-renderer';
|
|
import { useState } from 'react';
|
|
import { useBetween } from 'use-between';
|
|
import { CreateRoomSession, DoorStateType, GetConfigurationValue, INavigatorData, LocalizeText, NotificationAlertType, SendMessageComposer, TryVisitRoom, VisitDesktop } from '../../api';
|
|
import { useMessageEvent, useNitroEvent } from '../events';
|
|
import { useNotification } from '../notification';
|
|
|
|
const useNavigatorState = () =>
|
|
{
|
|
const [ categories, setCategories ] = useState<NavigatorCategoryDataParser[]>(null);
|
|
const [ eventCategories, setEventCategories ] = useState<NavigatorEventCategoryDataParser[]>(null);
|
|
const [ favouriteRoomIds, setFavouriteRoomIds ] = useState<number[]>([]);
|
|
const [ topLevelContext, setTopLevelContext ] = useState<NavigatorTopLevelContext>(null);
|
|
const [ topLevelContexts, setTopLevelContexts ] = useState<NavigatorTopLevelContext[]>(null);
|
|
const [ doorData, setDoorData ] = useState<{ roomInfo: RoomDataParser, state: number }>({ roomInfo: null, state: DoorStateType.NONE });
|
|
const [ searchResult, setSearchResult ] = useState<NavigatorSearchResultSet>(null);
|
|
const [ navigatorSearches, setNavigatorSearches ] = useState<NavigatorSavedSearch[]>(null);
|
|
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
|
|
});
|
|
const { simpleAlert = null } = useNotification();
|
|
|
|
useMessageEvent<FavouritesEvent>(FavouritesEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
const favoriteIds = (parser.favoriteRoomIds || []).map((x: any) => Number(x));
|
|
setFavouriteRoomIds(favoriteIds);
|
|
});
|
|
|
|
useMessageEvent<FavouriteChangedEvent>(FavouriteChangedEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
const roomId = Number(parser.flatId);
|
|
const added = !!parser.added;
|
|
|
|
setFavouriteRoomIds(prev =>
|
|
{
|
|
const ids = (prev || []).map((x: any) => Number(x));
|
|
|
|
if(added) return ids.includes(roomId) ? ids : [ ...ids, roomId ];
|
|
|
|
return ids.filter(id => id !== roomId);
|
|
});
|
|
});
|
|
|
|
useMessageEvent<RoomSettingsUpdatedEvent>(RoomSettingsUpdatedEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
SendMessageComposer(new GetGuestRoomMessageComposer(parser.roomId, false, false));
|
|
});
|
|
|
|
useMessageEvent<CanCreateRoomEventEvent>(CanCreateRoomEventEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
if(parser.canCreate)
|
|
{
|
|
// show room event cvreate
|
|
|
|
return;
|
|
}
|
|
|
|
simpleAlert(LocalizeText(`navigator.cannotcreateevent.error.${ parser.errorCode }`), null, null, null, LocalizeText('navigator.cannotcreateevent.title'));
|
|
});
|
|
|
|
useMessageEvent<UserInfoEvent>(UserInfoEvent, event =>
|
|
{
|
|
SendMessageComposer(new GetUserFlatCatsMessageComposer());
|
|
SendMessageComposer(new GetUserEventCatsMessageComposer());
|
|
});
|
|
|
|
useMessageEvent<UserPermissionsEvent>(UserPermissionsEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setNavigatorData(prevValue =>
|
|
{
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.eventMod = (parser.securityLevel >= SecurityLevel.MODERATOR);
|
|
newValue.roomPicker = (parser.securityLevel >= SecurityLevel.COMMUNITY);
|
|
|
|
return newValue;
|
|
});
|
|
});
|
|
|
|
useMessageEvent<RoomForwardEvent>(RoomForwardEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
TryVisitRoom(parser.roomId);
|
|
});
|
|
|
|
useMessageEvent<RoomEntryInfoMessageEvent>(RoomEntryInfoMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setNavigatorData(prevValue =>
|
|
{
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.enteredGuestRoom = null;
|
|
newValue.currentRoomOwner = parser.isOwner;
|
|
newValue.currentRoomId = parser.roomId;
|
|
|
|
return newValue;
|
|
});
|
|
|
|
// close room info
|
|
// close room settings
|
|
// close room filter
|
|
|
|
SendMessageComposer(new GetGuestRoomMessageComposer(parser.roomId, true, false));
|
|
|
|
if(LegacyExternalInterface.available) LegacyExternalInterface.call('legacyTrack', 'navigator', 'private', [ parser.roomId ]);
|
|
});
|
|
|
|
useMessageEvent<GetGuestRoomResultEvent>(GetGuestRoomResultEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
if(parser.roomEnter)
|
|
{
|
|
setDoorData({ roomInfo: null, state: DoorStateType.NONE });
|
|
|
|
setNavigatorData(prevValue =>
|
|
{
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.enteredGuestRoom = parser.data;
|
|
newValue.currentRoomIsStaffPick = parser.staffPick;
|
|
|
|
const isCreated = (newValue.createdFlatId === parser.data.roomId);
|
|
|
|
if(!isCreated && parser.data.displayRoomEntryAd)
|
|
{
|
|
if(GetConfigurationValue<boolean>('roomenterad.habblet.enabled', false)) HabboWebTools.openRoomEnterAd();
|
|
}
|
|
|
|
newValue.createdFlatId = 0;
|
|
|
|
if(newValue.enteredGuestRoom && (newValue.enteredGuestRoom.habboGroupId > 0))
|
|
{
|
|
// close event info
|
|
}
|
|
|
|
return newValue;
|
|
});
|
|
}
|
|
else if(parser.roomForward)
|
|
{
|
|
if((parser.data.ownerName !== GetSessionDataManager().userName) && !parser.isGroupMember)
|
|
{
|
|
switch(parser.data.doorMode)
|
|
{
|
|
case RoomDataParser.DOORBELL_STATE:
|
|
setDoorData(prevValue =>
|
|
{
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.roomInfo = parser.data;
|
|
newValue.state = DoorStateType.START_DOORBELL;
|
|
|
|
return newValue;
|
|
});
|
|
return;
|
|
case RoomDataParser.PASSWORD_STATE:
|
|
setDoorData(prevValue =>
|
|
{
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.roomInfo = parser.data;
|
|
newValue.state = DoorStateType.START_PASSWORD;
|
|
|
|
return newValue;
|
|
});
|
|
return;
|
|
}
|
|
}
|
|
|
|
if((parser.data.doorMode === RoomDataParser.NOOB_STATE) && !GetSessionDataManager().isAmbassador && !GetSessionDataManager().isRealNoob && !GetSessionDataManager().isModerator) return;
|
|
|
|
CreateRoomSession(parser.data.roomId);
|
|
}
|
|
else
|
|
{
|
|
setNavigatorData(prevValue =>
|
|
{
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.enteredGuestRoom = parser.data;
|
|
newValue.currentRoomIsStaffPick = parser.staffPick;
|
|
|
|
return newValue;
|
|
});
|
|
}
|
|
});
|
|
|
|
useMessageEvent<RoomScoreEvent>(RoomScoreEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setNavigatorData(prevValue =>
|
|
{
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.currentRoomRating = parser.totalLikes;
|
|
newValue.canRate = parser.canLike;
|
|
|
|
return newValue;
|
|
});
|
|
});
|
|
|
|
useMessageEvent<DoorbellMessageEvent>(DoorbellMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
if(!parser.userName || (parser.userName.length === 0))
|
|
{
|
|
setDoorData(prevValue =>
|
|
{
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.state = DoorStateType.STATE_WAITING;
|
|
|
|
return newValue;
|
|
});
|
|
}
|
|
});
|
|
|
|
useMessageEvent<RoomDoorbellAcceptedEvent>(RoomDoorbellAcceptedEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
if(!parser.userName || (parser.userName.length === 0))
|
|
{
|
|
setDoorData(prevValue =>
|
|
{
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.state = DoorStateType.STATE_ACCEPTED;
|
|
|
|
return newValue;
|
|
});
|
|
}
|
|
});
|
|
|
|
useMessageEvent<FlatAccessDeniedMessageEvent>(FlatAccessDeniedMessageEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
if(!parser.userName || (parser.userName.length === 0))
|
|
{
|
|
setDoorData(prevValue =>
|
|
{
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.state = DoorStateType.STATE_NO_ANSWER;
|
|
|
|
return newValue;
|
|
});
|
|
}
|
|
});
|
|
|
|
useMessageEvent<GenericErrorEvent>(GenericErrorEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
switch(parser.errorCode)
|
|
{
|
|
case -100002:
|
|
setDoorData(prevValue =>
|
|
{
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.state = DoorStateType.STATE_WRONG_PASSWORD;
|
|
|
|
return newValue;
|
|
});
|
|
return;
|
|
case 4009:
|
|
simpleAlert(LocalizeText('navigator.alert.need.to.be.vip'), NotificationAlertType.DEFAULT, null, null, LocalizeText('generic.alert.title'));
|
|
|
|
return;
|
|
case 4010:
|
|
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;
|
|
}
|
|
});
|
|
|
|
useMessageEvent<NavigatorMetadataEvent>(NavigatorMetadataEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setTopLevelContexts(parser.topLevelContexts);
|
|
setTopLevelContext(parser.topLevelContexts.length ? parser.topLevelContexts[0] : null);
|
|
});
|
|
|
|
useMessageEvent<NavigatorSearchEvent>(NavigatorSearchEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setTopLevelContext(prevValue =>
|
|
{
|
|
let newValue = prevValue;
|
|
|
|
if(!newValue) newValue = ((topLevelContexts && topLevelContexts.length && topLevelContexts[0]) || null);
|
|
|
|
if(!newValue) return null;
|
|
|
|
if((parser.result.code !== newValue.code) && topLevelContexts && topLevelContexts.length)
|
|
{
|
|
for(const context of topLevelContexts)
|
|
{
|
|
if(context.code !== parser.result.code) continue;
|
|
|
|
newValue = context;
|
|
}
|
|
}
|
|
|
|
for(const context of topLevelContexts)
|
|
{
|
|
if(context.code !== parser.result.code) continue;
|
|
|
|
newValue = context;
|
|
}
|
|
|
|
return newValue;
|
|
});
|
|
|
|
setSearchResult(parser.result);
|
|
});
|
|
|
|
useMessageEvent<UserFlatCatsEvent>(UserFlatCatsEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setCategories(parser.categories);
|
|
});
|
|
|
|
useMessageEvent<UserEventCatsEvent>(UserEventCatsEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
setEventCategories(parser.categories);
|
|
});
|
|
|
|
useMessageEvent<FlatCreatedEvent>(FlatCreatedEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
CreateRoomSession(parser.roomId);
|
|
});
|
|
|
|
// When reconnection starts, reset settingsReceived so the login sequence's
|
|
// NavigatorHomeRoomEvent is treated as a fresh login. Without this, the
|
|
// prevSettingsReceived check blocks home room navigation after reconnection,
|
|
// leaving the user stuck on hotel view.
|
|
useNitroEvent(NitroEventType.SOCKET_RECONNECTING, () =>
|
|
{
|
|
setNavigatorData(prevValue => ({ ...prevValue, settingsReceived: false }));
|
|
});
|
|
|
|
useMessageEvent<NavigatorHomeRoomEvent>(NavigatorHomeRoomEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
|
|
let prevSettingsReceived = false;
|
|
|
|
setNavigatorData(prevValue =>
|
|
{
|
|
prevSettingsReceived = prevValue.settingsReceived;
|
|
|
|
const newValue = { ...prevValue };
|
|
|
|
newValue.homeRoomId = parser.homeRoomId;
|
|
newValue.settingsReceived = true;
|
|
|
|
return newValue;
|
|
});
|
|
|
|
if(prevSettingsReceived)
|
|
{
|
|
// refresh room info window
|
|
return;
|
|
}
|
|
|
|
// If a room session was already restored (from a network disconnect reload),
|
|
// skip the normal home room navigation to avoid overriding it.
|
|
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');
|
|
|
|
if(parser.roomIdToEnter !== parser.homeRoomId)
|
|
{
|
|
CreateRoomSession(parser.roomIdToEnter);
|
|
}
|
|
else
|
|
{
|
|
CreateRoomSession(parser.homeRoomId);
|
|
}
|
|
}
|
|
});
|
|
|
|
useMessageEvent<RoomEnterErrorEvent>(RoomEnterErrorEvent, 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;
|
|
}
|
|
|
|
// During reconnection, don't navigate to desktop — the reconnection guard
|
|
// will handle retrying or cleaning up. Calling VisitDesktop here would
|
|
// remove the session from the map and send the user to hotel view.
|
|
if(GetRoomSessionManager().isReconnecting) return;
|
|
|
|
VisitDesktop();
|
|
});
|
|
|
|
useMessageEvent<NavigatorOpenRoomCreatorEvent>(NavigatorOpenRoomCreatorEvent, event => CreateLinkEvent('navigator/show'));
|
|
|
|
useMessageEvent<NavigatorSearchesEvent>(NavigatorSearchesEvent, event =>
|
|
{
|
|
const parser = event.getParser();
|
|
if(!parser) return;
|
|
setNavigatorSearches(parser.searches);
|
|
});
|
|
|
|
return { categories, doorData, setDoorData, topLevelContext, topLevelContexts, searchResult, navigatorData, favouriteRoomIds, navigatorSearches };
|
|
};
|
|
|
|
export const useNavigator = () => useBetween(useNavigatorState);
|