34 Commits

Author SHA1 Message Date
github-actions
faa9dda57f chore: bump version to v3.31.4 2025-09-09 16:48:13 +00:00
Swellington Soares
619ecc9e55 feat(imports/dui): added mising dui methods (#47) 2025-09-09 18:47:01 +02:00
Maximus7474
56c0a91022 feat(imports/logger): add definable dataset for fivemanage logging (#45) 2025-09-04 18:48:50 +02:00
PotatoFarmer441
d6417b9a84 fix(zones): set zone distance on creation (#44)
* fix(zones): set zone distance on creation

Signed-off-by: PotatoFarmer441 <helioau@live.com.au>

* Update shared.lua

Signed-off-by: PotatoFarmer441 <helioau@live.com.au>

---------

Signed-off-by: PotatoFarmer441 <helioau@live.com.au>
2025-08-30 13:39:20 +02:00
github-actions
ac9625d33a chore: bump version to v3.31.3 2025-08-18 12:00:25 +00:00
Zoo
2ab9114d2f chore(package/index): export addKeybind function (#40) 2025-08-18 13:58:42 +02:00
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
35 changed files with 679 additions and 457 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;
const newVersion = version.replace('v', '');
let newVersion = process.env.TGT_RELEASE_VERSION;
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}'`);
fs.writeFileSync('fxmanifest.lua', newFileContent);
await Bun.write('./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 = version.replace('v', '');
const newVersion = process.env.TGT_RELEASE_VERSION;
packageJson.version = newVersion.replace('v', '');
const packageFile = fs.readFileSync('package/package.json', { encoding: 'utf8' });
const newFileContent = packageFile.replace(/"version":\s+"(.*)",$/gm, `"version": "${newVersion}",`);
fs.writeFileSync('package/package.json', newFileContent);
await Bun.write('./package/package.json', JSON.stringify(packageJson, null, 2));

View File

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

View File

@@ -27,6 +27,6 @@ https://www.npmjs.com/package/@communityox/ox_lib
## 🖥️ 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 [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.
- 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'
author 'Overextended'
version '3.30.7'
version '3.31.4'
license 'LGPL-3.0-or-later'
repository 'https://github.com/communityox/ox_lib'
description 'A library of shared functions to utilise in other resources.'

View File

@@ -84,6 +84,29 @@ function lib.dui:sendMessage(message)
end
end
---@param x number
---@param y number
function lib.dui:sendMouseMove(x, y)
SendDuiMouseMove(self.duiObject, x, y)
end
---@param button 'left' | 'middle' | 'right'
function lib.dui:sendMouseDown(button)
SendDuiMouseDown(self.duiObject, button)
end
---@param button 'left' | 'middle' | 'right'
function lib.dui:sendMouseUp(button)
SendDuiMouseUp(self.duiObject, button)
end
---@param deltaX number
---@param deltaY number
function lib.dui:sendMouseWheel(deltaX, deltaY)
SendDuiMouseWheel(self.duiObject, deltaY, deltaX)
end
AddEventHandler('onResourceStop', function(resourceName)
if cache.resource ~= resourceName then return end

View File

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

View File

@@ -94,6 +94,7 @@ end
if service == 'fivemanage' then
local key = GetConvar('fivemanage:key', '')
local dataset = GetConvar('fivemanage:dataset', '')
if key ~= '' then
local endpoint = 'https://api.fivemanage.com/api/logs/batch'
@@ -101,9 +102,13 @@ if service == 'fivemanage' then
local headers = {
['Content-Type'] = 'application/json',
['Authorization'] = key,
['User-Agent'] = 'ox_lib'
['User-Agent'] = 'ox_lib',
}
if dataset ~= "" then
headers['X-Fivemanage-Dataset'] = dataset
end
function lib.logger(source, event, message, ...)
if not buffer then
buffer = {}

View File

@@ -9,14 +9,8 @@
---@diagnostic disable: param-type-mismatch
lib.marker = {}
local defaultRotation = vector3(0, 0, 0)
local defaultDirection = vector3(0, 0, 0)
local defaultColor = { r = 255, g = 255, b = 255, a = 100 }
local defaultSize = { width = 2, height = 1 }
local defaultTextureDict = nil
local defaultTextureName = nil
local markerTypesMap = {
---@enum (key) MarkerType
local markerTypes = {
UpsideDownCone = 0,
VerticalCylinder = 1,
ThickChevronUp = 2,
@@ -63,58 +57,12 @@ local markerTypesMap = {
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
---@field type MarkerType | number
---@field type? MarkerType | integer
---@field coords { x: number, y: number, z: number }
---@field width? 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 direction? { x: number, y: number, z: number }
---@field bobUpAndDown? boolean
@@ -122,9 +70,25 @@ local markerTypesMap = {
---@field rotate? boolean
---@field textureDict? string
---@field textureName? string
---@field invert? boolean
---@param self MarkerProps
local function drawMarker(self)
local vector3_zero = vector3(0, 0, 0)
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(
self.type,
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.width, self.width, self.height,
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
---@param options MarkerProps
function lib.marker.new(options)
local markerType
if type(options.type) == "string" then
markerType = markerTypesMap[options.type]
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
options.type =
type(options.type) == 'string' and markerTypes[options.type]
or type(options.type) == 'number' and options.type or nil
local self = {}
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
local self = setmetatable(options, marker_mt)
self.width += 0.0
self.height += 0.0
self.width += .0
self.height += .0
return self
end

View File

@@ -39,10 +39,14 @@ local function removePoint(self)
points[self.id] = nil
end
local function hasRemovePoint(entry)
return entry.remove == removePoint
end
CreateThread(function()
while true do
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)
cache.coords = coords
closestPoint = nil
@@ -89,9 +93,11 @@ CreateThread(function()
nearbyCount += 1
nearbyPoints[nearbyCount] = point
if point.onEnter and not point.inside then
if not point.inside then
point.inside = true
point:onEnter()
if point.onEnter then
point:onEnter()
end
end
elseif point.currentDistance then
if point.onExit then point:onExit() end

View File

@@ -123,11 +123,24 @@ local function shuffle(tbl)
return tbl
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.matches = table_matches
table.deepclone = table_deepclone
table.merge = table_merge
table.shuffle = shuffle
table.map = map
local frozenNewIndex = function(self) error(('cannot set values on a frozen table (%s)'):format(self), 2) end
local _rawset = rawset

View File

@@ -122,8 +122,15 @@ local function removeZone(zone)
insideZones[zone.id] = nil
table.remove(exitingZones, exitingZones:indexOf(zone))
table.remove(enteringZones, enteringZones:indexOf(zone))
local exitingIndex = exitingZones:indexOf(zone)
if exitingIndex then
table.remove(exitingZones, exitingIndex)
end
local enteringIndex = enteringZones:indexOf(zone)
if enteringIndex then
table.remove(enteringZones, enteringIndex)
end
end
CreateThread(function()
@@ -338,6 +345,8 @@ local function setZone(data)
data.contains = data.contains or contains
if lib.context == 'client' then
local coords = cache.coords or GetEntityCoords(cache.ped)
data.distance = #(data.coords - coords)
data.setDebug = setDebug
if data.debug then

View File

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

View File

@@ -9,25 +9,25 @@
"settings": {
"locale": "Endre språk",
"locale_description": "Nåværende språk: ${language} (%s)",
"notification_audio": "Varslings lyd",
"notification_position": "Varslings posisjon"
"notification_audio": "Varslingslyd",
"notification_position": "Varslingsposisjon"
},
"position": {
"bottom": "Bunn",
"bottom-left": "Bunn-venstre",
"bottom-right": "Bunn-høyre",
"center-left": "Senter-venstre",
"center-right": "Senter-høyre",
"top": "Top",
"top-left": "Top-venstre",
"top-right": "Top-høyre"
"bottom": "Nederst",
"bottom-left": "Nederst til venstre",
"bottom-right": "Nederst til høyre",
"center-left": "Midten venstre",
"center-right": "Midten høyre",
"top": "Øverst",
"top-left": "Øverst til venstre",
"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",
"txadmin_announcement": "Server annonsering fra %s",
"txadmin_announcement": "Serverannonsering fra %s",
"txadmin_dm": "Direktemelding fra %s",
"txadmin_warn": "Du har fått en advarsel fra %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",
"dependencies": {
"@nativewrappers/client": "^1.7.33",
"@nativewrappers/fivem": "^0.0.103",
"csstype": "^3.1.3",
"fast-printf": "^1.6.9",
"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=="],
"@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=="],

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

@@ -14,3 +14,4 @@ export * from './vehicleProperties';
export * from './callback';
export * from './points';
export * from './dui';
export * from './addKeybind';

View File

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

View File

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

View File

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

View File

@@ -1,11 +1,13 @@
{
"name": "@communityox/ox_lib",
"author": "Overextended",
"version": "3.30.7",
"version": "3.31.4",
"description": "JS/TS wrapper for ox_lib exports",
"main": "./shared/index.js",
"types": "./shared/index.d.ts",
"sideEffects": ["./shared/resource/locale/index.js"],
"sideEffects": [
"./shared/resource/locale/index.js"
],
"scripts": {
"compile": "tsc",
"prepare": "npm run compile"
@@ -26,7 +28,7 @@
},
"license": "LGPL-3.0",
"dependencies": {
"@nativewrappers/client": "^1.7.33",
"@nativewrappers/fivem": "^0.0.103",
"csstype": "^3.1.3",
"fast-printf": "^1.6.9",
"typescript": "^5.4.2"
@@ -40,4 +42,4 @@
"@types/react": "^18.2.66",
"prettier": "^2.8.8"
}
}
}

View File

@@ -1,5 +1,7 @@
export * from './resource';
export const context: 'server' | 'client' = IsDuplicityVersion() ? 'server' : 'client';
// 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
? 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 './cache';
export * from './locale'
export * from './locale';
export * from './getNearbyVehicles';

View File

@@ -29,40 +29,43 @@ local GetCurrentPedWeapon = GetCurrentPedWeapon
CreateThread(function()
while true do
local ped = PlayerPedId()
cache:set('ped', ped)
local vehicle = GetVehiclePedIsIn(ped, false)
-- 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)
if vehicle > 0 then
if vehicle ~= cache.vehicle then
local vehicle = GetVehiclePedIsIn(ped, false)
if vehicle > 0 then
if vehicle ~= cache.vehicle then
cache:set('seat', false)
end
cache:set('vehicle', vehicle)
if not cache.seat or GetPedInVehicleSeat(vehicle, cache.seat) ~= ped then
for i = -1, GetVehicleMaxNumberOfPassengers(vehicle) - 1 do
if GetPedInVehicleSeat(vehicle, i) == ped then
cache:set('seat', i)
break
end
end
end
else
cache:set('vehicle', false)
cache:set('seat', false)
end
cache:set('vehicle', vehicle)
if not cache.seat or GetPedInVehicleSeat(vehicle, cache.seat) ~= ped then
for i = -1, GetVehicleMaxNumberOfPassengers(vehicle) - 1 do
if GetPedInVehicleSeat(vehicle, i) == ped then
cache:set('seat', i)
break
end
end
if cache.game == 'redm' then
local mount = GetMount(ped)
local onMount = IsPedOnMount(ped)
cache:set('mount', onMount and mount or false)
end
else
cache:set('vehicle', false)
cache:set('seat', false)
local hasWeapon, currentWeapon = GetCurrentPedWeapon(ped, true)
cache:set('weapon', (hasWeapon and currentWeapon ~= 0) and currentWeapon or false)
end
if cache.game == 'redm' then
local mount = GetMount(ped)
local onMount = IsPedOnMount(ped)
cache:set('mount', onMount and mount or false)
end
local hasWeapon, currentWeapon = GetCurrentPedWeapon(ped, true)
cache:set('weapon', hasWeapon and currentWeapon or false)
Wait(100)
end
end)

View File

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

View File

@@ -21,7 +21,7 @@
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.41.3",
"react-hot-toast": "^2.4.0",
"react-hot-toast": "^2.5.2",
"react-markdown": "^8.0.1",
"remark-gfm": "^3.0.1",
"tinycolor2": "^1.6.0",
@@ -46,6 +46,9 @@
},
},
},
"patchedDependencies": {
"react-hot-toast@2.5.2": "patches/react-hot-toast@2.5.2.patch",
},
"packages": {
"@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-dom": "18.2.0",
"react-hook-form": "^7.41.3",
"react-hot-toast": "^2.4.0",
"react-hot-toast": "^2.5.2",
"react-markdown": "^8.0.1",
"remark-gfm": "^3.0.1",
"tinycolor2": "^1.6.0",
@@ -50,9 +50,7 @@
"prop-types": "^15.8.1",
"rimraf": "^3.0.2"
},
"pnpm": {
"patchedDependencies": {
"react-hot-toast@2.4.0": "patches/react-hot-toast@2.4.0.patch"
}
"patchedDependencies": {
"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',
description: 'Notification description',
type: 'error',
position: "bottom"
},
},
]);

View File

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

View File

@@ -24,6 +24,8 @@ const TextareaField: React.FC<Props> = (props) => {
autosize={props.row.autosize}
minRows={props.row.min}
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%)' };
} else if (position === 'top-center') {
animation = { from: 'Y(0px)', to: 'Y(-100%)' };
} else if (position === 'bottom') {
} else if (position === 'bottom-center') {
animation = { from: 'Y(0px)', to: 'Y(100%)' };
} else {
animation = { from: 'X(0px)', to: 'X(100%)' };
@@ -138,7 +138,7 @@ const Notifications: React.FC = () => {
} else {
iconColor = tinycolor(data.iconColor).toRgbString();
}
toast.custom(
(t) => (
<Box

View File

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