5180 fichiers 38.5 Mo 0 téléchargements 417 vues mis à jour il y a 7 heures ui
nitro-v36-with-renderer-v36 / src / components / room / widgets / avatar-info / AvatarInfoWidgetView.tsx
AvatarInfoWidgetView.tsx 13.3 Ko Télécharger le fichier
import {
    AddLinkEventTracker,
    GetRoomEngine,
    GetSessionDataManager,
    ILinkEventTracker,
    RemoveLinkEventTracker,
    RoomEngineEvent,
    RoomEngineObjectEvent,
    RoomEnterEffect,
    RoomSessionDanceEvent
} from '@octane/renderer';
import { FC, useEffect, useState } from 'react';
import {
    AvatarInfoFurni,
    AvatarInfoPet,
    AvatarInfoRentableBot,
    AvatarInfoUser,
    GetConfigurationValue,
    RoomWidgetUpdateRentableBotChatEvent,
    RoomWidgetUpdateRentableBotTextSkillEvent
} from '../../../../api';
import { Column, LayoutFurniIconImageView } from '../../../../common';
import { useAvatarInfoWidget, useFurniPickupGuard, useOctaneEvent, useRoom, useUiEvent } from '../../../../hooks';
import { AvatarInfoPetTrainingPanelView } from './AvatarInfoPetTrainingPanelView';
import { AvatarInfoRentableBotChatView } from './AvatarInfoRentableBotChatView';
import { AvatarInfoRentableBotTextSkillView } from './AvatarInfoRentableBotTextSkillView';
import { AvatarInfoUseProductConfirmView } from './AvatarInfoUseProductConfirmView';
import { AvatarInfoUseProductView } from './AvatarInfoUseProductView';
import { InfoStandWidgetBotView } from './infostand/InfoStandWidgetBotView';
import { InfoStandWidgetFurniView } from './infostand/InfoStandWidgetFurniView';
import { InfoStandWidgetPetView } from './infostand/InfoStandWidgetPetView';
import { InfoStandWidgetRentableBotView } from './infostand/InfoStandWidgetRentableBotView';
import { InfoStandWidgetUserView } from './infostand/InfoStandWidgetUserView';
import { AvatarInfoNewUserHelpView } from './menu/AvatarInfoNewUserHelpView';
import { AvatarInfoWidgetAvatarView } from './menu/AvatarInfoWidgetAvatarView';
import { AvatarInfoWidgetDecorateView } from './menu/AvatarInfoWidgetDecorateView';
import { AvatarInfoWidgetNameView } from './menu/AvatarInfoWidgetNameView';
import { AvatarInfoWidgetOwnAvatarView } from './menu/AvatarInfoWidgetOwnAvatarView';
import { AvatarInfoWidgetOwnPetView } from './menu/AvatarInfoWidgetOwnPetView';
import { AvatarInfoWidgetPetView } from './menu/AvatarInfoWidgetPetView';
import { AvatarInfoWidgetRentableBotView } from './menu/AvatarInfoWidgetRentableBotView';
import { BaseButton } from '../../../../common/BaseButton';
import { NativeTextTree } from '../../../../common/native-text/NativeTextTree';

