Files
Nitro-V3/src/hooks/catalog/useCatalog.ts
T
2026-04-17 14:23:26 +02:00

1020 lines
38 KiB
TypeScript

import { BuildersClubFurniCountMessageEvent, BuildersClubPlaceRoomItemMessageComposer, BuildersClubPlaceWallItemMessageComposer, BuildersClubQueryFurniCountMessageComposer, BuildersClubSubscriptionStatusMessageEvent, CatalogPageMessageEvent, CatalogPagesListEvent, CatalogPublishedMessageEvent, ClubGiftInfoEvent, CreateLinkEvent, FrontPageItem, FurniturePlaceComposer, FurniturePlacePaintComposer, GetCatalogIndexComposer, GetCatalogPageComposer, GetClubGiftInfo, GetGiftWrappingConfigurationComposer, GetRoomEngine, GetSessionDataManager, GetTickerTime, GiftWrappingConfigurationEvent, GuildMembershipsMessageEvent, HabboClubOffersMessageEvent, LegacyDataType, LimitedEditionSoldOutEvent, MarketplaceMakeOfferResult, NodeData, ProductOfferEvent, PurchaseErrorMessageEvent, PurchaseFromCatalogComposer, PurchaseNotAllowedMessageEvent, PurchaseOKMessageEvent, RoomControllerLevel, RoomEngineObjectPlacedEvent, RoomObjectCategory, RoomObjectPlacementSource, RoomObjectType, RoomObjectVariable, RoomPreviewer, SellablePetPalettesMessageEvent, Vector3d } from '@nitrots/nitro-renderer';
import { useCallback, useEffect, useRef, useState } from 'react';
import { useBetween } from 'use-between';
import { BuilderFurniPlaceableStatus, CatalogNode, CatalogPage, CatalogPetPalette, CatalogType, DispatchUiEvent, FurniCategory, GetFurnitureData, GetProductDataForLocalization, GetRoomSession, GiftWrappingConfiguration, ICatalogNode, ICatalogOptions, ICatalogPage, IPageLocalization, IProduct, IPurchasableOffer, IPurchaseOptions, LocalizeText, NotificationAlertType, Offer, PageLocalization, PlacedObjectPurchaseData, PlaySound, Product, ProductTypeEnum, RequestedPage, SearchResult, SendMessageComposer, SoundNames } from '../../api';
import { CatalogPurchaseFailureEvent, CatalogPurchaseNotAllowedEvent, CatalogPurchaseSoldOutEvent, CatalogPurchasedEvent, InventoryFurniAddedEvent } from '../../events';
import { useMessageEvent, useNitroEvent, useUiEvent } from '../events';
import { useNotification } from '../notification';
import { useCatalogPlaceMultipleItems } from './useCatalogPlaceMultipleItems';
import { useCatalogSkipPurchaseConfirmation } from './useCatalogSkipPurchaseConfirmation';
const DUMMY_PAGE_ID_FOR_OFFER_SEARCH = -12345678;
const DRAG_AND_DROP_ENABLED = true;
const useCatalogState = () =>
{
const [ isVisible, setIsVisible ] = useState(false);
const [ isBusy, setIsBusy ] = useState(false);
const [ pageId, setPageId ] = useState(-1);
const [ previousPageId, setPreviousPageId ] = useState(-1);
const [ currentType, setCurrentType ] = useState(CatalogType.NORMAL);
const [ rootNode, setRootNode ] = useState<ICatalogNode>(null);
const [ offersToNodes, setOffersToNodes ] = useState<Map<number, ICatalogNode[]>>(null);
const [ currentPage, setCurrentPage ] = useState<ICatalogPage>(null);
const [ currentOffer, setCurrentOffer ] = useState<IPurchasableOffer>(null);
const [ activeNodes, setActiveNodes ] = useState<ICatalogNode[]>([]);
const [ searchResult, setSearchResult ] = useState<SearchResult>(null);
const [ frontPageItems, setFrontPageItems ] = useState<FrontPageItem[]>([]);
const [ roomPreviewer, setRoomPreviewer ] = useState<RoomPreviewer>(null);
const [ navigationHidden, setNavigationHidden ] = useState(false);
const [ purchaseOptions, setPurchaseOptions ] = useState<IPurchaseOptions>({ quantity: 1, extraData: null, extraParamRequired: false, previewStuffData: null });
const [ catalogOptions, setCatalogOptions ] = useState<ICatalogOptions>({});
const [ objectMoverRequested, setObjectMoverRequested ] = useState(false);
const [ catalogPlaceMultipleObjects, setCatalogPlaceMultipleObjects ] = useCatalogPlaceMultipleItems();
const [ catalogSkipPurchaseConfirmation, setCatalogSkipPurchaseConfirmation ] = useCatalogSkipPurchaseConfirmation();
const [ purchasableOffer, setPurchaseableOffer ] = useState<IPurchasableOffer>(null);
const [ placedObjectPurchaseData, setPlacedObjectPurchaseData ] = useState<PlacedObjectPurchaseData>(null);
const [ furniCount, setFurniCount ] = useState(0);
const [ furniLimit, setFurniLimit ] = useState(0);
const [ maxFurniLimit, setMaxFurniLimit ] = useState(0);
const [ secondsLeft, setSecondsLeft ] = useState(0);
const [ updateTime, setUpdateTime ] = useState(0);
const [ secondsLeftWithGrace, setSecondsLeftWithGrace ] = useState(0);
const [ builderPlacementBlockedByVisitors, setBuilderPlacementBlockedByVisitors ] = useState(false);
const [ builderPlacementAllowedInCurrentRoom, setBuilderPlacementAllowedInCurrentRoom ] = useState(false);
const [ builderTrialRoomHideConfirmed, setBuilderTrialRoomHideConfirmed ] = useState(false);
const { simpleAlert = null, showConfirm = null } = useNotification();
const requestedPage = useRef(new RequestedPage());
const resetState = useCallback(() =>
{
setPageId(-1);
setPreviousPageId(-1);
setRootNode(null);
setOffersToNodes(null);
setCurrentPage(null);
setCurrentOffer(null);
setActiveNodes([]);
setSearchResult(null);
setFrontPageItems([]);
setIsVisible(false);
}, []);
const normalizeCatalogType = useCallback((type?: string) =>
{
if(type === CatalogType.BUILDER) return CatalogType.BUILDER;
return CatalogType.NORMAL;
}, []);
const resetVisibleCatalogState = useCallback((type?: string) =>
{
requestedPage.current.resetRequest();
setPageId(-1);
setPreviousPageId(-1);
setRootNode(null);
setOffersToNodes(null);
setCurrentPage(null);
setCurrentOffer(null);
setActiveNodes([]);
setSearchResult(null);
setFrontPageItems([]);
setNavigationHidden(false);
setCurrentType(normalizeCatalogType(type));
}, [ normalizeCatalogType ]);
const openCatalogByType = useCallback((type?: string) =>
{
const catalogType = normalizeCatalogType(type);
if(currentType !== catalogType)
{
resetVisibleCatalogState(catalogType);
}
setIsVisible(true);
}, [ currentType, normalizeCatalogType, resetVisibleCatalogState ]);
const toggleCatalogByType = useCallback((type?: string) =>
{
const catalogType = normalizeCatalogType(type);
if(isVisible && (currentType === catalogType))
{
setIsVisible(false);
return;
}
if(currentType !== catalogType)
{
resetVisibleCatalogState(catalogType);
}
setIsVisible(true);
}, [ isVisible, currentType, normalizeCatalogType, resetVisibleCatalogState ]);
const getBuilderFurniPlaceableStatus = useCallback((offer: IPurchasableOffer) =>
{
if(!offer) return BuilderFurniPlaceableStatus.MISSING_OFFER;
const roomSession = GetRoomSession();
const canUseGuildAdminFallback = (!!roomSession
&& roomSession.isGuildRoom
&& (roomSession.controllerLevel >= RoomControllerLevel.GUILD_ADMIN)
&& (secondsLeft > 0));
const usesSharedPlacementPool = (!!roomSession && !roomSession.isRoomOwner && (builderPlacementAllowedInCurrentRoom || canUseGuildAdminFallback));
if(!roomSession) return BuilderFurniPlaceableStatus.NOT_IN_ROOM;
if(!roomSession.isRoomOwner && !builderPlacementAllowedInCurrentRoom && !canUseGuildAdminFallback) return BuilderFurniPlaceableStatus.NOT_GROUP_ADMIN;
if(!usesSharedPlacementPool && ((furniCount < 0) || (furniCount >= furniLimit))) return BuilderFurniPlaceableStatus.FURNI_LIMIT_REACHED;
if((secondsLeft <= 0) && builderPlacementBlockedByVisitors) return BuilderFurniPlaceableStatus.VISITORS_IN_ROOM;
if(secondsLeft <= 0)
{
const roomEngine = GetRoomEngine();
const userDataManager = roomSession.userDataManager;
const sessionDataManager = GetSessionDataManager();
if(!roomEngine || !userDataManager || !sessionDataManager) return BuilderFurniPlaceableStatus.OKAY;
const roomObjects = roomEngine.getRoomObjects(roomSession.roomId, RoomObjectCategory.UNIT);
if(!roomObjects || !roomObjects.length) return BuilderFurniPlaceableStatus.OKAY;
for(const roomObject of roomObjects)
{
if(!roomObject) continue;
const userData = userDataManager.getUserDataByIndex(roomObject.id);
if(!userData || (userData.type !== RoomObjectType.USER)) continue;
if(userData.webID === sessionDataManager.userId) continue;
if(userData.isModerator) continue;
return BuilderFurniPlaceableStatus.VISITORS_IN_ROOM;
}
}
return BuilderFurniPlaceableStatus.OKAY;
}, [ builderPlacementAllowedInCurrentRoom, builderPlacementBlockedByVisitors, furniCount, furniLimit, secondsLeft ]);
const isDraggable = useCallback((offer: IPurchasableOffer) =>
{
const roomSession = GetRoomSession();
if(((DRAG_AND_DROP_ENABLED && roomSession && offer.page && (offer.page.layoutCode !== 'sold_ltd_items') && (currentType === CatalogType.NORMAL) && (roomSession.isRoomOwner || (roomSession.isGuildRoom && (roomSession.controllerLevel >= RoomControllerLevel.GUILD_MEMBER)))) || ((currentType === CatalogType.BUILDER) && (getBuilderFurniPlaceableStatus(offer) === BuilderFurniPlaceableStatus.OKAY))) && (offer.pricingModel !== Offer.PRICING_MODEL_BUNDLE) && (offer.product.productType !== ProductTypeEnum.EFFECT) && (offer.product.productType !== ProductTypeEnum.HABBO_CLUB)) return true;
return false;
}, [ currentType, getBuilderFurniPlaceableStatus ]);
const requestOfferToMover = useCallback((offer: IPurchasableOffer) =>
{
if(!isDraggable(offer)) return;
const product = offer.product;
if(!product) return;
let category = 0;
switch(product.productType)
{
case ProductTypeEnum.FLOOR:
category = RoomObjectCategory.FLOOR;
break;
case ProductTypeEnum.WALL:
category = RoomObjectCategory.WALL;
break;
}
if(GetRoomEngine().processRoomObjectPlacement(RoomObjectPlacementSource.CATALOG, -(offer.offerId), category, product.productClassId, product.extraParam))
{
setPurchaseableOffer(offer);
setObjectMoverRequested(true);
setIsVisible(false);
}
}, [ isDraggable ]);
const resetRoomPaint = useCallback((planeType: string, type: string) =>
{
const roomEngine = GetRoomEngine();
let wallType = roomEngine.getRoomInstanceVariable<string>(roomEngine.activeRoomId, RoomObjectVariable.ROOM_WALL_TYPE);
let floorType = roomEngine.getRoomInstanceVariable<string>(roomEngine.activeRoomId, RoomObjectVariable.ROOM_FLOOR_TYPE);
let landscapeType = roomEngine.getRoomInstanceVariable<string>(roomEngine.activeRoomId, RoomObjectVariable.ROOM_LANDSCAPE_TYPE);
wallType = (wallType && wallType.length) ? wallType : '101';
floorType = (floorType && floorType.length) ? floorType : '101';
landscapeType = (landscapeType && landscapeType.length) ? landscapeType : '1.1';
switch(planeType)
{
case 'floor':
roomEngine.updateRoomInstancePlaneType(roomEngine.activeRoomId, type, wallType, landscapeType, true);
return;
case 'wallpaper':
roomEngine.updateRoomInstancePlaneType(roomEngine.activeRoomId, floorType, type, landscapeType, true);
return;
case 'landscape':
roomEngine.updateRoomInstancePlaneType(roomEngine.activeRoomId, floorType, wallType, type, true);
return;
default:
roomEngine.updateRoomInstancePlaneType(roomEngine.activeRoomId, floorType, wallType, landscapeType, true);
return;
}
}, []);
const cancelObjectMover = useCallback(() =>
{
if(!purchasableOffer) return;
GetRoomEngine().cancelRoomObjectInsert();
setObjectMoverRequested(false);
setPurchaseableOffer(null);
}, [ purchasableOffer ]);
const resetObjectMover = useCallback((flag: boolean = true) =>
{
setObjectMoverRequested(prevValue =>
{
if(prevValue && flag)
{
CreateLinkEvent('catalog/open');
}
return false;
});
}, []);
const resetPlacedOfferData = useCallback((flag: boolean = false) =>
{
if(!flag) resetObjectMover();
setPlacedObjectPurchaseData(prevValue =>
{
if(prevValue)
{
switch(prevValue.category)
{
case RoomObjectCategory.FLOOR:
GetRoomEngine().removeRoomObjectFloor(prevValue.roomId, prevValue.objectId);
break;
case RoomObjectCategory.WALL: {
switch(prevValue.furniData.className)
{
case 'floor':
case 'wallpaper':
case 'landscape':
resetRoomPaint('reset', '');
break;
default:
GetRoomEngine().removeRoomObjectWall(prevValue.roomId, prevValue.objectId);
break;
}
break;
}
default:
GetRoomEngine().deleteRoomObject(prevValue.objectId, prevValue.category);
break;
}
}
return null;
});
}, [ resetObjectMover, resetRoomPaint ]);
const getNodeById = useCallback((id: number, node: ICatalogNode) =>
{
if((node.pageId === id) && (node !== rootNode)) return node;
for(const child of node.children)
{
const found = (getNodeById(id, child));
if(found) return found;
}
return null;
}, [ rootNode ]);
const getNodeByName = useCallback((name: string, node: ICatalogNode) =>
{
if((node.pageName === name) && (node !== rootNode)) return node;
for(const child of node.children)
{
const found = (getNodeByName(name, child));
if(found) return found;
}
return null;
}, [ rootNode ]);
const getNodesByOfferId = useCallback((offerId: number, flag: boolean = false) =>
{
if(!offersToNodes || !offersToNodes.size) return null;
if(flag)
{
const nodes: ICatalogNode[] = [];
const offers = offersToNodes.get(offerId);
if(offers && offers.length) for(const offer of offers) (offer.isVisible && nodes.push(offer));
if(nodes.length) return nodes;
}
return offersToNodes.get(offerId);
}, [ offersToNodes ]);
const loadCatalogPage = useCallback((pageId: number, offerId: number) =>
{
if(pageId < 0) return;
setIsBusy(true);
setPageId(pageId);
if(pageId > -1) SendMessageComposer(new GetCatalogPageComposer(pageId, offerId, currentType));
}, [ currentType ]);
const showCatalogPage = useCallback((pageId: number, layoutCode: string, localization: IPageLocalization, offers: IPurchasableOffer[], offerId: number, acceptSeasonCurrencyAsCredits: boolean) =>
{
const catalogPage = (new CatalogPage(pageId, layoutCode, localization, offers, acceptSeasonCurrencyAsCredits) as ICatalogPage);
setCurrentPage(catalogPage);
setPreviousPageId(prevValue => ((pageId !== -1) ? pageId : prevValue));
setNavigationHidden(false);
if((offerId > -1) && catalogPage.offers.length)
{
for(const offer of catalogPage.offers)
{
if(offer.offerId !== offerId) continue;
setCurrentOffer(offer);
break;
}
}
}, []);
const activateNode = useCallback((targetNode: ICatalogNode, offerId: number = -1) =>
{
cancelObjectMover();
if(targetNode.parent.pageName === 'root')
{
if(targetNode.children.length)
{
for(const child of targetNode.children)
{
if(!child.isVisible) continue;
targetNode = child;
break;
}
}
}
const nodes: ICatalogNode[] = [];
let node = targetNode;
while(node && (node.pageName !== 'root'))
{
nodes.push(node);
node = node.parent;
}
nodes.reverse();
setActiveNodes(prevValue =>
{
const isActive = (prevValue.indexOf(targetNode) >= 0);
const isOpen = targetNode.isOpen;
for(const existing of prevValue)
{
existing.deactivate();
if(nodes.indexOf(existing) === -1) existing.close();
}
for(const n of nodes)
{
n.activate();
if(n.parent) n.open();
if((n === targetNode.parent) && n.children.length) n.open();
}
if(isActive && isOpen) targetNode.close();
else targetNode.open();
return nodes;
});
if(targetNode.pageId > -1) loadCatalogPage(targetNode.pageId, offerId);
}, [ setActiveNodes, loadCatalogPage, cancelObjectMover ]);
const openPageById = useCallback((id: number) =>
{
if(id !== -1) setSearchResult(null);
if(!isVisible)
{
requestedPage.current.requestById = id;
setIsVisible(true);
}
else
{
const node = getNodeById(id, rootNode);
if(node) activateNode(node);
}
}, [ isVisible, rootNode, getNodeById, activateNode ]);
const openPageByName = useCallback((name: string) =>
{
setSearchResult(null);
if(!isVisible)
{
requestedPage.current.requestByName = name;
setIsVisible(true);
}
else
{
const node = getNodeByName(name, rootNode);
if(node) activateNode(node);
}
}, [ isVisible, rootNode, getNodeByName, activateNode ]);
const openPageByOfferId = useCallback((offerId: number) =>
{
setSearchResult(null);
if(!isVisible)
{
requestedPage.current.requestedByOfferId = offerId;
setIsVisible(true);
}
else
{
const nodes = getNodesByOfferId(offerId);
if(!nodes || !nodes.length) return;
activateNode(nodes[0], offerId);
}
}, [ isVisible, getNodesByOfferId, activateNode ]);
const refreshBuilderStatus = useCallback(() =>
{
}, []);
useMessageEvent<CatalogPagesListEvent>(CatalogPagesListEvent, event =>
{
const parser = event.getParser();
const parserCatalogType = normalizeCatalogType(parser.catalogType);
if(parserCatalogType !== currentType) return;
const offers: Map<number, ICatalogNode[]> = new Map();
const getCatalogNode = (node: NodeData, depth: number, parent: ICatalogNode) =>
{
const catalogNode = (new CatalogNode(node, depth, parent) as ICatalogNode);
for(const offerId of catalogNode.offerIds)
{
if(offers.has(offerId)) offers.get(offerId).push(catalogNode);
else offers.set(offerId, [ catalogNode ]);
}
depth++;
for(const child of node.children) catalogNode.addChild(getCatalogNode(child, depth, catalogNode));
return catalogNode;
};
setRootNode(getCatalogNode(parser.root, 0, null));
setOffersToNodes(offers);
});
useMessageEvent<CatalogPageMessageEvent>(CatalogPageMessageEvent, event =>
{
const parser = event.getParser();
if(parser.catalogType !== currentType) return;
const purchasableOffers: IPurchasableOffer[] = [];
for(const offer of parser.offers)
{
const products: IProduct[] = [];
const productData = GetProductDataForLocalization(offer.localizationId);
for(const product of offer.products)
{
const furnitureData = GetFurnitureData(product.furniClassId, product.productType);
products.push(new Product(product.productType, product.furniClassId, product.extraParam, product.productCount, productData, furnitureData, product.uniqueLimitedItem, product.uniqueLimitedSeriesSize, product.uniqueLimitedItemsLeft));
}
if(!products.length) continue;
const purchasableOffer = new Offer(offer.offerId, offer.localizationId, offer.rent, offer.priceCredits, offer.priceActivityPoints, offer.priceActivityPointsType, offer.giftable, offer.clubLevel, products, offer.bundlePurchaseAllowed, offer.itemIds, offer.haveOffer);
if((currentType === CatalogType.NORMAL) || ((purchasableOffer.pricingModel !== Offer.PRICING_MODEL_BUNDLE) && (purchasableOffer.pricingModel !== Offer.PRICING_MODEL_MULTI))) purchasableOffers.push(purchasableOffer);
}
if(parser.frontPageItems && parser.frontPageItems.length) setFrontPageItems(parser.frontPageItems);
setIsBusy(false);
if(pageId === parser.pageId)
{
showCatalogPage(parser.pageId, parser.layoutCode, new PageLocalization(parser.localization.images.concat(), parser.localization.texts.concat()), purchasableOffers, parser.offerId, parser.acceptSeasonCurrencyAsCredits);
}
});
useMessageEvent<PurchaseOKMessageEvent>(PurchaseOKMessageEvent, event =>
{
const parser = event.getParser();
DispatchUiEvent(new CatalogPurchasedEvent(parser.offer));
});
useMessageEvent<PurchaseErrorMessageEvent>(PurchaseErrorMessageEvent, event =>
{
const parser = event.getParser();
DispatchUiEvent(new CatalogPurchaseFailureEvent(parser.code));
});
useMessageEvent<PurchaseNotAllowedMessageEvent>(PurchaseNotAllowedMessageEvent, event =>
{
const parser = event.getParser();
DispatchUiEvent(new CatalogPurchaseNotAllowedEvent(parser.code));
});
useMessageEvent<LimitedEditionSoldOutEvent>(LimitedEditionSoldOutEvent, event =>
{
const parser = event.getParser();
DispatchUiEvent(new CatalogPurchaseSoldOutEvent());
});
useMessageEvent<ProductOfferEvent>(ProductOfferEvent, event =>
{
const parser = event.getParser();
const offerData = parser.offer;
if(!offerData || !offerData.products.length) return;
const offerProductData = offerData.products[0];
if(offerProductData.uniqueLimitedItem)
{
// update unique
}
const products: IProduct[] = [];
const productData = GetProductDataForLocalization(offerData.localizationId);
for(const product of offerData.products)
{
const furnitureData = GetFurnitureData(product.furniClassId, product.productType);
products.push(new Product(product.productType, product.furniClassId, product.extraParam, product.productCount, productData, furnitureData, product.uniqueLimitedItem, product.uniqueLimitedSeriesSize, product.uniqueLimitedItemsLeft));
}
const offer = new Offer(offerData.offerId, offerData.localizationId, offerData.rent, offerData.priceCredits, offerData.priceActivityPoints, offerData.priceActivityPointsType, offerData.giftable, offerData.clubLevel, products, offerData.bundlePurchaseAllowed, offerData.itemIds, offerData.haveOffer);
if(!((currentType === CatalogType.NORMAL) || ((offer.pricingModel !== Offer.PRICING_MODEL_BUNDLE) && (offer.pricingModel !== Offer.PRICING_MODEL_MULTI)))) return;
offer.page = currentPage;
setCurrentOffer(offer);
if(offer.product && (offer.product.productType === ProductTypeEnum.WALL))
{
setPurchaseOptions(prevValue =>
{
const newValue = { ...prevValue };
newValue.extraData =( offer.product.extraParam || null);
return newValue;
});
}
// (this._isObjectMoverRequested) && (this._purchasableOffer)
});
useMessageEvent<SellablePetPalettesMessageEvent>(SellablePetPalettesMessageEvent, event =>
{
const parser = event.getParser();
const petPalette = new CatalogPetPalette(parser.productCode, parser.palettes.slice());
setCatalogOptions(prevValue =>
{
const petPalettes = [];
if(prevValue.petPalettes) petPalettes.push(...prevValue.petPalettes);
for(let i = 0; i < petPalettes.length; i++)
{
const palette = petPalettes[i];
if(palette.breed === petPalette.breed)
{
petPalettes.splice(i, 1);
break;
}
}
petPalettes.push(petPalette);
return { ...prevValue, petPalettes };
});
});
useMessageEvent<HabboClubOffersMessageEvent>(HabboClubOffersMessageEvent, event =>
{
const parser = event.getParser();
setCatalogOptions(prevValue =>
{
const windowId = parser.windowId;
const clubOffersByWindowId = { ...(prevValue.clubOffersByWindowId || {}) };
clubOffersByWindowId[windowId] = parser.offers;
const clubOffers = clubOffersByWindowId[1] || prevValue.clubOffers;
return { ...prevValue, clubOffers, clubOffersByWindowId };
});
});
useMessageEvent<GuildMembershipsMessageEvent>(GuildMembershipsMessageEvent, event =>
{
const parser = event.getParser();
setCatalogOptions(prevValue =>
{
const groups = parser.groups;
return { ...prevValue, groups };
});
});
useMessageEvent<GiftWrappingConfigurationEvent>(GiftWrappingConfigurationEvent, event =>
{
const parser = event.getParser();
setCatalogOptions(prevValue =>
{
const giftConfiguration = new GiftWrappingConfiguration(parser);
return { ...prevValue, giftConfiguration };
});
});
useMessageEvent<MarketplaceMakeOfferResult>(MarketplaceMakeOfferResult, event =>
{
const parser = event.getParser();
if(!parser) return;
let title = '';
if(parser.result === 1)
{
title = LocalizeText('inventory.marketplace.result.title.success');
}
else
{
title = LocalizeText('inventory.marketplace.result.title.failure');
}
const message = LocalizeText(`inventory.marketplace.result.${ parser.result }`);
simpleAlert(message, NotificationAlertType.DEFAULT, null, null, title);
});
useMessageEvent<ClubGiftInfoEvent>(ClubGiftInfoEvent, event =>
{
const parser = event.getParser();
setCatalogOptions(prevValue =>
{
const clubGifts = parser;
return { ...prevValue, clubGifts };
});
});
useMessageEvent<CatalogPublishedMessageEvent>(CatalogPublishedMessageEvent, event =>
{
const wasVisible = isVisible;
resetState();
if(wasVisible) simpleAlert(LocalizeText('catalog.alert.published.description'), NotificationAlertType.ALERT, null, null, LocalizeText('catalog.alert.published.title'));
});
useMessageEvent<BuildersClubFurniCountMessageEvent>(BuildersClubFurniCountMessageEvent, event =>
{
const parser = event.getParser();
setFurniCount(parser.furniCount);
refreshBuilderStatus();
});
useMessageEvent<BuildersClubSubscriptionStatusMessageEvent>(BuildersClubSubscriptionStatusMessageEvent, event =>
{
const parser = event.getParser();
setFurniLimit(parser.furniLimit);
setMaxFurniLimit(parser.maxFurniLimit);
setSecondsLeft(parser.secondsLeft);
setUpdateTime(GetTickerTime());
setSecondsLeftWithGrace(parser.secondsLeftWithGrace);
setBuilderPlacementBlockedByVisitors(parser.placementBlockedByVisitors);
setBuilderPlacementAllowedInCurrentRoom(parser.placementAllowedInCurrentRoom);
refreshBuilderStatus();
});
useUiEvent<CatalogPurchasedEvent>(CatalogPurchasedEvent.PURCHASE_SUCCESS, event => PlaySound(SoundNames.CREDITS));
useNitroEvent<RoomEngineObjectPlacedEvent>(RoomEngineObjectPlacedEvent.PLACED, event =>
{
if(!objectMoverRequested || (event.type !== RoomEngineObjectPlacedEvent.PLACED)) return;
resetPlacedOfferData(true);
if(!purchasableOffer)
{
resetObjectMover();
return;
}
let placed = false;
const product = purchasableOffer.product;
if(event.category === RoomObjectCategory.WALL)
{
switch(product.furnitureData.className)
{
case 'floor':
case 'wallpaper':
case 'landscape':
placed = (event.placedOnFloor || event.placedOnWall);
break;
default:
placed = event.placedInRoom;
break;
}
}
else
{
placed = event.placedInRoom;
}
if(!placed)
{
resetObjectMover();
return;
}
setPlacedObjectPurchaseData(new PlacedObjectPurchaseData(event.roomId, event.objectId, event.category, event.wallLocation, event.x, event.y, event.direction, purchasableOffer));
switch(currentType)
{
case CatalogType.NORMAL: {
switch(event.category)
{
case RoomObjectCategory.FLOOR:
GetRoomEngine().addFurnitureFloor(event.roomId, event.objectId, product.productClassId, new Vector3d(event.x, event.y, event.z), new Vector3d(event.direction), 0, new LegacyDataType());
break;
case RoomObjectCategory.WALL: {
switch(product.furnitureData.className)
{
case 'floor':
case 'wallpaper':
case 'landscape':
resetRoomPaint(product.furnitureData.className, product.extraParam);
break;
default:
GetRoomEngine().addFurnitureWall(event.roomId, event.objectId, product.productClassId, new Vector3d(event.x, event.y, event.z), new Vector3d(event.direction * 45), 0, event.instanceData, 0);
break;
}
}
}
const roomObject = GetRoomEngine().getRoomObject(event.roomId, event.objectId, event.category);
if(roomObject) roomObject.model.setValue(RoomObjectVariable.FURNITURE_ALPHA_MULTIPLIER, 0.5);
if(catalogSkipPurchaseConfirmation)
{
SendMessageComposer(new PurchaseFromCatalogComposer(pageId, purchasableOffer.offerId, product.extraParam, 1));
if(catalogPlaceMultipleObjects) requestOfferToMover(purchasableOffer);
}
else
{
// confirm
if(catalogPlaceMultipleObjects) requestOfferToMover(purchasableOffer);
}
break;
}
case CatalogType.BUILDER: {
const placeBuilderItem = () =>
{
let pageId = purchasableOffer.page.pageId;
if(pageId === DUMMY_PAGE_ID_FOR_OFFER_SEARCH)
{
pageId = -1;
}
switch(event.category)
{
case RoomObjectCategory.FLOOR:
SendMessageComposer(new BuildersClubPlaceRoomItemMessageComposer(pageId, purchasableOffer.offerId, product.extraParam, event.x, event.y, event.direction));
break;
case RoomObjectCategory.WALL:
SendMessageComposer(new BuildersClubPlaceWallItemMessageComposer(pageId, purchasableOffer.offerId, product.extraParam, event.wallLocation));
break;
}
if(catalogPlaceMultipleObjects && ((furniCount + 1) < furniLimit)) requestOfferToMover(purchasableOffer);
};
if((secondsLeft <= 0) && (furniCount <= 0) && !builderTrialRoomHideConfirmed && showConfirm)
{
showConfirm(LocalizeText('room.confirm.hide_room'), () =>
{
setBuilderTrialRoomHideConfirmed(true);
placeBuilderItem();
}, () => resetPlacedOfferData());
}
else
{
placeBuilderItem();
}
break;
}
}
});
useUiEvent<InventoryFurniAddedEvent>(InventoryFurniAddedEvent.FURNI_ADDED, event =>
{
const roomEngine = GetRoomEngine();
if(!placedObjectPurchaseData || (placedObjectPurchaseData.productClassId !== event.spriteId) || (placedObjectPurchaseData.roomId !== roomEngine.activeRoomId)) return;
switch(event.category)
{
case FurniCategory.FLOOR: {
const floorType = roomEngine.getRoomInstanceVariable(roomEngine.activeRoomId, RoomObjectVariable.ROOM_FLOOR_TYPE);
if(placedObjectPurchaseData.extraParam !== floorType) SendMessageComposer(new FurniturePlacePaintComposer(event.id));
break;
}
case FurniCategory.WALL_PAPER: {
const wallType = roomEngine.getRoomInstanceVariable(roomEngine.activeRoomId, RoomObjectVariable.ROOM_WALL_TYPE);
if(placedObjectPurchaseData.extraParam !== wallType) SendMessageComposer(new FurniturePlacePaintComposer(event.id));
break;
}
case FurniCategory.LANDSCAPE: {
const landscapeType = roomEngine.getRoomInstanceVariable(roomEngine.activeRoomId, RoomObjectVariable.ROOM_LANDSCAPE_TYPE);
if(placedObjectPurchaseData.extraParam !== landscapeType) SendMessageComposer(new FurniturePlacePaintComposer(event.id));
break;
}
default:
SendMessageComposer(new FurniturePlaceComposer(event.id, placedObjectPurchaseData.category, placedObjectPurchaseData.wallLocation, placedObjectPurchaseData.x, placedObjectPurchaseData.y, placedObjectPurchaseData.direction));
}
if(!catalogPlaceMultipleObjects) resetPlacedOfferData();
});
useEffect(() =>
{
return () => setCurrentOffer(null);
}, [ currentPage ]);
useEffect(() =>
{
if(!isVisible || !rootNode || !offersToNodes || !requestedPage.current) return;
switch(requestedPage.current.requestType)
{
case RequestedPage.REQUEST_TYPE_NONE:
if(currentPage) return;
if(rootNode.isBranch)
{
for(const child of rootNode.children)
{
if(child && child.isVisible)
{
activateNode(child);
return;
}
}
}
return;
case RequestedPage.REQUEST_TYPE_ID:
openPageById(requestedPage.current.requestById);
requestedPage.current.resetRequest();
return;
case RequestedPage.REQUEST_TYPE_OFFER:
openPageByOfferId(requestedPage.current.requestedByOfferId);
requestedPage.current.resetRequest();
return;
case RequestedPage.REQUEST_TYPE_NAME:
openPageByName(requestedPage.current.requestByName);
requestedPage.current.resetRequest();
return;
}
}, [ isVisible, rootNode, offersToNodes, currentPage, activateNode, openPageById, openPageByOfferId, openPageByName ]);
useEffect(() =>
{
if(!searchResult && currentPage && (currentPage.pageId === -1)) openPageById(previousPageId);
}, [ searchResult, currentPage, previousPageId, openPageById ]);
useEffect(() =>
{
if(!currentOffer) return;
setPurchaseOptions({ quantity: 1, extraData: null, extraParamRequired: false, previewStuffData: null });
}, [ currentOffer ]);
useEffect(() =>
{
if(secondsLeft > 0) setBuilderTrialRoomHideConfirmed(false);
}, [ secondsLeft ]);
useEffect(() =>
{
if(!isVisible || rootNode) return;
SendMessageComposer(new GetGiftWrappingConfigurationComposer());
SendMessageComposer(new GetClubGiftInfo());
SendMessageComposer(new GetCatalogIndexComposer(currentType));
SendMessageComposer(new BuildersClubQueryFurniCountMessageComposer());
}, [ isVisible, rootNode, currentType ]);
useEffect(() =>
{
setRoomPreviewer(new RoomPreviewer(GetRoomEngine(), ++RoomPreviewer.PREVIEW_COUNTER));
return () =>
{
setRoomPreviewer(prevValue =>
{
prevValue.dispose();
return null;
});
};
}, []);
return { isVisible, setIsVisible, isBusy, pageId, previousPageId, currentType, rootNode, offersToNodes, currentPage, setCurrentPage, currentOffer, setCurrentOffer, activeNodes, searchResult, setSearchResult, frontPageItems, roomPreviewer, navigationHidden, setNavigationHidden, purchaseOptions, setPurchaseOptions, catalogOptions, setCatalogOptions, getNodeById, getNodeByName, activateNode, openPageById, openPageByName, openPageByOfferId, requestOfferToMover, openCatalogByType, toggleCatalogByType, furniCount, furniLimit, maxFurniLimit, secondsLeft, secondsLeftWithGrace, updateTime, catalogPlaceMultipleObjects, setCatalogPlaceMultipleObjects, getBuilderFurniPlaceableStatus };
};
export const useCatalog = () => useBetween(useCatalogState);