5180 fichiers 38.5 Mo 0 téléchargements 262 vues mis à jour il y a 5 heures ui
nitro-v36-with-renderer-v36 / src / hooks / achievements / useAchievements.ts
useAchievements.ts 9 Ko Télécharger le fichier
import {
    AchievementData,
    AchievementEvent,
    AchievementsEvent,
    AchievementsScoreEvent,
    AuthenticatedEvent,
    RequestAchievementsMessageComposer,
    RoomSessionEvent,
    WiredEnvironmentEvent
} from '@octane/renderer';
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { registerSharedHook, useSharedHook } from '@/state/useSharedHook';
import { AchievementCategory, AchievementUtilities, GetOptionalConfigurationValue, SendMessageComposer } from '../../api';
import { useMessageEvent, useOctaneEvent } from '../events';

const copyAchievement = (achievement: AchievementData): AchievementData => Object.assign(Object.create(AchievementData.prototype), achievement);

const useAchievementsState = () => {
    const [achievements, setAchievements] = useState<AchievementData[]>([]);
    const [isLoaded, setIsLoaded] = useState(false);
    const [isVisible, setIsVisible] = useState(false);
    const [selectedCategoryCode, setSelectedCategoryCode] = useState<string>(null);
    const [selectedAchievementId, setSelectedAchievementId] = useState(-1);
    const [achievementScore, setAchievementScore] = useState(0);
    const [enabledWiredAchievements, setEnabledWiredAchievements] = useState<string[]>([]);
    const pendingLevel = useRef<{ achievement: AchievementData; timeout: ReturnType<typeof setTimeout> }>(null);

    const achievementCategories = useMemo(() => {
        const categories = new Map<string, AchievementCategory>();
        const archive = new AchievementCategory('archive');
        const wiredGames = new AchievementCategory('wired_games');
        const newAchievements = new AchievementCategory('new');
        const newCodes = GetOptionalConfigurationValue<string>('achievements.new', '').split(',');
        categories.set(archive.code, archive);
        categories.set(wiredGames.code, wiredGames);

        for (const achievement of achievements) {
            if (!achievement.category || (achievement.state === AchievementData.STATE_CONTROLLED_BY_WIRED && achievement.category !== 'wired_games')) continue;

            const code = achievement.state === AchievementData.STATE_ARCHIVED ? archive.code : achievement.category;
            if (!categories.has(code)) categories.set(code, new AchievementCategory(code));

            categories.get(code).achievements.push(achievement);
            if (newCodes.includes(achievement.code)) newAchievements.achievements.push(achievement);
        }

        const regular = [...categories.values()].filter((category) => !['archive', 'wired_games', 'misc'].includes(category.code));
        if (categories.has('misc')) regular.push(categories.get('misc'));
        regular.push(archive, wiredGames);
        if (newAchievements.achievements.length) regular.push(newAchievements);

        return regular;
    }, [achievements]);

    const selectedCategory = achievementCategories.find((category) => category.code === selectedCategoryCode) ?? null;
    const visibleAchievements =
        selectedCategory?.achievements.filter(
            (achievement) =>
                selectedCategory.code !== 'wired_games' || (achievement.code.startsWith('WF_') && enabledWiredAchievements.includes(achievement.code.slice(3)))
        ) ?? [];
    const selectedAchievement =
        visibleAchievements.find((achievement) => achievement.achievementId === selectedAchievementId) ?? visibleAchievements[0] ?? null;
    const getTotalUnseen = achievements.filter((achievement) => achievement.unseen && !AchievementUtilities.getAchievementIsIgnored(achievement)).length;
    const getProgress = achievementCategories.reduce((total, category) => total + category.getProgress(), 0);
    const getMaxProgress = achievementCategories.reduce((total, category) => total + category.getMaxProgress(), 0);

    const updateAchievement = useCallback((achievement: AchievementData) => {
        setAchievements((previous) =>
            previous.some((entry) => entry.achievementId === achievement.achievementId)
                ? previous.map((entry) => (entry.achievementId === achievement.achievementId ? achievement : entry))
                : [...previous, achievement]
        );
    }, []);

    const clearUnseen = useCallback((categoryCode?: string) => {
        setAchievements((previous) =>
            previous.map((achievement) => {
                if (
                    !achievement.unseen ||
                    (categoryCode &&
                        achievement.category !== categoryCode &&
                        !(categoryCode === 'archive' && achievement.state === AchievementData.STATE_ARCHIVED))
                )
                    return achievement;

                const seen = copyAchievement(achievement);
                seen.unseen = 0;
                return seen;
            })
        );
    }, []);

    const close = useCallback(() => {
        setIsVisible(false);
        if (pendingLevel.current) pendingLevel.current.achievement.unseen = 0;
        clearUnseen();
    }, [clearUnseen]);

    const selectCategory = useCallback(
        (code: string) => {
            if (!code) clearUnseen(selectedCategoryCode);
            setSelectedCategoryCode(code);
            setSelectedAchievementId(-1);
        },
        [clearUnseen, selectedCategoryCode]
    );

    const show = useCallback(
        (categoryCode?: string) => {
            if (!isLoaded) SendMessageComposer(new RequestAchievementsMessageComposer());
            if (categoryCode) selectCategory(categoryCode);
            setIsVisible(true);
        },
        [isLoaded, selectCategory]
    );

    const clearPendingLevel = useCallback(() => {
        if (pendingLevel.current) clearTimeout(pendingLevel.current.timeout);
        pendingLevel.current = null;
    }, []);

    useMessageEvent<AchievementEvent>(AchievementEvent, (event) => {
        const achievement = event.getParser().achievement;
        const previous = achievements.find((entry) => entry.achievementId === achievement.achievementId);
        achievement.unseen = previous?.unseen || (selectedAchievement?.achievementId !== achievement.achievementId ? 1 : 0);

        if (pendingLevel.current?.achievement.achievementId === achievement.achievementId) {
            pendingLevel.current.achievement = achievement;
            return;
        }

        if (isVisible && selectedAchievement?.achievementId === achievement.achievementId && achievement.level > selectedAchievement.level) {
            if (pendingLevel.current) updateAchievement(pendingLevel.current.achievement);
            clearPendingLevel();
            const completed = copyAchievement(selectedAchievement);
            completed.setMaxProgress();
            updateAchievement(completed);
            pendingLevel.current = {
                achievement,
                timeout: setTimeout(() => {
                    updateAchievement(pendingLevel.current.achievement);
                    pendingLevel.current = null;
                }, 2000)
            };
            return;
        }

        updateAchievement(achievement);
    });

    useMessageEvent<AchievementsEvent>(AchievementsEvent, (event) => {
        const parser = event.getParser();
        clearPendingLevel();
        setAchievements(parser.achievements);
        setIsLoaded(true);
        if (isVisible && !selectedCategoryCode && parser.defaultCategory) selectCategory(parser.defaultCategory);
    });

    useMessageEvent<AchievementsScoreEvent>(AchievementsScoreEvent, (event) => setAchievementScore(event.getParser().score));

    useMessageEvent<AuthenticatedEvent>(AuthenticatedEvent, () => {
        clearPendingLevel();
        setAchievements([]);
        setAchievementScore(0);
        setEnabledWiredAchievements([]);
        setIsLoaded(false);
        setIsVisible(false);
        setSelectedCategoryCode(null);
        setSelectedAchievementId(-1);
        SendMessageComposer(new RequestAchievementsMessageComposer());
    });

    useMessageEvent<WiredEnvironmentEvent>(WiredEnvironmentEvent, (event) => setEnabledWiredAchievements(event.getParser().enabledAchievements));

    useOctaneEvent<RoomSessionEvent>(RoomSessionEvent.ENDED, () => {
        setEnabledWiredAchievements([]);
        close();
    });

    useEffect(() => {
        SendMessageComposer(new RequestAchievementsMessageComposer());
        return clearPendingLevel;
    }, [clearPendingLevel]);

    return {
        achievementCategories,
        selectedCategoryCode,
        setSelectedCategoryCode: selectCategory,
        selectedAchievementId,
        setSelectedAchievementId,
        achievementScore,
        getTotalUnseen,
        getProgress,
        getMaxProgress,
        scaledProgressPercent: getMaxProgress ? Math.floor((getProgress / getMaxProgress) * 100) : 0,
        selectedCategory,
        selectedAchievement,
        visibleAchievements,
        hasWiredAchievements: enabledWiredAchievements.length > 0,
        enabledWiredAchievements,
        isLoaded,
        isVisible,
        show,
        close
    };
};

export const useAchievements = () => useSharedHook(useAchievementsState);

registerSharedHook(useAchievementsState);
15Sujets
1Dépôts
20Membres
2En 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