diff --git a/lib/entities/client/behaviors.lua b/lib/entities/client/behaviors.lua deleted file mode 100644 index 8641d03..0000000 --- a/lib/entities/client/behaviors.lua +++ /dev/null @@ -1,61 +0,0 @@ -Behaviors = { - All = {}, - isSetup = false, -} - -function Behaviors.Setup() - if Behaviors.isSetup then return end - Behaviors.isSetup = true - local behaviors = Require("lib/entities/client/behaviors/init.lua") - for _, behavior in ipairs(behaviors) do - Behaviors.Create(behavior.tag, behavior) - end -end - -function Behaviors.Create(behaviorId, behavior) - if not behaviorId or not behavior then return end - if Behaviors.All[behaviorId] then - print(string.format("[ClientEntity] Behavior %s already exists", behaviorId)) - return - end - Behaviors.All[behaviorId] = behavior -end - -function Behaviors.Get(behaviorId) - return Behaviors.All[behaviorId] -end - -function Behaviors.Remove(behaviorId) - if not Behaviors.All[behaviorId] then return end - Behaviors.All[behaviorId] = nil - return true -end - -function Behaviors.Trigger(actionName, clientEntityData, ...) - if not clientEntityData or not actionName then return end - for tag, behavior in pairs(Behaviors.All) do - local hasBehaviorArgs = Behaviors.Has(tag, clientEntityData) -- this is everything that's contained inside the object's individual tag - if hasBehaviorArgs and behavior[actionName] then - behavior[actionName](clientEntityData, hasBehaviorArgs, ...) - end - end -end - -function Behaviors.Inherit(behaviorId, clientEntityData, defaultData) - if not Behaviors.All[behaviorId] then - print(string.format("[ClientEntity] Behavior %s does not exist", behaviorId)) - return false - end - if not clientEntityData or not clientEntityData.id then - print("[ClientEntity] Invalid client entity data provided for inheritance") - return false - end - clientEntityData[behaviorId] = defaultData or {} -- Mark the entity as having this behavior - return true -end - -function Behaviors.Has(behaviorId, clientEntityData) - return clientEntityData and clientEntityData[behaviorId] -end - -return Behaviors \ No newline at end of file diff --git a/lib/entities/client/behaviors/init.lua b/lib/entities/client/behaviors/init.lua deleted file mode 100644 index 8c70fff..0000000 --- a/lib/entities/client/behaviors/init.lua +++ /dev/null @@ -1,20 +0,0 @@ -local fileList = { - "particles", - "targets", -} - -local path = "lib/entities/client/behaviors/" - -local function loadAllResources() - local modules = {} - for _, fileName in ipairs(fileList) do - local filePath = path .. fileName .. ".lua" - local required = Require(filePath) - if required then - table.insert(modules, required) - end - end - return modules -end - -return loadAllResources() \ No newline at end of file diff --git a/lib/entities/client/client_entity.lua b/lib/entities/client/client_entity.lua index 6e17102..22fa91b 100644 --- a/lib/entities/client/client_entity.lua +++ b/lib/entities/client/client_entity.lua @@ -282,12 +282,21 @@ RegisterNetEvent("community_bridge:client:DeleteEntity", function(id) end) RegisterNetEvent("community_bridge:client:UpdateEntity", function(id, data) - ClientEntity.Update(id, data) + for k, v in pairs(data) do + ClientEntity.Set(id, k, v) + end +end) + +local Loaded = false +AddEventHandler('community_bridge:Client:OnPlayerLoaded', function(resourceName) + if Loaded then return end + Loaded = true end) AddEventHandler('onResourceStart', function(resourceName) if resourceName ~= GetCurrentResourceName() then return end - Behaviors.Setup() + if Loaded then return end + Loaded = true end) -- Resource Stop Cleanup diff --git a/lib/entities/server/server_entity.lua b/lib/entities/server/server_entity.lua index 9d00fc4..487a809 100644 --- a/lib/entities/server/server_entity.lua +++ b/lib/entities/server/server_entity.lua @@ -117,6 +117,19 @@ function ServerEntity.Remove(id) Entities[id] = nil end +--- Updates data for a server-side entity and notifies clients. +-- @param id string|number The ID of the entity to update. +-- @param data table The data fields to update. +function ServerEntity.Set(id, data) + local entity = Entities[id] + if not entity then return false end + for key, value in pairs(data) do + entity[key] = value + end + TriggerClientEvent("community_bridge:client:UpdateEntity", -1, id, data) + return true +end + -- Clean up entities associated with a stopped resource AddEventHandler('onResourceStop', function(resourceName) local toDelete = {} diff --git a/lib/entities/shared/behaviors.lua b/lib/entities/shared/behaviors.lua new file mode 100644 index 0000000..f152c8e --- /dev/null +++ b/lib/entities/shared/behaviors.lua @@ -0,0 +1,73 @@ +Behaviors = { + All = {}, + isSetup = false, + invoked = {} +} + + +function Behaviors.Create(behaviorId, behavior) + if not behaviorId or not behavior then return end + if Behaviors.All[behaviorId] then return print(string.format("[ClientEntity] Behavior %s already exists", behaviorId)) end + local invoking = GetInvokingResource() or "community_bridge" + Behaviors.All[behaviorId] = behavior + Behaviors.invoked[invoking] = Behaviors.invoked[invoking] or {} + table.insert(Behaviors.invoked[invoking], behaviorId) +end + +function Behaviors.Get(behaviorId) + return Behaviors.All[behaviorId] +end + +function Behaviors.Remove(behaviorId) + if not Behaviors.All[behaviorId] then return end + Behaviors.All[behaviorId] = nil + return true +end + +function Behaviors.Trigger(actionName, clientEntityData, ...) + if not clientEntityData or not actionName then return end + for property, behavior in pairs(Behaviors.All) do + local hasBehaviorArgs = Behaviors.Has(property, clientEntityData) -- this is everything that's contained inside the object's individual property + if hasBehaviorArgs and behavior[actionName] then + local success, result = pcall(behavior[actionName], clientEntityData, hasBehaviorArgs, ...) + if not success then + print(string.format("[ClientEntity] Behavior %s failed: %s", property, result)) + end + end + end +end + +function Behaviors.Inherit(behaviorId, clientEntityData, defaultData) + if not Behaviors.All[behaviorId] then + print(string.format("[ClientEntity] Behavior %s does not exist", behaviorId)) + return false + end + if not clientEntityData or not clientEntityData.id then + print("[ClientEntity] Invalid client entity data provided for inheritance") + return false + end + clientEntityData[behaviorId] = defaultData or {} -- Mark the entity as having this behavior + return true +end + +function Behaviors.Has(behaviorId, clientEntityData) + return clientEntityData and clientEntityData[behaviorId] +end + +function Behaviors.Cleanup(resourceName) + if not resourceName or not Behaviors.invoked[resourceName] then return end + for _, behaviorId in ipairs(Behaviors.invoked[resourceName]) do + Behaviors.Remove(behaviorId) + end + Behaviors.invoked[resourceName] = nil +end + +AddEventHandler("onResourceStop", function(resourceName) + Behaviors.Cleanup(resourceName) + if resourceName ~= GetCurrentResourceName() then return end + for behaviorId, _ in pairs(Behaviors.All) do + Behaviors.Remove(behaviorId) + end +end) + +return Behaviors \ No newline at end of file diff --git a/modules/inventory/ox_inventory/server.lua b/modules/inventory/ox_inventory/server.lua index f4702b4..10730e0 100644 --- a/modules/inventory/ox_inventory/server.lua +++ b/modules/inventory/ox_inventory/server.lua @@ -131,17 +131,16 @@ Inventory.OpenStash = function(src, _type, id) end ---This will register a stash ----@param id number|string +---@param id string ---@param label string ---@param slots number ---@param weight number ---@param owner string ---@param groups table ---@param coords table ----@return boolean ----@return string|number +---@return string Inventory.RegisterStash = function(id, label, slots, weight, owner, groups, coords) - if Inventory.Stashes[id] then return true, id end + if Inventory.Stashes[id] then return id end Inventory.Stashes[id] = { id = id, label = label, @@ -151,8 +150,8 @@ Inventory.RegisterStash = function(id, label, slots, weight, owner, groups, coor groups = groups, coords = coords } - ox_inventory:RegisterStash(id, label, slots, weight, owner, groups) - return true, id + ox_inventory:RegisterStash(id, label, slots, weight, owner, groups, coords) + return id end ---This will return a boolean if the player has the item. @@ -194,24 +193,47 @@ end -- This will open the specified shop for the src passed. ---@param src number ----@param shopTitle string -Inventory.OpenShop = function(src, shopTitle) - TriggerClientEvent('ox_inventory:openInventory', src, 'shop', {type = shopTitle}) +---@param id string +Inventory.OpenShop = function(src, id) + local title = registeredShops[id]?.title or id + TriggerClientEvent('ox_inventory:openInventory', src, 'shop', {type = title}) end -- This will register a shop, if it already exists it will return true. ----@param shopTitle string ----@param shopInventory table ----@param shopCoords table ----@param shopGroups table -Inventory.RegisterShop = function(shopTitle, shopInventory, shopCoords, shopGroups) - if registeredShops[shopTitle] then return true end - registeredShops[shopTitle] = true - ox_inventory:RegisterShop(shopTitle, { name = shopTitle, inventory = shopInventory, groups = shopGroups, }) - --return Inventory.OpenShop(src, shopTitle) - return true +---@param title string +---@param items table +---@param coords table +---@param groups table +Inventory.RegisterShop = function(title, items, coords, groups) + return Inventory.CreateShop({id = title, name = title, items = items, coords = coords, groups = groups}) end +--- Creates a new shop if it doesn't already exist. +--- +--- @class ShopData +--- @field id string|nil -- Unique identifier for the shop (optional, falls back to title) +--- @field name string -- Display name of the shop +--- @field items table -- Table of items available in the shop +--- @field coords table|nil -- Optional coordinates for the shop location +--- @field groups table|nil -- Optional groups allowed to access the shop +--- +--- @param data ShopData -- Table containing shop properties +--- @return string|boolean -- Returns the shop ID if the shop was created, false if it already exists +Inventory.CreateShop = function(data) + assert(data, "CreateShop: data is required") + local id = data.id or data.name + if registeredShops[id] then return id end + assert(data.name, "CreateShop: name is required") + assert(data.items and type(data.items) == "table", "CreateShop: items table is required") + registeredShops[id] = { + name = data.name, + items = data.items, + coords = data.coords, + groups = data.groups + } + ox_inventory:RegisterShop(id, data) + return id +end ---UNUSED: ---This will return generic item data from the specified inventory, with the items total count.