export const AvatarInfoWidgetView: FC<{}> = (props) => {
    const BLOCK_MENU_WINDOW_MS = 500;
    const BLOCK_ROTATE_WINDOW_MS = 500;
    const [isGameMode, setGameMode] = useState(false);
    const { pickupRoomObject } = useFurniPickupGuard();
    const [isDancing, setIsDancing] = useState(false);
    const [isTouchLayout, setIsTouchLayout] = useState(false);
    const [mobileFurniDetailsOpen, setMobileFurniDetailsOpen] = useState(false);
    const [mobileUserDetailsOpen, setMobileUserDetailsOpen] = useState(false);
    const [rentableBotChatEvent, setRentableBotChatEvent] = useState<RoomWidgetUpdateRentableBotChatEvent>(null);
    const [rentableBotTextSkillEvent, setRentableBotTextSkillEvent] = useState<RoomWidgetUpdateRentableBotTextSkillEvent>(null);
    const {
        avatarInfo = null,
        setAvatarInfo = null,
        activeNameBubble = null,
        setActiveNameBubble = null,
        nameBubbles = [],
        removeNameBubble = null,
        productBubbles = [],
        confirmingProduct = null,
        updateConfirmingProduct = null,
        removeProductBubble = null,
        isDecorating = false,
        setIsDecorating = null
    } = useAvatarInfoWidget();
    const { roomSession = null } = useRoom();

    const updateAvatarClickControl = (updates: { suppressMenuUntil?: number; suppressRotateUntil?: number }) => {
        const globalScope = globalThis as any;

        if (!globalScope.__octaneAvatarClickControl) {
            globalScope.__octaneAvatarClickControl = {
                suppressMenuUntil: 0,
                suppressRotateUntil: 0
            };
        }

        Object.assign(globalScope.__octaneAvatarClickControl, updates);
    };

    useOctaneEvent<RoomEngineEvent>(RoomEngineEvent.NORMAL_MODE, (event) => {
        if (isGameMode) setGameMode(false);
    });

    useOctaneEvent<RoomEngineEvent>(RoomEngineEvent.GAME_MODE, (event) => {
        if (!isGameMode) setGameMode(true);
    });

    useEffect(() => {
        const query = window.matchMedia('(pointer: coarse), (hover: none)');
        const updateTouchLayout = () => setIsTouchLayout(query.matches);

        updateTouchLayout();
        query.addEventListener('change', updateTouchLayout);

        return () => query.removeEventListener('change', updateTouchLayout);
    }, []);

    useOctaneEvent<RoomSessionDanceEvent>(RoomSessionDanceEvent.RSDE_DANCE, (event) => {
        if (event.roomIndex !== roomSession.ownRoomIndex) return;

        setIsDancing(event.danceId !== 0);
    });

    useUiEvent<RoomWidgetUpdateRentableBotChatEvent>(RoomWidgetUpdateRentableBotChatEvent.UPDATE_CHAT, (event) => setRentableBotChatEvent(event));

    useUiEvent<RoomWidgetUpdateRentableBotTextSkillEvent>(RoomWidgetUpdateRentableBotTextSkillEvent.UPDATE_TEXT_SKILL, (event) =>
        setRentableBotTextSkillEvent(event)
    );

    useOctaneEvent<RoomEngineObjectEvent>(RoomEngineObjectEvent.REQUEST_PICKUP, (event) => pickupRoomObject(event.objectId, event.category));

    useOctaneEvent<RoomEngineObjectEvent>(RoomEngineObjectEvent.REQUEST_MANIPULATION, (event) => {
        if (!(avatarInfo instanceof AvatarInfoFurni)) return;
        if (event.category !== avatarInfo.category || event.objectId !== avatarInfo.id) return;

        setMobileFurniDetailsOpen(false);
    });

    useEffect(() => {
        const linkTracker: ILinkEventTracker = {
            linkReceived: (url: string) => {
                const parts = url.split('/');

                if (parts.length < 2) return;

                switch (parts[1]) {
                    case 'hide':
                        setAvatarInfo(null);
                        setActiveNameBubble(null);

                        if (roomSession) GetRoomEngine().clearSelectedAvatar(roomSession.roomId);
                        return;
                    case 'block-menu':
                        updateAvatarClickControl({ suppressMenuUntil: Date.now() + BLOCK_MENU_WINDOW_MS });
                        setAvatarInfo(null);
                        setActiveNameBubble(null);
                        return;
                    case 'block-rotate':
                        updateAvatarClickControl({ suppressRotateUntil: Date.now() + BLOCK_ROTATE_WINDOW_MS });
                        return;
                }
            },
            eventUrlPrefix: 'avatar-info/'
        };

        AddLinkEventTracker(linkTracker);

        return () => RemoveLinkEventTracker(linkTracker);
    }, [roomSession, setActiveNameBubble, setAvatarInfo]);

    useEffect(() => {
        if (avatarInfo?.type !== AvatarInfoFurni.FURNI) {
            setMobileFurniDetailsOpen(false);
        }

        if (avatarInfo?.type !== AvatarInfoUser.OWN_USER && avatarInfo?.type !== AvatarInfoUser.PEER) {
            setMobileUserDetailsOpen(false);
        }
    }, [avatarInfo]);

    const getMenuView = () => {
        if (!roomSession || isGameMode) return null;

        if (activeNameBubble) return <AvatarInfoWidgetNameView nameInfo={activeNameBubble} onClose={() => setActiveNameBubble(null)} />;

        if (avatarInfo) {
            switch (avatarInfo.type) {
                // AIR has no bubble over furni: move, rotate and pick up stay in the infostand.
                case AvatarInfoFurni.FURNI:
                    return null;
                case AvatarInfoUser.OWN_USER:
                case AvatarInfoUser.PEER: {
                    const info = avatarInfo as AvatarInfoUser;

                    if (isTouchLayout && !mobileUserDetailsOpen) return null;

                    if (GetConfigurationValue('user.tags.enabled')) GetSessionDataManager().getUserTags(info.roomIndex);

                    if (info.isSpectatorMode) return null;

                    if (info.isOwnUser) {
                        if (RoomEnterEffect.isRunning()) return <AvatarInfoNewUserHelpView avatarInfo={info} onClose={() => setAvatarInfo(null)} />;

                        return (
                            <NativeTextTree>
                                <AvatarInfoWidgetOwnAvatarView
                                    avatarInfo={info}
                                    isDancing={isDancing}
                                    setIsDecorating={setIsDecorating}
                                    onClose={() => setAvatarInfo(null)}
                                />
                            </NativeTextTree>
                        );
                    }

                    return <AvatarInfoWidgetAvatarView avatarInfo={info} onClose={() => setAvatarInfo(null)} />;
                }
                case AvatarInfoPet.PET_INFO: {
                    const info = avatarInfo as AvatarInfoPet;

                    if (info.isOwner) return <AvatarInfoWidgetOwnPetView avatarInfo={info} onClose={() => setAvatarInfo(null)} />;

                    return <AvatarInfoWidgetPetView avatarInfo={info} onClose={() => setAvatarInfo(null)} />;
                }
                case AvatarInfoRentableBot.RENTABLE_BOT: {
                    return <AvatarInfoWidgetRentableBotView avatarInfo={avatarInfo as AvatarInfoRentableBot} onClose={() => setAvatarInfo(null)} />;
                }
            }
        }

        return null;
    };

    const getInfostandView = () => {
        if (!avatarInfo) return null;

        switch (avatarInfo.type) {
            case AvatarInfoFurni.FURNI:
                if (isTouchLayout && !isDecorating) {
                    const info = avatarInfo as AvatarInfoFurni;

                    if (!mobileFurniDetailsOpen) {
                        return (
                            <NativeTextTree>
                                <BaseButton className="octane-mobile-furni-infostand-trigger" type="button" onClick={() => setMobileFurniDetailsOpen(true)}>
                                    <LayoutFurniIconImageView productType={info.productType} productClassId={info.spriteId} />
                                </BaseButton>
                            </NativeTextTree>
                        );
                    }
                }

                return <InfoStandWidgetFurniView avatarInfo={avatarInfo as AvatarInfoFurni} onClose={() => setAvatarInfo(null)} />;
            case AvatarInfoUser.OWN_USER:
            case AvatarInfoUser.PEER:
                return <InfoStandWidgetUserView avatarInfo={avatarInfo as AvatarInfoUser} setAvatarInfo={setAvatarInfo} onClose={() => setAvatarInfo(null)} />;
            case AvatarInfoUser.BOT:
                return <InfoStandWidgetBotView avatarInfo={avatarInfo as AvatarInfoUser} onClose={() => setAvatarInfo(null)} />;
            case AvatarInfoRentableBot.RENTABLE_BOT:
                return <InfoStandWidgetRentableBotView avatarInfo={avatarInfo as AvatarInfoRentableBot} onClose={() => setAvatarInfo(null)} />;
            case AvatarInfoPet.PET_INFO:
                return <InfoStandWidgetPetView avatarInfo={avatarInfo as AvatarInfoPet} onClose={() => setAvatarInfo(null)} />;
        }
    };

    return (
        <NativeTextTree>
            <>
                {isDecorating && (
                    <AvatarInfoWidgetDecorateView
                        roomIndex={roomSession.ownRoomIndex}
                        setIsDecorating={setIsDecorating}
                        userId={GetSessionDataManager().userId}
                        userName={GetSessionDataManager().userName}
                    />
                )}
                {getMenuView()}
                {avatarInfo && (
                    <Column alignItems="end" className="octane-infostand-area absolute right-[10px] bottom-[65px] pointer-events-none z-30 text-white">
                        {getInfostandView()}
                    </Column>
                )}
                {nameBubbles.length > 0 &&
                    nameBubbles.map((name, index) => <AvatarInfoWidgetNameView key={index} nameInfo={name} onClose={() => removeNameBubble(index)} />)}
                {productBubbles.length > 0 &&
                    productBubbles.map((item, index) => {
                        return (
                            <AvatarInfoUseProductView
                                key={item.id}
                                item={item}
                                updateConfirmingProduct={updateConfirmingProduct}
                                onClose={() => removeProductBubble(index)}
                            />
                        );
                    })}
                {rentableBotChatEvent && <AvatarInfoRentableBotChatView chatEvent={rentableBotChatEvent} onClose={() => setRentableBotChatEvent(null)} />}
                {rentableBotTextSkillEvent && (
                    <AvatarInfoRentableBotTextSkillView
                        key={`${rentableBotTextSkillEvent.botId}:${rentableBotTextSkillEvent.skillType}:${rentableBotTextSkillEvent.text}`}
                        skillEvent={rentableBotTextSkillEvent}
                        onClose={() => setRentableBotTextSkillEvent(null)}
                    />
                )}
                {confirmingProduct && <AvatarInfoUseProductConfirmView item={confirmingProduct} onClose={() => updateConfirmingProduct(null)} />}
                <AvatarInfoPetTrainingPanelView />
            </>
        </NativeTextTree>
    );
};
15Sujets
1Dépôts
20Membres
3En ligne
Profile
Inscrit
Dernière visite
Messages
0
Votes positifs
0
Votes négatifs
0

Nous utilisons des cookies pour assurer le bon fonctionnement du site et améliorer votre expérience. en savoir plus

Autoriser