mirror of
https://github.com/CommunityOx/ox_lib.git
synced 2026-08-17 15:06:02 +01:00
Compare commits
7 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8bf225b3d | ||
|
|
1e02469d9a | ||
|
|
4b2446f7a8 | ||
|
|
f33c613b6d | ||
|
|
e66b6805bc | ||
|
|
fdc1674f4f | ||
|
|
c8db003cbc |
14
.github/workflows/release.yml
vendored
14
.github/workflows/release.yml
vendored
@@ -5,6 +5,10 @@ on:
|
|||||||
tags:
|
tags:
|
||||||
- 'v*.*.*'
|
- 'v*.*.*'
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
id-token: write # Required for OIDC
|
||||||
|
contents: write
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
create-release:
|
create-release:
|
||||||
if: github.actor_id != 210085057
|
if: github.actor_id != 210085057
|
||||||
@@ -86,8 +90,12 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
ref: ${{ github.ref_name }}
|
ref: ${{ github.ref_name }}
|
||||||
|
|
||||||
|
|
||||||
|
- name: Setup Node.js
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: '24'
|
||||||
|
|
||||||
- name: Publish package to npm registry
|
- name: Publish package to npm registry
|
||||||
run: bun publish --access public
|
run: npm publish --access public
|
||||||
working-directory: package
|
working-directory: package
|
||||||
env:
|
|
||||||
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ rdr3_warning 'I acknowledge that this is a prerelease build of RedM, and I am aw
|
|||||||
|
|
||||||
name 'ox_lib'
|
name 'ox_lib'
|
||||||
author 'Overextended'
|
author 'Overextended'
|
||||||
version '3.32.2'
|
version '3.32.3'
|
||||||
license 'LGPL-3.0-or-later'
|
license 'LGPL-3.0-or-later'
|
||||||
repository 'https://github.com/communityox/ox_lib'
|
repository 'https://github.com/communityox/ox_lib'
|
||||||
description 'A library of shared functions to utilise in other resources.'
|
description 'A library of shared functions to utilise in other resources.'
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function triggerServerCallback<T = unknown>(
|
|||||||
|
|
||||||
return new Promise<T>((resolve, reject) => {
|
return new Promise<T>((resolve, reject) => {
|
||||||
pendingCallbacks[key] = (args) => {
|
pendingCallbacks[key] = (args) => {
|
||||||
if (args[0] === 'cb_invalid') reject(`callback '${eventName} does not exist`);
|
if (Array.isArray(args) && args[0] === 'cb_invalid') reject(`callback '${eventName} does not exist`);
|
||||||
|
|
||||||
resolve(args);
|
resolve(args);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "@communityox/ox_lib",
|
"name": "@communityox/ox_lib",
|
||||||
"author": "Overextended",
|
"author": "Overextended",
|
||||||
"version": "3.32.2",
|
"version": "3.32.3",
|
||||||
"description": "JS/TS wrapper for ox_lib exports",
|
"description": "JS/TS wrapper for ox_lib exports",
|
||||||
"main": "./shared/index.js",
|
"main": "./shared/index.js",
|
||||||
"types": "./shared/index.d.ts",
|
"types": "./shared/index.d.ts",
|
||||||
@@ -21,10 +21,10 @@
|
|||||||
],
|
],
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "git+https://github.com/communityox/ox_lib.git"
|
"url": "git+https://github.com/CommunityOx/ox_lib.git"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"bugs": {
|
||||||
"url": "https://github.com/communityox/ox_lib/issues"
|
"url": "https://github.com/CommunityOx/ox_lib/issues"
|
||||||
},
|
},
|
||||||
"license": "LGPL-3.0",
|
"license": "LGPL-3.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ export function triggerClientCallback<T = unknown>(
|
|||||||
|
|
||||||
return new Promise<T>((resolve, reject) => {
|
return new Promise<T>((resolve, reject) => {
|
||||||
pendingCallbacks[key] = (args) => {
|
pendingCallbacks[key] = (args) => {
|
||||||
if (args[0] === 'cb_invalid') reject(`callback '${eventName} does not exist`);
|
if (Array.isArray(args) && args[0] === 'cb_invalid') reject(`callback '${eventName} does not exist`);
|
||||||
|
|
||||||
resolve(args);
|
resolve(args);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ local openMenu
|
|||||||
|
|
||||||
---@alias MenuPosition 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
|
---@alias MenuPosition 'top-left' | 'top-right' | 'bottom-left' | 'bottom-right'
|
||||||
---@alias MenuChangeFunction fun(selected: number, scrollIndex?: number, args?: any, checked?: boolean)
|
---@alias MenuChangeFunction fun(selected: number, scrollIndex?: number, args?: any, checked?: boolean)
|
||||||
|
---@alias MenuScrollSelectChangeFunction fun(selected: number, scrollIndex?: number, args?: any)
|
||||||
|
|
||||||
---@class MenuOptions
|
---@class MenuOptions
|
||||||
---@field label string
|
---@field label string
|
||||||
@@ -35,9 +36,9 @@ local openMenu
|
|||||||
---@field disableInput? boolean
|
---@field disableInput? boolean
|
||||||
---@field canClose? boolean
|
---@field canClose? boolean
|
||||||
---@field onClose? fun(keyPressed?: 'Escape' | 'Backspace')
|
---@field onClose? fun(keyPressed?: 'Escape' | 'Backspace')
|
||||||
---@field onSelected? MenuChangeFunction
|
---@field onSelected? MenuScrollSelectChangeFunction
|
||||||
---@field onSideScroll? MenuChangeFunction
|
---@field onSideScroll? MenuScrollSelectChangeFunction
|
||||||
---@field onCheck? MenuChangeFunction
|
---@field onCheck? fun(selected: number, checked: boolean, args?: any)
|
||||||
---@field cb? MenuChangeFunction
|
---@field cb? MenuChangeFunction
|
||||||
|
|
||||||
---@param data MenuProps
|
---@param data MenuProps
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ if cache.game == 'redm' then return end
|
|||||||
---@field model? number
|
---@field model? number
|
||||||
---@field plate? string
|
---@field plate? string
|
||||||
---@field plateIndex? number
|
---@field plateIndex? number
|
||||||
|
---@field lockState? number
|
||||||
---@field bodyHealth? number
|
---@field bodyHealth? number
|
||||||
---@field engineHealth? number
|
---@field engineHealth? number
|
||||||
---@field tankHealth? number
|
---@field tankHealth? number
|
||||||
@@ -202,6 +203,7 @@ function lib.getVehicleProperties(vehicle)
|
|||||||
model = GetEntityModel(vehicle),
|
model = GetEntityModel(vehicle),
|
||||||
plate = GetVehicleNumberPlateText(vehicle),
|
plate = GetVehicleNumberPlateText(vehicle),
|
||||||
plateIndex = GetVehicleNumberPlateTextIndex(vehicle),
|
plateIndex = GetVehicleNumberPlateTextIndex(vehicle),
|
||||||
|
lockState = GetVehicleDoorLockStatus(vehicle),
|
||||||
bodyHealth = math.floor(GetVehicleBodyHealth(vehicle) + 0.5),
|
bodyHealth = math.floor(GetVehicleBodyHealth(vehicle) + 0.5),
|
||||||
engineHealth = math.floor(GetVehicleEngineHealth(vehicle) + 0.5),
|
engineHealth = math.floor(GetVehicleEngineHealth(vehicle) + 0.5),
|
||||||
tankHealth = math.floor(GetVehiclePetrolTankHealth(vehicle) + 0.5),
|
tankHealth = math.floor(GetVehiclePetrolTankHealth(vehicle) + 0.5),
|
||||||
@@ -322,6 +324,10 @@ function lib.setVehicleProperties(vehicle, props, fixVehicle)
|
|||||||
SetVehicleNumberPlateTextIndex(vehicle, props.plateIndex)
|
SetVehicleNumberPlateTextIndex(vehicle, props.plateIndex)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if props.lockState ~= nil then
|
||||||
|
SetVehicleDoorsLocked(vehicle, props.lockState)
|
||||||
|
end
|
||||||
|
|
||||||
if props.bodyHealth then
|
if props.bodyHealth then
|
||||||
SetVehicleBodyHealth(vehicle, props.bodyHealth + 0.0)
|
SetVehicleBodyHealth(vehicle, props.bodyHealth + 0.0)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { useCallback, useEffect, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
import type { SkillCheckProps } from '../../typings';
|
import type { SkillCheckProps } from '../../typings';
|
||||||
import { useInterval } from '@mantine/hooks';
|
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
angle: number;
|
angle: number;
|
||||||
@@ -11,15 +10,58 @@ interface Props {
|
|||||||
handleComplete: (success: boolean) => void;
|
handleComplete: (success: boolean) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Indicator: React.FC<Props> = ({ angle, offset, multiplier, handleComplete, skillCheck, className }) => {
|
const BASE_DURATION_MS = 2000;
|
||||||
|
|
||||||
|
const Indicator: React.FC<Props> = ({
|
||||||
|
angle,
|
||||||
|
offset,
|
||||||
|
multiplier,
|
||||||
|
handleComplete,
|
||||||
|
skillCheck,
|
||||||
|
className,
|
||||||
|
}) => {
|
||||||
const [indicatorAngle, setIndicatorAngle] = useState(-90);
|
const [indicatorAngle, setIndicatorAngle] = useState(-90);
|
||||||
const [keyPressed, setKeyPressed] = useState<false | string>(false);
|
const [keyPressed, setKeyPressed] = useState<false | string>(false);
|
||||||
const interval = useInterval(
|
|
||||||
() =>
|
const rafIdRef = useRef<number | null>(null);
|
||||||
setIndicatorAngle((prevState) => {
|
const startTimeRef = useRef<number | null>(null);
|
||||||
return (prevState += multiplier);
|
const completedRef = useRef(false);
|
||||||
}),
|
|
||||||
1
|
const stopAnimation = () => {
|
||||||
|
if (rafIdRef.current !== null) {
|
||||||
|
cancelAnimationFrame(rafIdRef.current);
|
||||||
|
rafIdRef.current = null;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const animate = useCallback(
|
||||||
|
(time: number) => {
|
||||||
|
if (completedRef.current) return;
|
||||||
|
|
||||||
|
if (startTimeRef.current === null) {
|
||||||
|
startTimeRef.current = time;
|
||||||
|
}
|
||||||
|
|
||||||
|
const elapsed = time - startTimeRef.current;
|
||||||
|
|
||||||
|
const speed = Math.max(multiplier || 0, 0.0001);
|
||||||
|
const duration = BASE_DURATION_MS / speed;
|
||||||
|
|
||||||
|
const progress = Math.min(elapsed / duration, 1);
|
||||||
|
const newAngle = -90 + progress * 360;
|
||||||
|
|
||||||
|
setIndicatorAngle(newAngle);
|
||||||
|
|
||||||
|
if (newAngle + 90 >= 360) {
|
||||||
|
completedRef.current = true;
|
||||||
|
stopAnimation();
|
||||||
|
handleComplete(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
rafIdRef.current = requestAnimationFrame(animate);
|
||||||
|
},
|
||||||
|
[multiplier, handleComplete]
|
||||||
);
|
);
|
||||||
const keyHandler = useCallback(
|
const keyHandler = useCallback(
|
||||||
(e: KeyboardEvent) => {
|
(e: KeyboardEvent) => {
|
||||||
@@ -42,32 +84,43 @@ const Indicator: React.FC<Props> = ({ angle, offset, multiplier, handleComplete,
|
|||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setIndicatorAngle(-90);
|
setIndicatorAngle(-90);
|
||||||
|
startTimeRef.current = null;
|
||||||
|
completedRef.current = false;
|
||||||
|
|
||||||
window.addEventListener('keydown', keyHandler);
|
window.addEventListener('keydown', keyHandler);
|
||||||
interval.start();
|
rafIdRef.current = requestAnimationFrame(animate);
|
||||||
}, [skillCheck]);
|
|
||||||
|
return () => {
|
||||||
|
stopAnimation();
|
||||||
|
window.removeEventListener('keydown', keyHandler);
|
||||||
|
startTimeRef.current = null;
|
||||||
|
completedRef.current = true;
|
||||||
|
};
|
||||||
|
}, [skillCheck, keyHandler, animate]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (indicatorAngle + 90 >= 360) {
|
if (!keyPressed || completedRef.current) return;
|
||||||
interval.stop();
|
|
||||||
handleComplete(false);
|
|
||||||
}
|
|
||||||
}, [indicatorAngle]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
if (!keyPressed) return;
|
|
||||||
|
|
||||||
if (skillCheck.keys && !skillCheck.keys?.includes(keyPressed)) return;
|
if (skillCheck.keys && !skillCheck.keys?.includes(keyPressed)) return;
|
||||||
|
|
||||||
interval.stop();
|
stopAnimation();
|
||||||
|
|
||||||
window.removeEventListener('keydown', keyHandler);
|
window.removeEventListener('keydown', keyHandler);
|
||||||
|
completedRef.current = true;
|
||||||
|
|
||||||
if (keyPressed !== skillCheck.key || indicatorAngle < angle || indicatorAngle > angle + offset)
|
if (keyPressed !== skillCheck.key || indicatorAngle < angle || indicatorAngle > angle + offset)
|
||||||
handleComplete(false);
|
handleComplete(false);
|
||||||
else handleComplete(true);
|
else handleComplete(true);
|
||||||
|
|
||||||
setKeyPressed(false);
|
setKeyPressed(false);
|
||||||
}, [keyPressed]);
|
}, [
|
||||||
|
keyPressed,
|
||||||
|
angle,
|
||||||
|
offset,
|
||||||
|
indicatorAngle,
|
||||||
|
skillCheck,
|
||||||
|
keyHandler,
|
||||||
|
handleComplete,
|
||||||
|
]);
|
||||||
|
|
||||||
return <circle transform={`rotate(${indicatorAngle}, 250, 250)`} className={className} />;
|
return <circle transform={`rotate(${indicatorAngle}, 250, 250)`} className={className} />;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user