28 Commits

Author SHA1 Message Date
github-actions
88c68c7068 chore: bump version to v3.31.2 2025-08-18 11:45:57 +00:00
PaPi
1e178180bb chore(locales): update fr.json (#38) 2025-08-18 13:45:14 +02:00
Zoo
fef441c456 feat(package/addKeybind): add keybind to ts package (#39) 2025-08-18 13:30:43 +02:00
github-actions
85a3879a03 chore: bump version to v3.31.1 2025-08-12 14:45:04 +00:00
mikigoalie
65813e75e6 feat(imports/table): add table.map (#35) 2025-08-12 16:42:57 +02:00
David Malchin
a9648fb45f fix(points): grid inconsistencies (#37) 2025-08-10 02:20:46 +02:00
github-actions
dec6caa63b chore: bump version to v3.31.0 2025-07-26 17:59:55 +00:00
mikigoalie
967682c449 fix(web/notifications): bottom center position (#33) 2025-07-26 16:07:52 +02:00
Luca
301ff2daf8 feat(interface/input): add size to input dialog options (#32) 2025-07-26 14:34:01 +02:00
ANTOND.
fd8d65166b fix(interface/input): add min and max length props to input type (#31) 2025-07-23 17:10:57 +02:00
ANTOND.
581640c07a feat(web/dialog/textarea): add min and max length (#30) 2025-07-15 21:51:52 +02:00
Mustafa Burak Güneş
9fbf0222ad fix(resource/cache): skip cache updates during ped transitions (#28)
also fixes an issue with cache not being set correctly when weapon hash is a negative number
2025-07-09 18:59:19 +02:00
Laica Lunasys
753d3eb025 chore: use nativewrappers/fivem instead of client (#25) 2025-06-30 15:59:34 +02:00
andreutu
815caddb02 fix(client/interface): add missing warning notify type in npm package (#23) 2025-06-08 15:01:32 +02:00
github-actions
3c5d5faa9f chore: bump version to v3.30.10 2025-05-29 11:17:05 +00:00
uShifty
ae640729ca fix(shared): Improper import of context (#18) 2025-05-27 11:18:45 +02:00
github-actions
3c405250b0 chore: bump version to v3.30.9 2025-05-18 13:25:19 +00:00
ANTOND.
7375e4054d docs: update cfxlua extension url (#16) 2025-05-18 14:45:54 +02:00
ANTOND.
22b3600a14 fix(web): re-apply patch for react-hot-toast (#13) 2025-05-18 14:32:22 +02:00
github-actions
b5fdd8a160 chore: bump version to v3.30.8 2025-05-15 22:26:37 +00:00
Edward
ba790f9830 feat(imports/getClosestPlayer): Implement ignorePlayerId on the server (#11)
Co-authored-by: Edward <24864616+Edward-Bakker@users.noreply.github.com>
2025-05-07 20:40:33 +02:00
Mats
9ec43862a2 chore(locales): update norwegian translation (#10) 2025-05-05 05:56:38 +02:00
ANTOND.
2d2575963d ci(create-release): bump version before running build script (#9) 2025-05-04 20:03:35 +02:00
uShifty
8039539158 feat(package/getNearbyVehicles): Implement getNearbyVehicles (#8) 2025-05-04 18:00:08 +02:00
Sergio
f59beb2af6 feat(imports/marker): Added invert property (#4)
MarkerType alias was replaced for an enum.
The type property in MarkerProps class is now optional, MarkerType or an integer (UpsideDownCone if missing).
The properties inside color are now defined as integers.
Added invert property, documented by CFX as drawOnEnts.
Added marker_mt metatable that stores default properties and draw method.

Signed-off-by: Sergio <89666307+feelfreetofee@users.noreply.github.com>
2025-05-04 17:59:18 +02:00
Zoo
ab0dac8fde chore(package/interface): add label to progressCircle (#2) 2025-05-04 17:59:02 +02:00
Zoo
4491ad3599 fix(zones/shared): ensure safe removal of zones from entering and exiting lists (#1)
Co-authored-by: toshko <toshko0003@gmail.com>
2025-05-04 17:58:50 +02:00
ANTOND.
a9728663ca ci(create-release): use github app token 2025-05-04 01:50:09 +02:00
32 changed files with 647 additions and 456 deletions

View File

@@ -1,10 +1,8 @@
const fs = require('fs'); const fxManifest = await Bun.file('./fxmanifest.lua').text();
const version = process.env.TGT_RELEASE_VERSION; let newVersion = process.env.TGT_RELEASE_VERSION;
const newVersion = version.replace('v', ''); newVersion = newVersion.replace('v', '')
const manifestFile = fs.readFileSync('fxmanifest.lua', { encoding: 'utf8' }); const newFileContent = fxManifest.replace(/\bversion\s+(.*)$/gm, `version '${newVersion}'`);
const newFileContent = manifestFile.replace(/\bversion\s+(.*)$/gm, `version '${newVersion}'`); await Bun.write('./fxmanifest.lua', newFileContent);
fs.writeFileSync('fxmanifest.lua', newFileContent);

View File

@@ -1,10 +1,6 @@
const fs = require('fs'); const packageJson = await Bun.file('./package/package.json').json();
const version = process.env.TGT_RELEASE_VERSION; const newVersion = process.env.TGT_RELEASE_VERSION;
const newVersion = version.replace('v', ''); packageJson.version = newVersion.replace('v', '');
const packageFile = fs.readFileSync('package/package.json', { encoding: 'utf8' }); await Bun.write('./package/package.json', JSON.stringify(packageJson, null, 2));
const newFileContent = packageFile.replace(/"version":\s+"(.*)",$/gm, `"version": "${newVersion}",`);
fs.writeFileSync('package/package.json', newFileContent);

View File

@@ -7,44 +7,43 @@ on:
jobs: jobs:
create-release: create-release:
if: github.actor_id != 210085057
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Get latest code - name: Install zip
uses: actions/checkout@v4 run: sudo apt install zip
with:
fetch-depth: 0
ref: ${{ github.event.repository.default_branch }}
- name: Setup Bun - name: Install Bun
uses: oven-sh/setup-bun@v2 uses: oven-sh/setup-bun@v2
with: with:
bun-version: latest bun-version: latest
- name: Install package dependencies - name: Generate GitHub App token
run: bun install id: app_token
working-directory: package uses: tibdex/github-app-token@v2
with:
app_id: ${{ secrets.APP_ID }}
private_key: ${{ secrets.APP_PRIVATE_KEY }}
- name: Install web dependencies - name: Get latest code
run: bun install uses: actions/checkout@v4
working-directory: web with:
fetch-depth: 0
- name: Run web build script ref: ${{ github.event.repository.default_branch }}
run: bun run build token: ${{ steps.app_token.outputs.token }}
working-directory: web
- name: Bump package version - name: Bump package version
run: bun .github/actions/bump-package-version.js run: bun run .github/actions/bump-package-version.js
env: env:
TGT_RELEASE_VERSION: ${{ github.ref_name }} TGT_RELEASE_VERSION: ${{ github.ref_name }}
- name: Bump manifest version - name: Bump manifest version
run: bun .github/actions/bump-manifest-version.js run: bun run .github/actions/bump-manifest-version.js
env: env:
TGT_RELEASE_VERSION: ${{ github.ref_name }} TGT_RELEASE_VERSION: ${{ github.ref_name }}
- name: Push version bump change - name: Push version bump change
uses: EndBug/add-and-commit@v9 uses: EndBug/add-and-commit@v9
with: with:
@@ -53,25 +52,23 @@ jobs:
default_author: github_actions default_author: github_actions
message: 'chore: bump version to ${{ github.ref_name }}' message: 'chore: bump version to ${{ github.ref_name }}'
- name: Update tag
uses: EndBug/latest-tag@v1
with:
ref: ${{ github.ref_name }}
- name: Install package dependencies
- name: Publish package to npm registry run: bun install --frozen-lockfile
run: bun publish --access public
working-directory: package working-directory: package
env:
NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Install zip - name: Install web dependencies
run: sudo apt install zip run: bun install --frozen-lockfile
working-directory: web
- name: Run web build script
run: bun run build
working-directory: web
- name: Bundle files - name: Bundle files
run: | run: |
mkdir -p ./temp/ox_lib mkdir -p ./temp/ox_lib/web
mkdir -p ./temp/ox_lib/web/
cp ./{LICENSE,README.md,fxmanifest.lua,init.lua} ./temp/ox_lib cp ./{LICENSE,README.md,fxmanifest.lua,init.lua} ./temp/ox_lib
cp -r ./{imports,resource,locales} ./temp/ox_lib cp -r ./{imports,resource,locales} ./temp/ox_lib
cp -r ./web/build ./temp/ox_lib/web/ cp -r ./web/build ./temp/ox_lib/web/
@@ -79,11 +76,18 @@ jobs:
- name: Create release - name: Create release
uses: 'marvinpinto/action-automatic-releases@v1.2.1' uses: 'marvinpinto/action-automatic-releases@v1.2.1'
id: auto_release
with: with:
repo_token: ${{ secrets.GITHUB_TOKEN }} repo_token: ${{ secrets.GITHUB_TOKEN }}
prerelease: false prerelease: false
files: ox_lib.zip files: ox_lib.zip
- name: Update tag
uses: EndBug/latest-tag@v1
with:
ref: ${{ github.ref_name }}
- name: Publish package to npm registry
run: bun publish --access public
working-directory: package
env: env:
CI: false NPM_CONFIG_TOKEN: ${{ secrets.NPM_TOKEN }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -27,6 +27,6 @@ https://www.npmjs.com/package/@communityox/ox_lib
## 🖥️ Lua Language Server ## 🖥️ Lua Language Server
- Install [Lua Language Server](https://marketplace.visualstudio.com/items?itemName=sumneko.lua) to ease development with annotations, type checking, diagnostics, and more. - Install [Lua Language Server](https://marketplace.visualstudio.com/items?itemName=sumneko.lua) to ease development with annotations, type checking, diagnostics, and more.
- Install [cfxlua-vscode](https://marketplace.visualstudio.com/items?itemName=communityox.cfxlua-vscode) to add natives and cfxlua runtime declarations to LLS. - Install [CfxLua IntelliSense](https://marketplace.visualstudio.com/items?itemName=communityox.cfxlua-vscode-cox) to add natives and cfxlua runtime declarations to LLS.
- You can load ox_lib into your global development environment by modifying workspace/user settings "Lua.workspace.library" with the resource path. - You can load ox_lib into your global development environment by modifying workspace/user settings "Lua.workspace.library" with the resource path.
- e.g. "c:/fxserver/resources/ox_lib" - e.g. "c:/fxserver/resources/ox_lib"

View File

@@ -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.30.7' version '3.31.2'
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.'

View File

@@ -8,16 +8,19 @@
---@param coords vector3 The coords to check from. ---@param coords vector3 The coords to check from.
---@param maxDistance? number The max distance to check. ---@param maxDistance? number The max distance to check.
---@param ignorePlayerId? number|false The player server ID to ignore.
---@return number? playerId ---@return number? playerId
---@return number? playerPed ---@return number? playerPed
---@return vector3? playerCoords ---@return vector3? playerCoords
function lib.getClosestPlayer(coords, maxDistance) function lib.getClosestPlayer(coords, maxDistance, ignorePlayerId)
local players = GetActivePlayers() local players = GetActivePlayers()
local closestId, closestPed, closestCoords local closestId, closestPed, closestCoords
maxDistance = maxDistance or 2.0 maxDistance = maxDistance or 2.0
for i = 1, #players do for i = 1, #players do
local playerId = players[i] local playerId = players[i]
if not ignorePlayerId or playerId ~= ignorePlayerId then
local playerPed = GetPlayerPed(playerId) local playerPed = GetPlayerPed(playerId)
local playerCoords = GetEntityCoords(playerPed) local playerCoords = GetEntityCoords(playerPed)
local distance = #(coords - playerCoords) local distance = #(coords - playerCoords)
@@ -29,6 +32,7 @@ function lib.getClosestPlayer(coords, maxDistance)
closestCoords = playerCoords closestCoords = playerCoords
end end
end end
end
return closestId, closestPed, closestCoords return closestId, closestPed, closestCoords
end end

View File

@@ -9,14 +9,8 @@
---@diagnostic disable: param-type-mismatch ---@diagnostic disable: param-type-mismatch
lib.marker = {} lib.marker = {}
local defaultRotation = vector3(0, 0, 0) ---@enum (key) MarkerType
local defaultDirection = vector3(0, 0, 0) local markerTypes = {
local defaultColor = { r = 255, g = 255, b = 255, a = 100 }
local defaultSize = { width = 2, height = 1 }
local defaultTextureDict = nil
local defaultTextureName = nil
local markerTypesMap = {
UpsideDownCone = 0, UpsideDownCone = 0,
VerticalCylinder = 1, VerticalCylinder = 1,
ThickChevronUp = 2, ThickChevronUp = 2,
@@ -63,58 +57,12 @@ local markerTypesMap = {
Unknown43 = 43, Unknown43 = 43,
} }
---@alias MarkerType
---| "UpsideDownCone"
---| "VerticalCylinder"
---| "ThickChevronUp"
---| "ThinChevronUp"
---| "CheckeredFlagRect"
---| "CheckeredFlagCircle"
---| "VerticleCircle"
---| "PlaneModel"
---| "LostMCTransparent"
---| "LostMC"
---| "Number0"
---| "Number1"
---| "Number2"
---| "Number3"
---| "Number4"
---| "Number5"
---| "Number6"
---| "Number7"
---| "Number8"
---| "Number9"
---| "ChevronUpx1"
---| "ChevronUpx2"
---| "ChevronUpx3"
---| "HorizontalCircleFat"
---| "ReplayIcon"
---| "HorizontalCircleSkinny"
---| "HorizontalCircleSkinny_Arrow"
---| "HorizontalSplitArrowCircle"
---| "DebugSphere"
---| "DollarSign"
---| "HorizontalBars"
---| "WolfHead"
---| "QuestionMark"
---| "PlaneSymbol"
---| "HelicopterSymbol"
---| "BoatSymbol"
---| "CarSymbol"
---| "MotorcycleSymbol"
---| "BikeSymbol"
---| "TruckSymbol"
---| "ParachuteSymbol"
---| "Unknown41"
---| "SawbladeSymbol"
---| "Unknown43"
---@class MarkerProps ---@class MarkerProps
---@field type MarkerType | number ---@field type? MarkerType | integer
---@field coords { x: number, y: number, z: number } ---@field coords { x: number, y: number, z: number }
---@field width? number ---@field width? number
---@field height? number ---@field height? number
---@field color? { r: number, g: number, b: number, a: number } ---@field color? { r: integer, g: integer, b: integer, a: integer }
---@field rotation? { x: number, y: number, z: number } ---@field rotation? { x: number, y: number, z: number }
---@field direction? { x: number, y: number, z: number } ---@field direction? { x: number, y: number, z: number }
---@field bobUpAndDown? boolean ---@field bobUpAndDown? boolean
@@ -122,9 +70,25 @@ local markerTypesMap = {
---@field rotate? boolean ---@field rotate? boolean
---@field textureDict? string ---@field textureDict? string
---@field textureName? string ---@field textureName? string
---@field invert? boolean
---@param self MarkerProps local vector3_zero = vector3(0, 0, 0)
local function drawMarker(self)
local marker_mt = {
type = 0,
width = 2.,
height = 1.,
color = {r = 255, g = 100, b = 0, a = 100},
rotation = vector3_zero,
direction = vector3_zero,
bobUpAndDown = false,
faceCamera = false,
rotate = false,
invert = false,
}
marker_mt.__index = marker_mt
function marker_mt:draw()
DrawMarker( DrawMarker(
self.type, self.type,
self.coords.x, self.coords.y, self.coords.z, self.coords.x, self.coords.y, self.coords.z,
@@ -132,40 +96,19 @@ local function drawMarker(self)
self.rotation.x, self.rotation.y, self.rotation.z, self.rotation.x, self.rotation.y, self.rotation.z,
self.width, self.width, self.height, self.width, self.width, self.height,
self.color.r, self.color.g, self.color.b, self.color.a, self.color.r, self.color.g, self.color.b, self.color.a,
self.bobUpAndDown, self.faceCamera, 2, self.rotate, self.textureDict, self.textureName, false) self.bobUpAndDown, self.faceCamera, 2, self.rotate, self.textureDict, self.textureName, self.invert)
end end
---@param options MarkerProps ---@param options MarkerProps
function lib.marker.new(options) function lib.marker.new(options)
local markerType options.type =
if type(options.type) == "string" then type(options.type) == 'string' and markerTypes[options.type]
markerType = markerTypesMap[options.type] or type(options.type) == 'number' and options.type or nil
if markerType == nil then
error(("unknown marker type '%s'"):format(options.type))
end
elseif type(options.type) == "number" then
markerType = options.type
else
error(("expected marker type to have type 'string' or 'number' (received %s)"):format(type(options.type)))
end
local self = {} local self = setmetatable(options, marker_mt)
self.type = markerType
self.coords = options.coords
self.color = options.color or defaultColor
self.width = options.width or defaultSize.width
self.height = options.height or defaultSize.height
self.rotation = options.rotation or defaultRotation
self.direction = options.direction or defaultDirection
self.bobUpAndDown = type(options.bobUpAndDown) == 'boolean' and options.bobUpAndDown
self.faceCamera = type(options.faceCamera) ~= 'boolean' or options.faceCamera
self.rotate = type(options.rotate) == 'boolean' and options.rotate
self.textureDict = options.textureDict or defaultTextureDict
self.textureName = options.textureName or defaultTextureName
self.draw = drawMarker
self.width += 0.0 self.width += .0
self.height += 0.0 self.height += .0
return self return self
end end

View File

@@ -39,10 +39,14 @@ local function removePoint(self)
points[self.id] = nil points[self.id] = nil
end end
local function hasRemovePoint(entry)
return entry.remove == removePoint
end
CreateThread(function() CreateThread(function()
while true do while true do
local coords = GetEntityCoords(cache.ped) local coords = GetEntityCoords(cache.ped)
local newPoints = lib.grid.getNearbyEntries(coords, function(entry) return entry.remove == removePoint end) --[[@as CPoint[] ]] local newPoints = lib.grid.getNearbyEntries(coords, hasRemovePoint) --[[@as CPoint[] ]]
local cellX, cellY = lib.grid.getCellPosition(coords) local cellX, cellY = lib.grid.getCellPosition(coords)
cache.coords = coords cache.coords = coords
closestPoint = nil closestPoint = nil
@@ -89,10 +93,12 @@ CreateThread(function()
nearbyCount += 1 nearbyCount += 1
nearbyPoints[nearbyCount] = point nearbyPoints[nearbyCount] = point
if point.onEnter and not point.inside then if not point.inside then
point.inside = true point.inside = true
if point.onEnter then
point:onEnter() point:onEnter()
end end
end
elseif point.currentDistance then elseif point.currentDistance then
if point.onExit then point:onExit() end if point.onExit then point:onExit() end

View File

@@ -123,11 +123,24 @@ local function shuffle(tbl)
return tbl return tbl
end end
---@param tbl table
---@param fn function(value: any, key: any): any
---@return table
local function map(tbl, fn)
local result = {}
for k, v in pairs(tbl) do
result[k] = fn(v, k)
end
return result
end
table.contains = contains table.contains = contains
table.matches = table_matches table.matches = table_matches
table.deepclone = table_deepclone table.deepclone = table_deepclone
table.merge = table_merge table.merge = table_merge
table.shuffle = shuffle table.shuffle = shuffle
table.map = map
local frozenNewIndex = function(self) error(('cannot set values on a frozen table (%s)'):format(self), 2) end local frozenNewIndex = function(self) error(('cannot set values on a frozen table (%s)'):format(self), 2) end
local _rawset = rawset local _rawset = rawset

View File

@@ -122,8 +122,15 @@ local function removeZone(zone)
insideZones[zone.id] = nil insideZones[zone.id] = nil
table.remove(exitingZones, exitingZones:indexOf(zone)) local exitingIndex = exitingZones:indexOf(zone)
table.remove(enteringZones, enteringZones:indexOf(zone)) if exitingIndex then
table.remove(exitingZones, exitingIndex)
end
local enteringIndex = enteringZones:indexOf(zone)
if enteringIndex then
table.remove(enteringZones, enteringIndex)
end
end end
CreateThread(function() CreateThread(function()

View File

@@ -7,27 +7,27 @@
"confirm": "Confirmer", "confirm": "Confirmer",
"more": "Plus...", "more": "Plus...",
"settings": { "settings": {
"locale": "Change locale", "locale": "Changer la langue",
"locale_description": "Current language: ${language} (%s)", "locale_description": "Langue actuelle : ${language} (%s)",
"notification_audio": "Notification audio", "notification_audio": "Audio des notifications",
"notification_position": "Notification position" "notification_position": "Position des notifications"
}, },
"position": { "position": {
"bottom": "Bottom", "bottom": "Bas",
"bottom-left": "Bottom-left", "bottom-left": "Bas-gauche",
"bottom-right": "Bottom-right", "bottom-right": "Bas-droite",
"center-left": "Center-left", "center-left": "Centre-gauche",
"center-right": "Center-right", "center-right": "Centre-droite",
"top": "Top", "top": "Haut",
"top-left": "Top-left", "top-left": "Haut-gauche",
"top-right": "Top-right" "top-right": "Haut-droite"
} }
}, },
"open_radial_menu": "Open radial menu", "open_radial_menu": "Ouvrir le menu radial",
"cancel_progress": "Cancel current progress bar", "cancel_progress": "Annuler la barre de progression actuelle",
"txadmin_announcement": "Server announcement by %s", "txadmin_announcement": "Annonce serveur par %s",
"txadmin_dm": "Direct Message from %s", "txadmin_dm": "Message privé de %s",
"txadmin_warn": "You have been warned by %s", "txadmin_warn": "Vous avez été averti par %s",
"txadmin_warn_content": "%s \nAction ID: %s", "txadmin_warn_content": "%s\nID de l'action : %s",
"txadmin_scheduledrestart": "Scheduled Restart" "txadmin_scheduledrestart": "Redémarrage programmé"
} }

View File

@@ -9,25 +9,25 @@
"settings": { "settings": {
"locale": "Endre språk", "locale": "Endre språk",
"locale_description": "Nåværende språk: ${language} (%s)", "locale_description": "Nåværende språk: ${language} (%s)",
"notification_audio": "Varslings lyd", "notification_audio": "Varslingslyd",
"notification_position": "Varslings posisjon" "notification_position": "Varslingsposisjon"
}, },
"position": { "position": {
"bottom": "Bunn", "bottom": "Nederst",
"bottom-left": "Bunn-venstre", "bottom-left": "Nederst til venstre",
"bottom-right": "Bunn-høyre", "bottom-right": "Nederst til høyre",
"center-left": "Senter-venstre", "center-left": "Midten venstre",
"center-right": "Senter-høyre", "center-right": "Midten høyre",
"top": "Top", "top": "Øverst",
"top-left": "Top-venstre", "top-left": "Øverst til venstre",
"top-right": "Top-høyre" "top-right": "Øverst til høyre"
} }
}, },
"open_radial_menu": "Åpne radial menyen", "open_radial_menu": "Åpne radialmenyen",
"cancel_progress": "Avbryt den nåværende progresjonsbaren", "cancel_progress": "Avbryt den nåværende progresjonsbaren",
"txadmin_announcement": "Server annonsering fra %s", "txadmin_announcement": "Serverannonsering fra %s",
"txadmin_dm": "Direktemelding fra %s", "txadmin_dm": "Direktemelding fra %s",
"txadmin_warn": "Du har fått en advarsel fra %s", "txadmin_warn": "Du har fått en advarsel fra %s",
"txadmin_warn_content": "%s \nAction ID: %s", "txadmin_warn_content": "%s \nAction ID: %s",
"txadmin_scheduledrestart": "Planlagt Omstart" "txadmin_scheduledrestart": "Planlagt omstart"
} }

View File

@@ -4,7 +4,7 @@
"": { "": {
"name": "@communityox/ox_lib", "name": "@communityox/ox_lib",
"dependencies": { "dependencies": {
"@nativewrappers/client": "^1.7.33", "@nativewrappers/fivem": "^0.0.103",
"csstype": "^3.1.3", "csstype": "^3.1.3",
"fast-printf": "^1.6.9", "fast-printf": "^1.6.9",
"typescript": "^5.4.2", "typescript": "^5.4.2",
@@ -97,7 +97,7 @@
"@mantine/utils": ["@mantine/utils@6.0.22", "", { "peerDependencies": { "react": ">=16.8.0" } }, "sha512-RSKlNZvxhMCkOFZ6slbYvZYbWjHUM+PxDQnupIOxIdsTZQQjx/BFfrfJ7kQFOP+g7MtpOds8weAetEs5obwMOQ=="], "@mantine/utils": ["@mantine/utils@6.0.22", "", { "peerDependencies": { "react": ">=16.8.0" } }, "sha512-RSKlNZvxhMCkOFZ6slbYvZYbWjHUM+PxDQnupIOxIdsTZQQjx/BFfrfJ7kQFOP+g7MtpOds8weAetEs5obwMOQ=="],
"@nativewrappers/client": ["@nativewrappers/client@1.7.33", "", {}, "sha512-phuBBGdDPxZiZyw5CaFs1XWfvllnEtwATMdLaNucwMofVg/O/FjlP1bTUq4SOm4qhSZ4Zdo351ijHzBSIbZs6g=="], "@nativewrappers/fivem": ["@nativewrappers/fivem@0.0.103", "", {}, "sha512-x0W00Mx9ZN/rTS9XZc5Kf1hjahqRmlo9sPiuJP4kCYeQG4LDJyglXCsHcfNfygGq6WEblG1W2FLgm4MGDn/wHA=="],
"@radix-ui/number": ["@radix-ui/number@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA=="], "@radix-ui/number": ["@radix-ui/number@1.0.0", "", { "dependencies": { "@babel/runtime": "^7.13.10" } }, "sha512-Ofwh/1HX69ZfJRiRBMTy7rgjAzHmwe4kW9C9Y99HTRUcYLUuVT0KESFj15rPjRgKJs20GPq8Bm5aEDJ8DuA3vA=="],

View File

@@ -0,0 +1,120 @@
interface CKeybind extends KeybindProps {
currentKey: string;
disabled: boolean;
isPressed: boolean;
hash: number;
getCurrentKey(): string;
isControlPressed(): boolean;
}
interface KeybindProps {
name: string;
description: string;
defaultMapper?: string;
defaultKey?: string;
disabled?: boolean;
disable?(this: CKeybind, toggle: boolean): void;
onPressed?(this: CKeybind): void;
onReleased?(this: CKeybind): void;
[key: string]: any;
}
const keybinds: Record<string, CKeybind> = {};
class Keybind implements CKeybind {
name: string;
description: string;
defaultMapper?: string;
defaultKey?: string;
onPressed?: (this: CKeybind) => void;
onReleased?: (this: CKeybind) => void;
secondaryKey?: string;
secondaryMapper?: string;
[key: string]: any;
disabled: boolean = false;
isPressed: boolean = false;
hash: number;
constructor(data: KeybindProps) {
this.name = data.name;
this.description = data.description;
this.defaultMapper = data.defaultMapper ?? "keyboard";
this.defaultKey = data.defaultKey ?? "";
this.secondaryKey = data.secondaryKey;
this.secondaryMapper = data.secondaryMapper;
if (typeof data.disabled === "boolean") this.disabled = data.disabled;
this.onPressed = data.onPressed;
this.onReleased = data.onReleased;
this.hash = GetHashKey("+" + this.name) | 0x80000000;
}
get currentKey(): string {
return this.getCurrentKey();
}
getCurrentKey(): string {
const label = GetControlInstructionalButton(0, this.hash, true);
return label.substring(2);
}
isControlPressed(): boolean {
return this.isPressed;
}
disable(toggle: boolean): void {
this.disabled = toggle;
}
}
export function addKeybind(data: KeybindProps): CKeybind {
const kb = new Keybind(data);
keybinds[kb.name] = kb;
RegisterCommand("+" + kb.name, () => {
if (kb.disabled || IsPauseMenuActive()) return;
kb.isPressed = true;
kb.onPressed?.call(kb);
}, false);
RegisterCommand("-" + kb.name, () => {
if (kb.disabled || IsPauseMenuActive()) return;
kb.isPressed = false;
kb.onReleased?.call(kb);
}, false);
RegisterKeyMapping(
"+" + kb.name,
kb.description,
kb.defaultMapper ?? "keyboard",
kb.defaultKey ?? ""
);
if (kb.secondaryKey) {
RegisterKeyMapping(
"~!+" + kb.name,
kb.description,
kb.secondaryMapper ?? kb.defaultMapper ?? "keyboard",
kb.secondaryKey
);
}
setTimeout(() => {
emit("chat:removeSuggestion", `/+${kb.name}`);
emit("chat:removeSuggestion", `/-${kb.name}`);
}, 500);
return kb;
}
export function getKeybind(name: string): CKeybind | undefined {
return keybinds[name];
}
export function getAllKeybinds(): Readonly<Record<string, CKeybind>> {
return keybinds;
}

View File

@@ -10,7 +10,7 @@ type NotificationPosition =
| 'bottom-left' | 'bottom-left'
| 'center-right' | 'center-right'
| 'center-left'; | 'center-left';
type NotificationType = 'inform' | 'error' | 'success'; type NotificationType = 'inform' | 'error' | 'success' | 'warning';
type IconAnimation = 'spin' | 'spinPulse' | 'spinReverse' | 'pulse' | 'beat' | 'fade' | 'beatFade' | 'bounce' | 'shake'; type IconAnimation = 'spin' | 'spinPulse' | 'spinReverse' | 'pulse' | 'beat' | 'fade' | 'beatFade' | 'bounce' | 'shake';
interface NotifyProps { interface NotifyProps {

View File

@@ -12,6 +12,7 @@ interface PropProps {
} }
interface ProgressProps { interface ProgressProps {
label?: string;
duration: number; duration: number;
position?: 'middle' | 'bottom'; position?: 'middle' | 'bottom';
useWhileDead?: boolean; useWhileDead?: boolean;

View File

@@ -1,4 +1,4 @@
import { Vector3 } from '@nativewrappers/client'; import { Vector3 } from '@nativewrappers/fivem';
import { cache } from '../cache'; import { cache } from '../cache';
let points: Point[] = []; let points: Point[] = [];

View File

@@ -1,11 +1,13 @@
{ {
"name": "@communityox/ox_lib", "name": "@communityox/ox_lib",
"author": "Overextended", "author": "Overextended",
"version": "3.30.7", "version": "3.31.2",
"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",
"sideEffects": ["./shared/resource/locale/index.js"], "sideEffects": [
"./shared/resource/locale/index.js"
],
"scripts": { "scripts": {
"compile": "tsc", "compile": "tsc",
"prepare": "npm run compile" "prepare": "npm run compile"
@@ -26,7 +28,7 @@
}, },
"license": "LGPL-3.0", "license": "LGPL-3.0",
"dependencies": { "dependencies": {
"@nativewrappers/client": "^1.7.33", "@nativewrappers/fivem": "^0.0.103",
"csstype": "^3.1.3", "csstype": "^3.1.3",
"fast-printf": "^1.6.9", "fast-printf": "^1.6.9",
"typescript": "^5.4.2" "typescript": "^5.4.2"

View File

@@ -1,5 +1,7 @@
export * from './resource'; export * from './resource';
export const context: 'server' | 'client' = IsDuplicityVersion() ? 'server' : 'client';
// https://www.raygesualdo.com/posts/flattening-object-keys-with-typescript-types/ // https://www.raygesualdo.com/posts/flattening-object-keys-with-typescript-types/
export type FlattenObjectKeys<T extends Record<string, any>, Key = keyof T> = Key extends string export type FlattenObjectKeys<T extends Record<string, any>, Key = keyof T> = Key extends string
? T[Key] extends Record<string, unknown> ? T[Key] extends Record<string, unknown>

View File

@@ -0,0 +1,29 @@
import { cache } from '../cache/index';
import { context } from '../../index';
import { Vector3 } from "@nativewrappers/fivem";
interface NearbyVehicle {
vehicle: number;
coords: Vector3;
}
export function getNearbyVehicles(coords: Vector3, maxDistance: number = 2.0, includePlayerVehicle: boolean = false): NearbyVehicle[] {
const vehicles = GetGamePool('CVehicle');
const nearbyVehicles: NearbyVehicle[] = [];
for (const vehicle of vehicles) {
if (context === 'server' || !cache.vehicle || vehicle !== cache.vehicle || includePlayerVehicle) {
const vehicleCoords = Vector3.fromArray(GetEntityCoords(vehicle, true));
const distance = vehicleCoords.distance(coords);
if (distance < maxDistance && NetworkGetEntityIsNetworked(vehicle) ) {
nearbyVehicles.push({
vehicle,
coords: vehicleCoords
});
}
}
}
return nearbyVehicles;
}

View File

@@ -1,3 +1,4 @@
export * from './version'; export * from './version';
export * from './cache'; export * from './cache';
export * from './locale' export * from './locale';
export * from './getNearbyVehicles';

View File

@@ -29,6 +29,9 @@ local GetCurrentPedWeapon = GetCurrentPedWeapon
CreateThread(function() CreateThread(function()
while true do while true do
local ped = PlayerPedId() local ped = PlayerPedId()
-- If the player's ped is changed, the ped value may return 0 during the transition. If the value is 0, skip all checks.
if ped ~= 0 then
cache:set('ped', ped) cache:set('ped', ped)
local vehicle = GetVehiclePedIsIn(ped, false) local vehicle = GetVehiclePedIsIn(ped, false)
@@ -60,8 +63,8 @@ CreateThread(function()
end end
local hasWeapon, currentWeapon = GetCurrentPedWeapon(ped, true) local hasWeapon, currentWeapon = GetCurrentPedWeapon(ped, true)
cache:set('weapon', (hasWeapon and currentWeapon ~= 0) and currentWeapon or false)
cache:set('weapon', hasWeapon and currentWeapon or false) end
Wait(100) Wait(100)
end end

View File

@@ -30,9 +30,12 @@ local input
---@field searchable? boolean ---@field searchable? boolean
---@field description? string ---@field description? string
---@field maxSelectedValues? number ---@field maxSelectedValues? number
---@field minLength? number
---@field maxLength? number
---@class InputDialogOptionsProps ---@class InputDialogOptionsProps
---@field allowCancel? boolean ---@field allowCancel? boolean
---@field size? 'xs' | 'sm' | 'md' | 'lg' | 'xl'
---@param heading string ---@param heading string
---@param rows string[] | InputDialogRowProps[] ---@param rows string[] | InputDialogRowProps[]

View File

@@ -21,7 +21,7 @@
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-hook-form": "^7.41.3", "react-hook-form": "^7.41.3",
"react-hot-toast": "^2.4.0", "react-hot-toast": "^2.5.2",
"react-markdown": "^8.0.1", "react-markdown": "^8.0.1",
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",
"tinycolor2": "^1.6.0", "tinycolor2": "^1.6.0",
@@ -46,6 +46,9 @@
}, },
}, },
}, },
"patchedDependencies": {
"react-hot-toast@2.5.2": "patches/react-hot-toast@2.5.2.patch",
},
"packages": { "packages": {
"@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="], "@ampproject/remapping": ["@ampproject/remapping@2.3.0", "", { "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", "@jridgewell/trace-mapping": "^0.3.24" } }, "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw=="],

View File

@@ -21,7 +21,7 @@
"react": "18.2.0", "react": "18.2.0",
"react-dom": "18.2.0", "react-dom": "18.2.0",
"react-hook-form": "^7.41.3", "react-hook-form": "^7.41.3",
"react-hot-toast": "^2.4.0", "react-hot-toast": "^2.5.2",
"react-markdown": "^8.0.1", "react-markdown": "^8.0.1",
"remark-gfm": "^3.0.1", "remark-gfm": "^3.0.1",
"tinycolor2": "^1.6.0", "tinycolor2": "^1.6.0",
@@ -50,9 +50,7 @@
"prop-types": "^15.8.1", "prop-types": "^15.8.1",
"rimraf": "^3.0.2" "rimraf": "^3.0.2"
}, },
"pnpm": {
"patchedDependencies": { "patchedDependencies": {
"react-hot-toast@2.4.0": "patches/react-hot-toast@2.4.0.patch" "react-hot-toast@2.5.2": "patches/react-hot-toast@2.5.2.patch"
}
} }
} }

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -26,6 +26,7 @@ export const debugCustomNotification = () => {
title: 'Error', title: 'Error',
description: 'Notification description', description: 'Notification description',
type: 'error', type: 'error',
position: "bottom"
}, },
}, },
]); ]);

View File

@@ -103,7 +103,7 @@ const InputDialog: React.FC = () => {
centered centered
closeOnEscape={fields.options?.allowCancel !== false} closeOnEscape={fields.options?.allowCancel !== false}
closeOnClickOutside={false} closeOnClickOutside={false}
size="xs" size={fields.options?.size || 'xs'}
styles={{ title: { textAlign: 'center', width: '100%', fontSize: 18 } }} styles={{ title: { textAlign: 'center', width: '100%', fontSize: 18 } }}
title={fields.heading} title={fields.heading}
withCloseButton={false} withCloseButton={false}

View File

@@ -24,6 +24,8 @@ const TextareaField: React.FC<Props> = (props) => {
autosize={props.row.autosize} autosize={props.row.autosize}
minRows={props.row.min} minRows={props.row.min}
maxRows={props.row.max} maxRows={props.row.max}
minLength={props.row.minLength}
maxLength={props.row.maxLength}
/> />
); );
}; };

View File

@@ -61,7 +61,7 @@ const getAnimation = (visible: boolean, position: string) => {
animation = { from: 'X(0px)', to: 'X(-100%)' }; animation = { from: 'X(0px)', to: 'X(-100%)' };
} else if (position === 'top-center') { } else if (position === 'top-center') {
animation = { from: 'Y(0px)', to: 'Y(-100%)' }; animation = { from: 'Y(0px)', to: 'Y(-100%)' };
} else if (position === 'bottom') { } else if (position === 'bottom-center') {
animation = { from: 'Y(0px)', to: 'Y(100%)' }; animation = { from: 'Y(0px)', to: 'Y(100%)' };
} else { } else {
animation = { from: 'X(0px)', to: 'X(100%)' }; animation = { from: 'X(0px)', to: 'X(100%)' };

View File

@@ -5,6 +5,7 @@ export interface InputProps {
rows: Array<IInput | ICheckbox | ISelect | INumber | ISlider | IColorInput | IDateInput | ITextarea | ITimeInput>; rows: Array<IInput | ICheckbox | ISelect | INumber | ISlider | IColorInput | IDateInput | ITextarea | ITimeInput>;
options?: { options?: {
allowCancel?: boolean; allowCancel?: boolean;
size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl';
}; };
} }
@@ -76,4 +77,6 @@ export interface ITextarea extends BaseField<'textarea', string> {
autosize?: boolean; autosize?: boolean;
min?: number; min?: number;
max?: number; max?: number;
minLength?: number;
maxLength?: number;
} }