Files
community_bridge/components/Class.lua
T
2025-01-08 06:33:31 -05:00

154 lines
4.5 KiB
Lua

local Tables = Require('use/tables.lua')
local Ids = Require("use/ids.lua")
local AllInstances = {}
---@class Class
Class = {}
Class.ClassName = "Class"
Class.__call = function(this, ...)
return this:new(...)
end
Builders = {}
function Class.SetInstance(instance)
AllInstances[instance.id] = instance
end
function Class.GetInstance(id)
return AllInstances[id]
end
--- Default (empty) constructor
--- @param self Class
--- @vararg any
function Class:init(...) end
--- Creates a subclass of the current class.
--- This function copies the properties and methods of the current class to a new object.
--- It also sets up metatables to allow for object-oriented behavior, such as method calls and property access.
--- @param obj object | nil: The table to extend. If nil, a new table will be created.
--- @return obj object: The extended object with properties and methods from the given class obj.
function Class:extend(obj)
local className = obj.ClassName or "Class"
local old = Tables.DeepClone(self, {}, {components = true})
local new = Tables.DeepClone(obj, old, {ClassName = true})
new.components = self.components or {}
new.components[className] = obj
if not new.id then new.id = Ids.CreateUniqueId(new.components) end
-- create new objects directly, like o = Object()
self = setmetatable(new, Class)
if not Class.GetInstance(new.id) then Class.SetInstance(self) end
return self
end
--- Sets a property on the object. NOTE: This is mostly for internal purposes.
--- @param prop string|table: The property name or a table of properties to set.
--- @param value any: The value to set the property to.
function Class:set(prop, value)
if not value and type(prop) == "table" then
for k, v in pairs(prop) do
rawset(self._, k, v)
end
else
rawset(self._, prop, value)
end
end
--- This function is used to create a new instance of the class.
--- It calls the init function if it exists.
--- @vararg any: The arguments to pass to the init
--- @return object: The new instance of the class.
function Class:new(...)
local obj = self:extend({})
if obj.init then obj:init(...) end
return obj
end
--- This function is used to create a new instance of the class.
--- It calls the struct function if it exists.
--- @vararg object(s): List of objects to extend the class with.
--- @return object: The new instance of the class with the data and functions from the objects passed.
function class(className, ...)
local newObj = Class:extend({})
local components = table.pack(...)
newObj.ClassName = className
if components then
for k, v in pairs(components) do
local clName = v.ClassName
if not Builders[clName] then -- builders are used to reconstruct an object usually when pulled from server to client or vice versa
Builders[clName] = Tables.DeepClone(newObj)
end
end
end
if components.n > 0 then
for k, v in pairs(components) do
if k ~= "n" then
local newNewObject = nil
if v.Struct and type(v.Struct) == "function" then
newNewObject = v:Struct()
end
newObj = newObj:extend(newNewObject or v)
end
end
else
return newObj
end
return newObj
end
function reconstruct(obj)
local newTable = {}
local tbl = obj.components or {}
for k, v in pairs(tbl) do
local builder = Builders[k]
if builder then
newTable[k] = builder
end
end
return class(table.unpack(newTable))
end
--- Overwrites the type(self) value to return "Class".
--- @return string: The string "Class".
function Class:__type()
return self.ClassName or "Class"
end
--- Overwrites the call operator to call the new function. Ex: Class()
--- @vararg any: The arguments to pass to the new function.
--- @return object: The new instance of the class.
function Class:__call(...)
return self:new(...)
end
--- Checks to see if the class is an instance of the given class.
--- @param cls Class: The class to check against.
--- @return boolean: True if the class is an instance of the given class, false otherwise.
function Class:IsA(cls)
local p = promise.new()
CreateThread(function()
local m = getmetatable(self)
while m do
if m == cls then
return p:resolve(true)
end
m = getmetatable(m)
Wait(0)
end
return p:resolve(false)
end)
return Citizen.Await(p)
end
return {Class, class}