New features and cleanup

Added Networked Markers
Added Anim module
Added framework default file for things that are native to game related to player
Started on a batch network event trigger to allow for single event call for multiple events

Updated params notation for ids
Removed prints from client_entity + actions + ext
This commit is contained in:
gononono64 committed 2025-05-09 19:06:50 -05:00
1 parent 91d69a6742
commit 38d0d5527a
17 files changed
+463 -130

No files matched your search

+19 -32
View File
@@ -8,7 +8,7 @@ function Bridge.RegisterModule(moduleName, moduleTable)
return
end
local wrappedModule = {}
local wrappedModule = Bridge[moduleName] or {}
if type(moduleTable) == 'function' then
Bridge[moduleName] = wrappedModule
exports(moduleName, moduleTable)
@@ -57,22 +57,28 @@ Bridge.RegisterModule("Shops", Shops)
Bridge.RegisterModule("Housing", Housing)
--lib
Bridge.RegisterModule("Tables", cLib.Tables)
Bridge.RegisterModule("Math", cLib.Math)
Bridge.RegisterModule("Prints", cLib.Prints)
Bridge.RegisterModule("Callback", cLib.Callback)
-- Bridge.RegisterModule("Tables", cLib.Tables)
-- Bridge.RegisterModule("Math", cLib.Math)
-- Bridge.RegisterModule("Prints", cLib.Prints)
-- Bridge.RegisterModule("Callback", cLib.Callback)
--new
-- --new
Bridge.RegisterModule("Require", Require)
Bridge.RegisterModule("Ids", cLib.Ids)
Bridge.RegisterModule("ReboundEntities", cLib.ReboundEntities)
Bridge.RegisterModule("LA", cLib.LA)
Bridge.RegisterModule("Perlin", cLib.Perlin)
Bridge.RegisterModule("Actions", cLib.Actions)
Bridge.RegisterModule("Cache", cLib.Cache)
Bridge.RegisterModule("Skills", Skills)
-- Bridge.RegisterModule("Ids", cLib.Ids)
-- Bridge.RegisterModule("ReboundEntities", cLib.ReboundEntities)
-- Bridge.RegisterModule("LA", cLib.LA)
-- Bridge.RegisterModule("Perlin", cLib.Perlin)
-- Bridge.RegisterModule("Actions", cLib.Actions)
-- Bridge.RegisterModule("Cache", cLib.Cache)
-- Bridge.RegisterModule("Skills", Skills)
for k, v in pairs(cLib) do
if v then
Bridge.RegisterModule(k, v)
end
end
exports('Bridge', function()
return Bridge
end)
@@ -81,13 +87,6 @@ end)
-- ▄█▀ █▄▄ █▀▄ ▀▄▀ █▄▄ █▀▄
if not IsDuplicityVersion() then goto client end
Bridge.RegisterModule("SQL", cLib.SQL)
Bridge.RegisterModule("Logs", cLib.Logs)
Bridge.RegisterModule("ItemsBuilder", cLib.ItemsBuilder)
Bridge.RegisterModule("LootTables", cLib.LootTables)
Bridge.RegisterModule("Version", Version)
Bridge.RegisterModule("ServerEntity", cLib.ServerEntity)
-- ▄▀▀ █ █ ██▀ █▄ █ ▀█▀
-- ▀▄▄ █▄▄ █ █▄▄ █ ▀█ █
@@ -106,18 +105,6 @@ Bridge.RegisterModule("Menu", Menu)
Bridge.RegisterModule("Dialogue", Dialogue)
Bridge.RegisterModule("Accessibility", Accessibility) -- new
Bridge.RegisterModule("Utility", cLib.Utility)
Bridge.RegisterModule("Placeable", cLib.Placeable)--new
Bridge.RegisterModule("Gizmo", cLib.Gizmo)
Bridge.RegisterModule("Scaleform", cLib.Scaleform)
Bridge.RegisterModule("Raycast", cLib.Raycast)
Bridge.RegisterModule("PlaceableObject", cLib.PlaceableObject)
Bridge.RegisterModule("Point", cLib.Point)
Bridge.RegisterModule("Object", cLib.Object)
Bridge.RegisterModule("Particle", cLib.Particle)
Bridge.RegisterModule("ClientEntity", cLib.ClientEntity)
Bridge.RegisterModule("ClientEntityActions", cLib.ClientEntityActions)
-- Fill the bridge tables with player data.
function FillBridgeTables()
PlayerLoaded = true
+161
View File
@@ -0,0 +1,161 @@
Anim = Anim or {}
Ids = Ids or Require("lib/utility/shared/ids.lua")
Anim.Active = Anim.Active or {}
Anim.isUpdateLoopRunning = Anim.isUpdateLoopRunning or false
--- This will request the animation dictionary.
--- @param animDict string
--- @return boolean
function Anim.RequestDict(animDict)
if not animDict or type(animDict) ~= "string" then
return false
end
if HasAnimDictLoaded(animDict) then
return true
end
RequestAnimDict(animDict)
local timeout = GetGameTimer() + 2000
while not HasAnimDictLoaded(animDict) and GetGameTimer() < timeout do
Wait(50)
end
return HasAnimDictLoaded(animDict)
end
--- This will start the animation update loop.
--- @return void
function Anim.Start()
if Anim.isUpdateLoopRunning then return end
Anim.isUpdateLoopRunning = true
CreateThread(function()
while Anim.isUpdateLoopRunning do
local idsToProcess = {}
for idKey, _ in pairs(Anim.Active) do
table.insert(idsToProcess, idKey)
end
if #idsToProcess == 0 then
Wait(750)
else
for _, id in ipairs(idsToProcess) do
local animData = Anim.Active[id]
if animData then
local entity = animData.entity
local onComplete = animData.onComplete
if not DoesEntityExist(entity) then
if onComplete then onComplete(false, "despawned") end
Anim.Active[id] = nil
elseif animData.status == "pending_task" then
TaskPlayAnim(entity, animData.animDict, animData.animName, animData.blendIn, animData.blendOut, animData.duration, animData.flag, animData.playbackRate, false, false, false)
animData.startTime = GetGameTimer()
animData.animEndTime = animData.duration > 0 and (animData.startTime + animData.duration) or -1
animData.status = "playing"
elseif animData.status == "playing" then
local animationCompletedNaturally = false
if animData.duration == -1 then
if not IsEntityPlayingAnim(entity, animData.animDict, animData.animName, 3) and GetEntityAnimCurrentTime(entity, animData.animDict, animData.animName) > 0.8 then
animationCompletedNaturally = true
end
elseif animData.animEndTime ~= -1 and GetGameTimer() >= animData.animEndTime then
animationCompletedNaturally = true
end
if animationCompletedNaturally then
if onComplete then onComplete(true, "completed") end
Anim.Active[id] = nil
end
end
end
end
Wait(100)
end
end
end)
end
--- This will play an animation on the specified ped.
--- @param id string | nil
--- @param entity number
--- @param animDict string
--- @param animName string
--- @param blendIn number | nil
--- @param blendOut number | nil
--- @param duration number | nil
--- @param flag number | nil
--- @param playbackRate number | nil
--- @param onComplete function | nil
--- @return string | nil
function Anim.Play(id, entity, animDict, animName, blendIn, blendOut, duration, flag, playbackRate, onComplete)
local newId = id or Ids.CreateUniqueId(Anim.Active)
if Anim.Active[newId] then
if onComplete then
onComplete(false, "id_in_use")
end
return newId
end
if not entity or not DoesEntityExist(entity) or not IsEntityAPed(entity) then
if onComplete then
onComplete(false, "invalid_entity")
end
return nil
end
if not Anim.RequestDict(animDict) then
if onComplete then
onComplete(false, "dict_load_failed")
end
return nil
end
Anim.Active[newId] = {
entity = entity,
animDict = animDict,
animName = animName,
blendIn = blendIn or 8.0,
blendOut = blendOut or -8.0,
duration = duration or -1,
flag = flag or 1,
playbackRate = playbackRate or 0.0,
onComplete = onComplete,
status = "pending_task",
startTime = 0,
animEndTime = 0
}
Anim.Start()
return newId
end
function Anim.Stop(id)
if not id or not Anim.Active or not Anim.Active[id] then
return false
end
local animData = Anim.Active[id]
if animData.entity and DoesEntityExist(animData.entity) and IsEntityAPed(animData.entity) then
if animData.status == "playing" or animData.status == "pending_task" then
StopAnimTask(animData.entity, animData.animDict, animData.animName, 1.0)
end
end
if animData.onComplete then
animData.onComplete(false, "stopped_by_id")
end
Anim.Active[id] = nil
local anyLeft = Anim.Active and next(Anim.Active) ~= nil
if not anyLeft then
Anim.isUpdateLoopRunning = false
end
return true
end
return Anim
+65
View File
@@ -0,0 +1,65 @@
Batch = Batch or {}
Batch.Event = Batch.Event or {}
Batch.Event.Queued = Batch.Event.Queued or {}
Batch.Event.IsQueued = Batch.Event.IsQueued or false
local SERVER = IsDuplicityVersion()
-- could do a callback from client to server back to client with a time stamp. Use that timestamp to generate some random string/number and use that fo
-- this event name. Would help by masking from exploits. Thinking about making a module out of it
--- This is used to batch single events together to reduce network strain
---
if SERVER then
function Batch.Event.Queue(src, event, ...)
if src == -1 then
src = GetPlayers()
for k, v in pairs(src) do
local strSrc = tostring(v)
Batch.Event.Queued[strSrc] = Batch.Event.Queued[strSrc] or {}
table.insert(Batch.Event.Queued[strSrc], {
src = v,
event = event,
args = {...}
})
end
else
local strSrc = tostring(src)
Batch.Event.Queued[strSrc] = Batch.Event.Queued[strSrc] or {}
table.insert(Batch.Event.Queued[strSrc], {
src = src,
event = event,
args = {...}
})
end
if Batch.Event.IsQueued then return end
Batch.Event.IsQueued = true
SetTimeout(100, function()
for k, v in pairs(Batch.Event.Queued) do
TriggerClientEvent('community_bridge:client:BatchEvents', v.src, v)
end
Batch.Event.IsQueued = false
Batch.Event.Queued = {}
end)
end
return Batch
else
Batch.Event.Fire = function(array)
local playerSrc = PlayerId()
for k, v in pairs(array) do
if v.src == playerSrc then
local event = v.event
local args = v.args
TriggerEvent(event, table.unpack(args))
end
end
end
RegisterNetEvent('community_bridge:client:BatchEvents', function(array)
Batch.Event.Fire(array)
end)
return Batch
end
+5 -5
View File
@@ -35,10 +35,11 @@ local function SpawnEntity(entityData)
print(string.format("[ClientEntity] Unknown entity type '%s' for entity %s", entityData.entityType, entityData.id))
end
if entity then
-- print(string.format("[ClientEntity] Spawned %s entity %s (GameID: %s)", entityData.entityType, entityData.id, entity))
entityData.spawned = entity
SetModelAsNoLongerNeeded(model)
SetEntityAsMissionEntity(entity, true, true) -- Keep entity from being deleted by game engine
FreezeEntityPosition(entity, entityData.freeze or false) -- Optional freeze based on meta
FreezeEntityPosition(entity, true) -- Optional freeze based on meta
if entityData.OnSpawn and type(entityData.OnSpawn) == 'function' then
entityData.OnSpawn(entityData)
end
@@ -75,7 +76,7 @@ function ClientEntity.Register(entityData)
-- print(string.format("[ClientEntity] Registering %s entity %s", entityData.entityType, entityData.id))
-- Use Point system for proximity checks
print(string.format("[ClientEntity] Registering entity %s at %s", entityData.id, json.encode(entityData)))
-- print(string.format("[ClientEntity] Registering entity %s at %s", entityData.id, json.encode(entityData)))
Point.Register(entityData.id, entityData.coords, entityData.spawnDistance or 50.0, entityData, SpawnEntity, RemoveEntity, function() end)
end
@@ -96,13 +97,13 @@ end
-- @param data table The data fields to update.
function ClientEntity.Update(id, data)
local entityData = Entities[id]
print(string.format("[ClientEntity] Updating entity %s", id))
-- print(string.format("[ClientEntity] Updating entity %s", id))
if not entityData then return end
local needsPointUpdate = false
for key, value in pairs(data) do
if key == 'coords' and #(entityData.coords - value) > 0.1 then
print(string.format("[ClientEntity] Updating coords for entity %s", id))
-- print(string.format("[ClientEntity] Updating coords for entity %s", id))
needsPointUpdate = true
end
if key == 'spawnDistance' and entityData.spawnDistance ~= value then
@@ -176,7 +177,6 @@ end)
-- New handler for entity actions
RegisterNetEvent("community_bridge:client:TriggerEntityAction", function(entityId, actionName, ...)
local entityData = Entities[entityId]
print("here", json.encode(entityData))
-- Check if entity exists locally (it doesn't need to be spawned to queue actions)
if entityData then
if actionName == "Stop" then
@@ -12,7 +12,6 @@ ClientEntityActions.RegisteredActions = {} -- New: Registry for action implemen
-- @param entityId string|number The ID of the entity.
function ClientEntityActions.ProcessNextAction(entityId)
if ClientEntityActions.IsActionRunning [entityId] then return end -- Already running something
print(string.format("[ClientEntityActions] Processing next action for entity %s", entityId))
local queue = ClientEntityActions.ActionQueue[entityId]
if not queue or #queue == 0 then return end -- Queue is empty
@@ -27,7 +26,6 @@ function ClientEntityActions.ProcessNextAction(entityId)
-- Look up the action in the registry
local actionFunc = ClientEntityActions.RegisteredActions [nextAction.name]
print(string.format("[ClientEntityActions] Action '%s' dequeued for entity %s", nextAction.name, entityId))
if actionFunc then
-- print(string.format("[ClientEntityActions] Starting action '%s' for entity %s", nextAction.name, entityId))
ClientEntityActions.IsActionRunning [entityId] = true
@@ -4,7 +4,6 @@ LA = LA or Require("lib/utility/shared/la.lua")
--- Internal implementation for walking. Registered via RegisterAction.
function DefaultActions.WalkTo(entityData, coords, speed, timeout)
print("[ClientEntityActions] WalkTo action called", coords, speed, timeout)
local entity = entityData.spawned
local entityId = entityData.id -- Store ID locally for safety in thread
@@ -179,9 +178,7 @@ function DefaultActions.AttachProp(entityData, propModel, boneName, offsetPos, o
end
local modelHash = Utility.GetEntityHashFromModel(propModel)
print(modelHash, propModel)
if not Utility.LoadModel(modelHash) then
print(string.format("[ClientEntityActions] Failed to load prop model '%s' for entity %s", propModel, entityId))
ClientEntityActions.IsActionRunning[entityId] = false
ClientEntityActions.ProcessNextAction(entityId)
return
@@ -196,7 +193,6 @@ function DefaultActions.AttachProp(entityData, propModel, boneName, offsetPos, o
if boneIndex == -1 then boneIndex = 0 end -- Default to root if bone not found or not ped
offsetPos = offsetPos or vector3(0.0, 0.0, 0.0)
offsetRot = offsetRot or vector3(0.0, 0.0, 0.0)
print(string.format("[ClientEntityActions] Attaching prop '%s' to entity %s at bone %d", propModel, entityId, boneIndex))
AttachEntityToEntity(prop, entity, boneIndex, offsetPos.x, offsetPos.y, offsetPos.z, offsetRot.x, offsetRot.y, offsetRot.z, false, useSoftPinning or false, collision or false, isPed or false, vertexIndex or 2, fixedRot == nil and true or fixedRot)
entityData.props = entityData.props or {} -- Ensure props table exists
table.insert(entityData.props, prop) -- Store the prop handle in the entity data
@@ -351,6 +347,11 @@ function DefaultActions.Circle(entityData, radius, speed)
-- ClientEntityActions.ProcessNextAction(entityId) -- Try next action if this one failed immediately
end
function DefaultActions.Collisions(entityData, enable, keepPhysics)
local entity = entityData.spawned
SetEntityCollision(entity, enable, keepPhysics)
end
for name, func in pairs(DefaultActions) do
ClientEntityActions.RegisterAction(name, func)
end
+4 -1
View File
@@ -58,7 +58,7 @@ cLib.ItemsBuilder = ItemsBuilder or Require("lib/generators/server/ItemsBuilder.
cLib.LootTables = LootTables or Require("lib/generators/server/lootTables.lua")
cLib.Cache = Cache or Require("lib/cache/shared/cache.lua")
cLib.ServerEntity = ServerEntity or Require("lib/entities/server/server_entity.lua")
cLib.Marker = Marker or Require("lib/markers/server/server.lua")
if IsDuplicityVersion() then return cLib end
::client::
@@ -74,4 +74,7 @@ cLib.Cache = Cache or Require("lib/cache/client/cache.lua")
cLib.ClientEntity = ClientEntity or Require("lib/entities/client/client_entity.lua")
cLib.ClientEntityActions = ClientEntityActions or Require("lib/entities/client/client_entity_actions.lua")
cLib.ClientStateBag = ClientStateBag or Require("lib/statebags/client/client.lua")
cLib.Marker = Marker or Require("lib/markers/client/markers.lua")
cLib.Anim = Anim or Require("lib/anim/client/client.lua")
return cLib
+134 -73
View File
@@ -1,8 +1,10 @@
Marker = {
}
local Created = setmetatable({}, { __mode = "k" })
local id = Require("lib/utility/shared/ids")
---@diagnostic disable: duplicate-set-field
Marker = {}
local Created = setmetatable({}, { __mode = "k" }) --what is mode?
local id = Ids or Require("lib/utility/shared/ids.lua")
local point = Require("lib/points/client/points.lua")
local loopRunning = false
local Drawing = {}
--- This will validate the marker data.
--- @param data table{position: vector3, offset: vector3, rotation: vector3, size: vector3, color: vector3, alpha: number, bobUpAndDown: boolean, marker: number, interaction: function}
@@ -23,91 +25,150 @@ local function validateMarkerData(data)
return true
end
AddEventHandler("community_bridge:client:marker", function(data)
if not validateMarkerData(data) then return end
if source == "" then return end
Marker.DrawMarker(data)
end)
--- This will create a marker.
--- @param data table{position: vector3, offset: vector3, rotation: vector3, size: vector3, color: vector3, alpha: number, bobUpAndDown: boolean, marker: number, interaction: function}
---@return number
function Marker.DrawMarker(data)
--- @return string|nil
function Marker.Create(data)
local _id = data.id or id.Random()
local position = data.position or vector3(0.0, 0.0, 0.0)
local offset = data.offset or vector3(0.0, 0.0, 0.0)
local marker = data.marker or 1
local pos = vector3(position.x + offset.x, position.y + offset.y, position.z + offset.z)
local rotation = data.rotation or vector3(0, 0, 0)
local size = data.size or vector3(1.0, 1.0, 1.0)
local color = data.color or vector3(0, 255, 0)
local alpha = data.alpha or 255
local bobUpAndDown = data.bobUpAndDown
local interaction = data.interaction or false
Created[_id] = {
position = pos,
rotation = rotation,
size = size,
color = color,
alpha = alpha,
bobUpAndDown =
bobUpAndDown,
marker = marker,
offset = offset,
interaction = interaction,
if not validateMarkerData(data) then return end
local basePosition = data.position or vector3(0.0, 0.0, 0.0)
local baseOffset = data.offset or vector3(0.0, 0.0, 0.0)
local data = {
id = _id,
position = vector3(basePosition.x + baseOffset.x, basePosition.y + baseOffset.y, basePosition.z + baseOffset.z),
offset = baseOffset,
marker = data.marker or 1,
rotation = data.rotation or vector3(0, 0, 0),
size = data.size or vector3(1.0, 1.0, 1.0),
color = data.color or vector3(0, 255, 0),
alpha = data.alpha or 255,
bobUpAndDown = data.bobUpAndDown,
-- interaction = data.interaction or false, -- Uncomment if you re-implement interaction logic
rotate = data.rotate,
textureDict = data.textureDict,
textureName = data.textureName,
drawOnEnts = data.drawOnEnts,
}
Created[_id] = data
point.Register(
_id, data.position, data.drawDistance or 50.0, data,
function(_)
if not Created[_id] then return point.Remove(_id) end
Drawing[_id] = Created[_id]
Marker.Run(Drawing[_id])
end,
function(markerData)
Drawing[_id] = nil
end
)
return _id
end
function Marker.RemoveMarker(id)
if Created[id] then
--- This will remove a marker.
--- @param id string
--- @return boolean
function Marker.Remove(id)
if not Created[id] then return false end
point.Remove(id)
Drawing[id] = nil
Created[id] = nil
return true
end
--- This will remove all markers.
--- @param id string
function Marker.RemoveAll()
for id, _ in pairs(Created) do
point.Remove(id)
Created[id] = nil
return true
end
return false
end
end
function Marker.Draw()
while true do
Wait(0)
if not next(Created) then
Wait(1000) -- Reduce CPU usage when no markers are present
goto continue
end
for id, _ in pairs(Created) do
if Created[id] then
local data = Created[id]
if #(data.position - GetEntityCoords(PlayerPedId())) > 100.0 then
-- This will loop through all marker(points) in range and draw them.
-- @param data table{marker: number, position: vector3, rotation: vector3, size: vector3, color: vector3, alpha: number, bobUpAndDown: boolean, faceCamera: boolean, rotate: boolean, textureDict: string, textureName: string, drawOnEnts: boolean}
-- @return nil
function Marker.Run(data)
if loopRunning then return end
loopRunning = true
CreateThread(function()
while loopRunning do
for drawingId, drawingData in pairs(Drawing) do
if not Created[drawingId] then
Drawing[drawingId] = nil
goto continue
else
DrawMarker(
data.marker,
data.position.x, data.position.y, data.position.z,
0.0, 0.0, 0.0,
data.rotation.x, data.rotation.y, data.rotation.z,
data.size.x, data.size.y, data.size.z,
data.color.x, data.color.y, data.color.z, data.alpha,
data.bobUpAndDown, false, false
)
if data.interaction then
local playerCoords = GetEntityCoords(PlayerPedId())
local distance = #(data.position - playerCoords)
if distance < 2.0 then
if IsControlJustReleased(0, 38) then -- E key
data.interaction(data.id)
end
end
end
end
DrawMarker(
data.marker,
data.position.x, data.position.y, data.position.z,
0.0, 0.0, 0.0,
data.rotation.x, data.rotation.y, data.rotation.z,
data.size.x, data.size.y, data.size.z,
data.color.x, data.color.y, data.color.z, data.alpha,
data.bobUpAndDown, data.faceCamera, false,
data.rotate, data.textureDict, data.textureName, data.drawOnEnts
)
::continue::
end
Wait(3)
end
::continue::
end
end)
end
Marker.Draw() -- Start the marker drawing loop
RegisterNetEvent("community_bridge:Client:Marker", function(data)
print("community_bridge:Client:Marker")
Marker.Create(data)
end)
RegisterNetEvent("community_bridge:Client:MarkerRemove", function(id)
Marker.Remove(id)
end)
-- local loopRunning = false
-- function Marker.Draw()
-- if loopRunning then return end
-- loopRunning = true
-- while loopRunning do
-- Wait(0)
-- if not next(Created) then
-- Wait(1000) -- Reduce CPU usage when no markers are present
-- goto continue
-- end
-- for id, _ in pairs(Created) do
-- if Created[id] then
-- local data = Created[id]
-- if #(data.position - GetEntityCoords(PlayerPedId())) > 100.0 then
-- goto continue
-- else
-- DrawMarker(
-- data.marker,
-- data.position.x, data.position.y, data.position.z,
-- 0.0, 0.0, 0.0,
-- data.rotation.x, data.rotation.y, data.rotation.z,
-- data.size.x, data.size.y, data.size.z,
-- data.color.x, data.color.y, data.color.z, data.alpha,
-- data.bobUpAndDown, data.faceCamera, false,
-- data.rotate, data.textureDict, data.textureName, data.drawOnEnts
-- )
-- -- if data.interaction then
-- -- local playerCoords = GetEntityCoords(PlayerPedId())
-- -- local distance = #(data.position - playerCoords)
-- -- if distance < 2.0 then
-- -- if IsControlJustReleased(0, 38) then -- E key
-- -- data.interaction(data.id)
-- -- end
-- -- end
-- -- end
-- end
-- end
-- end
-- ::continue::
-- end
-- end
-- Marker.Draw() -- Start the marker drawing loop
exports("Marker", Marker)
+38 -4
View File
@@ -1,4 +1,9 @@
local function RegisterNewMarker(data)
---@diagnostic disable: duplicate-set-field
local id = Ids or Require("lib/utility/shared/ids.lua")
Marker = {}
local Created = {}
function Marker.Create(data)
if not data.position or not data.position.x or not data.position.y or not data.position.z then
print("Invalid marker position. Must be a vector3 with x, y, and z coordinates.")
return
@@ -17,8 +22,37 @@ local function RegisterNewMarker(data)
return
end
TriggerClientEvent("community_bridge:client:marker", source, data)
local _id = id.CreateUniqueId(Created)
local data = {
id = _id,
position = data.position,
offset = data.offset or vector3(0.0, 0.0, 0.0),
marker = data.marker or 1,
rotation = data.rotation or vector3(0, 0, 0),
size = data.size or vector3(1.0, 1.0, 1.0),
color = data.color or vector3(0, 255, 0),
alpha = data.alpha or 255,
bobUpAndDown = data.bobUpAndDown,
-- interaction = data.interaction or false, -- Uncomment if you re-implement interaction logic
rotate = data.rotate,
textureDict = data.textureDict,
textureName = data.textureName,
drawOnEnts = data.drawOnEnts,
}
Created[_id] = data
TriggerClientEvent("community_bridge:Client:Marker", -1, data)
return _id
end
RegisterNetEvent("community_bridge:server:createMarker", RegisterNewMarker)
exports("RegisterNewMarker", RegisterNewMarker)
function Marker.Remove(id)
if not Created[id] then return end
TriggerClientEvent("community_bridge:Client:MarkerRemove", -1, id)
Created[id] = nil
end
RegisterNetEvent("community_bridge:Server:MarkerRemove", function(id)
Marker.Remove(id)
end)
exports("Marker", Marker)
return Marker
+3 -3
View File
@@ -2,9 +2,9 @@ Ids = Ids or {}
---This will generate a unique id.
---@param tbl table
---@param len number
---@param pattern string
---@param tbl table | nil
---@param len number | nil
---@param pattern string | nil
---@return string
Ids.CreateUniqueId = function(tbl, len, pattern) -- both optional
tbl = tbl or {} -- table to check uniqueness. Ids to check against must be the key to the tables value
+2
View File
@@ -0,0 +1,2 @@
Framework = Framework or {}
-1
View File
@@ -3,7 +3,6 @@ if GetResourceState('es_extended') ~= 'started' then return end
ESX = exports["es_extended"]:getSharedObject()
Framework = {}
Framework.GetFrameworkName = function()
return 'es_extended'
+12 -1
View File
@@ -3,7 +3,7 @@ if GetResourceState('es_extended') ~= 'started' then return end
ESX = exports["es_extended"]:getSharedObject()
Framework = {}
Framework = Framework or {}
Framework.GetFrameworkName = function()
return 'es_extended'
@@ -140,6 +140,17 @@ Framework.GetIsPlayerDead = function(src)
return xPlayer.get("is_dead") or false
end
Framework.RevivePlayer = function(src)
src = tonumber(src)
if not src then return false end
TriggerEvent('esx_ambulancejob:revive', src) -- FIXME: deprecate
-- TriggerEvent('txAdmin:events:playerHealed', {
-- target = src,
-- })
return true
end
-- Framework.AddThirst(src, value)
-- Adds the specified value from the player's thirst level.
Framework.AddThirst = function(src, value)
+1 -1
View File
@@ -4,7 +4,7 @@ if GetResourceState('qbx_core') == 'started' then return end
QBCore = exports['qb-core']:GetCoreObject()
Framework = {}
Framework = Framework or {}
---This will get the name of the framework being used (if a supported framework).
---@return string
+12 -1
View File
@@ -4,7 +4,7 @@ if GetResourceState('qbx_core') == 'started' then return end
QBCore = exports['qb-core']:GetCoreObject()
Framework = {}
Framework = Framework or {}
Framework.Shared = QBCore.Shared
Framework.GetFrameworkName = function()
return 'qb-core'
@@ -265,6 +265,17 @@ Framework.GetIsPlayerDead = function(src)
return playerData.metadata.isdead or playerData.metadata.inlaststand or false
end
Framework.RevivePlayer = function(src)
src = tonumber(src)
if not src then return false end
TriggerClientEvent('hospital:client:Revive', src) -- FIXME: deprecate
-- TriggerEvent('txAdmin:events:playerHealed', {
-- target = src,
-- })
return true
end
---This will get the thirst of a player
---@param src any
+1 -1
View File
@@ -3,7 +3,7 @@ if GetResourceState('qbx_core') ~= 'started' then return end
QBox = exports.qbx_core
Framework = {}
Framework = Framework or {}
Framework.GetFrameworkName = function()
return 'qbx_core'
+1 -1
View File
@@ -3,7 +3,7 @@ if GetResourceState('qbx_core') ~= 'started' then return end
local QBox = exports.qbx_core
Framework = {}
Framework = Framework or {}
---Returns the name of the framework being used (if a supported framework).
---@return string