From 6264bbcbc90bbc7fe003921204abb99b3c3515e8 Mon Sep 17 00:00:00 2001 From: Luke Date: Tue, 18 Oct 2022 17:59:02 +0200 Subject: [PATCH] refactor(skillcheck): move array handling into ui --- resource/interface/client/skillcheck.lua | 54 ++++---------------- web/src/features/skillcheck/index.tsx | 42 +++++++++++++--- web/src/features/skillcheck/indicator.tsx | 61 ++++++++++++++--------- 3 files changed, 82 insertions(+), 75 deletions(-) diff --git a/resource/interface/client/skillcheck.lua b/resource/interface/client/skillcheck.lua index 9dc1a90..cbae068 100644 --- a/resource/interface/client/skillcheck.lua +++ b/resource/interface/client/skillcheck.lua @@ -1,62 +1,28 @@ ---@type promise? local skillcheck -local gameCount = 0 ---@alias SkillCheckDifficulity 'easy' | 'medium' | 'hard' | { areaSize: number, speedMultiplier: number } ----@type SkillCheckDifficulity | SkillCheckDifficulity[] -local gameDifficulty - ----@type promise? -local gamePromise - -local function resolveSkillCheck(success) - if skillcheck then - skillcheck:resolve(success) - skillcheck = nil - SetNuiFocus(false, false) - end -end - ---@param difficulty SkillCheckDifficulity | SkillCheckDifficulity[] ---@return boolean? function lib.skillCheck(difficulty) if skillcheck then return end - skillcheck = promise:new() - gameDifficulty = difficulty - SetNuiFocus(true, false) - if type(difficulty) == 'table' then - gameCount = 0 - for i = 1, #difficulty do - gamePromise = promise:new() - SendNUIMessage({ - action = 'startSkillCheck', - data = difficulty[i] - }) - if not Citizen.Await(gamePromise) then - gamePromise = nil - break - end - end - else - SendNUIMessage({ - action = 'startSkillCheck', - data = difficulty - }) - end + SetNuiFocus(true, false) + SendNUIMessage({ + action = 'startSkillCheck', + data = difficulty + }) return Citizen.Await(skillcheck) end -RegisterNUICallback('skillCheckOver', function(data, cb) +RegisterNUICallback('skillCheckOver', function(success, cb) cb(1) - if not gamePromise then return resolveSkillCheck(data.success) end - gamePromise:resolve(data.success) - if not data.success then return resolveSkillCheck(data.success) end - gameCount += 1 - if gameCount == #gameDifficulty then - resolveSkillCheck(data.success) + if skillcheck then + skillcheck:resolve(success) + skillcheck = nil + SetNuiFocus(false, false) end end) diff --git a/web/src/features/skillcheck/index.tsx b/web/src/features/skillcheck/index.tsx index d4b9a99..93833cf 100644 --- a/web/src/features/skillcheck/index.tsx +++ b/web/src/features/skillcheck/index.tsx @@ -1,8 +1,9 @@ import { Box, Center } from '@chakra-ui/react'; -import { useEffect, useMemo, useState } from 'react'; +import { useEffect, useMemo, useRef, useState } from 'react'; import { useNuiEvent } from '../../hooks/useNuiEvent'; import { debugData } from '../../utils/debugData'; import Indicator from './indicator'; +import { fetchNui } from '../../utils/fetchNui'; interface CustomGameDifficulty { areaSize: number; @@ -28,27 +29,54 @@ const difficultyOffsets = { debugData([ { action: 'startSkillCheck', - data: 'easy', + data: [{ areaSize: 250, speedMultiplier: 2 }, 'easy'], }, ]); const SkillCheck: React.FC = () => { const [visible, setVisible] = useState(false); + const dataRef = useRef(null); + const dataIndexRef = useRef(0); const [skillCheck, setSkillCheck] = useState({ angle: 0, difficultyOffset: 315, difficulty: 'easy', }); - useNuiEvent('startSkillCheck', (data: GameDifficulty) => { + useNuiEvent('startSkillCheck', (data: GameDifficulty | GameDifficulty[]) => { + dataRef.current = data; + dataIndexRef.current = 0; + const gameData = Array.isArray(data) ? data[0] : data; + const offset = typeof gameData === 'object' ? gameData.areaSize : difficultyOffsets[gameData]; + setSkillCheck({ + angle: -90 + getRandomAngle(120, 360 - (315 - offset)), + difficultyOffset: offset, + difficulty: gameData, + }); + + setVisible(true); + }); + + const handleComplete = (success: boolean) => { + if (!success || !Array.isArray(dataRef.current)) { + setVisible(false); + return fetchNui('skillCheckOver', success); + } + + if (dataIndexRef.current >= dataRef.current.length - 1) { + setVisible(false); + return fetchNui('skillCheckOver', success); + } + + dataIndexRef.current++; + const data = dataRef.current[dataIndexRef.current]; const offset = typeof data === 'object' ? data.areaSize : difficultyOffsets[data]; setSkillCheck({ angle: -90 + getRandomAngle(120, 360 - (315 - offset)), difficultyOffset: offset, difficulty: data, }); - setVisible(true); - }); + }; return (
@@ -89,8 +117,8 @@ const SkillCheck: React.FC = () => { ? 1.75 : skillCheck.difficulty.speedMultiplier } - setSkillCheck={setSkillCheck} - setVisible={setVisible} + handleComplete={handleComplete} + skillCheck={skillCheck} /> >; - setSkillCheck: React.Dispatch>; + skillCheck: SkillCheckProps; + handleComplete: (success: boolean) => void; } -const Indicator: React.FC = ({ angle, offset, multiplier, setSkillCheck, setVisible }) => { +const Indicator: React.FC = ({ angle, offset, multiplier, handleComplete, skillCheck }) => { const [indicatorAngle, setIndicatorAngle] = useState(-90); - const intervalRef = useRef(null); + const [gameState, setGameState] = useState(false); const isKeyPressed = useKeyPress('e'); - useEffect(() => { - intervalRef.current = setInterval(() => { - setIndicatorAngle((prevState) => (prevState += multiplier)); - }, 1); - - return () => { - if (intervalRef.current) clearInterval(intervalRef.current); - }; - }, []); + useInterval( + () => { + setIndicatorAngle((prevState) => { + return (prevState += multiplier); + }); + }, + gameState ? 1 : null + ); useEffect(() => { - if (intervalRef.current && indicatorAngle + 90 >= 360) { - clearInterval(intervalRef.current); - fetchNui('skillCheckOver', { success: false }); - setVisible(false); + setIndicatorAngle(-90); + setGameState(true); + }, [skillCheck]); + + useEffect(() => { + if (indicatorAngle + 90 >= 360) { + // fetchNui('skillCheckOver', { success: false }); + setGameState(false); + handleComplete(false); } + }, [indicatorAngle]); - if (isKeyPressed && intervalRef.current) { - clearInterval(intervalRef.current); + useEffect(() => { + if (!isKeyPressed) return; + // + + setGameState(false); + if (isKeyPressed) { if (indicatorAngle < angle || indicatorAngle > angle + (315 - offset)) { - fetchNui('skillCheckOver', { success: false }); + // fetchNui('skillCheckOver', { success: false }); + handleComplete(false); } else { - fetchNui('skillCheckOver', { success: true }); + // fetchNui('skillCheckOver', { success: true }); + handleComplete(true); } - setVisible(false); } - }, [indicatorAngle, isKeyPressed]); + }, [isKeyPressed]); return (