diff --git a/lua/acf/core/classes/helpers.lua b/lua/acf/core/classes/helpers.lua
index 992ff1e69..c5ca903ed 100644
--- a/lua/acf/core/classes/helpers.lua
+++ b/lua/acf/core/classes/helpers.lua
@@ -1,6 +1,7 @@
local Classes = ACF.Classes
-
+--- Adds an sbox limit for this class
+--- @param Data {Name:string, Amount:number, Text:string}
function Classes.AddSboxLimit(Data)
if CLIENT then return end
if ConVarExists("sbox_max" .. Data.Name) then return end
diff --git a/lua/acf/core/classes/object.lua b/lua/acf/core/classes/object.lua
index 89788b3cf..7ebcf8706 100644
--- a/lua/acf/core/classes/object.lua
+++ b/lua/acf/core/classes/object.lua
@@ -6,10 +6,14 @@ local Classes = ACF.Classes
local Stored = {}
local Queued = {}
-
+--- Creates a new instance of the provided class
+--- If the class has an "OnCalled" method defined, it will run that.
+--- @param Class table The class to create an instance of
+--- @return table # The newly created instance
local function CreateInstance(Class)
local New = {}
+ -- This simulates "instantiation" among other things (https://www.lua.org/pil/13.4.1.html)
setmetatable(New, { __index = table.Copy(Class) })
if New.OnCalled then
@@ -19,6 +23,9 @@ local function CreateInstance(Class)
return New
end
+--- Used to queue classes that are waiting for their base classes to be loaded
+--- @param ID string The id of the class to queue
+--- @param Base string The base class
local function QueueBaseClass(ID, Base)
if not Queued[Base] then
Queued[Base] = { [ID] = true }
@@ -27,26 +34,31 @@ local function QueueBaseClass(ID, Base)
end
end
+--- Updates/Initializes a metatable for a class and "parents" it to a base class
+--- @param Class table The class to be initialized/updated
+--- @param Base string The base class of the provided class
local function AttachMetaTable(Class, Base)
local OldMeta = getmetatable(Class) or {}
if Base then
- local BaseClass = Stored[Base]
+ local BaseClass = Stored[Base] -- Retrieve the base class from ID
if BaseClass then
- Class.BaseClass = BaseClass
- OldMeta.__index = BaseClass
+ Class.BaseClass = BaseClass -- Class' base class becomes BaseClass
+ OldMeta.__index = BaseClass -- Class inherits from BaseClass
else
QueueBaseClass(Class.ID, Base)
end
end
+ -- Update the "constructor" of the class to create an instance of the updated class
OldMeta.__call = function()
return CreateInstance(Class)
end
setmetatable(Class, OldMeta)
+ -- A tick later, classes will be guaranteed to have been loaded.
timer.Simple(0, function()
if Class.OnLoaded then
Class:OnLoaded()
@@ -58,6 +70,11 @@ local function AttachMetaTable(Class, Base)
end)
end
+--- Creates a new object with the given ID, as a subclass of the Base class provided
+--- @param ID string The ID of the new sub class to add
+--- @param Base string The ID of the base class the sub class will inherit from
+--- @param Destiny table A table that the new object will be indexed into, with the ID as key
+--- @return table # The created class
function Classes.AddObject(ID, Base, Destiny)
if not isstring(ID) then return end
if not istable(Destiny) then return end
@@ -67,8 +84,9 @@ function Classes.AddObject(ID, Base, Destiny)
Class.ID = ID
- AttachMetaTable(Class, Base)
+ AttachMetaTable(Class, Base) -- Attach a metatable to "Class" with "Base" as parent
+ -- If this class is a base class for other class(es), attach metatables to all its sub classes with itself as base class.
if Queued[ID] then
for K in pairs(Queued[ID]) do
AttachMetaTable(Stored[K], ID)
diff --git a/lua/acf/core/utilities/util_sv.lua b/lua/acf/core/utilities/util_sv.lua
index 893152d8f..74df8236d 100644
--- a/lua/acf/core/utilities/util_sv.lua
+++ b/lua/acf/core/utilities/util_sv.lua
@@ -57,6 +57,13 @@ do -- HTTP Request
end
end
+ --- Sends a fetch request to the given url with the given headers.
+ --- For further elaboration, please read this function's definition and SuccessfulRequest.
+ --- To better understand the inputs, please check: https://wiki.facepunch.com/gmod/http.Fetch.
+ --- @param Link string The HTTP endpoint to send a fetch request to
+ --- @param Headers table Headers to use in the HTTP request
+ --- @param OnSuccess fun(Body:string,Data:table)
+ --- @param OnFailure fun(Error:string)
function ACF.StartRequest(Link, OnSuccess, OnFailure, Headers)
if not isstring(Link) then return end
if not isfunction(OnSuccess) then OnSuccess = nil end
@@ -116,7 +123,9 @@ do -- HTTP Request
end)
end
-do -- Entity saving and restoring
+-- Entity saving and restoring
+-- Necessary because some components will update their physics object on update (e.g. ammo crates/scalable guns)
+do
local ConstraintTypes = duplicator.ConstraintType
local Entities = {}
@@ -226,7 +235,10 @@ do -- Entity saving and restoring
end
------------------------------------------------------------------------
-
+ --- Saves the physical properties/constraints/etc. of an entity to the "Entities" table.
+ --- Should be used before calling Update functions on ACF entities. Call RestoreEntity after.
+ --- Necessary because some components will update their physics object on update (e.g. ammo crates/scalable guns).
+ --- @param Entity table The entity to index
function ACF.SaveEntity(Entity)
if not IsValid(Entity) then return end
@@ -244,11 +256,16 @@ do -- Entity saving and restoring
ClearConstraints(Entity)
+ -- If for whatever reason the entity is removed before RestoreEntity is called,
+ -- Update the entity table
Entity:CallOnRemove("ACF_RestoreEntity", function()
Entities[Entity] = nil
end)
end
+ --- Sets the properties/constraints/etc of an entity from the "Entities" table.
+ --- Should be used after calling Update functions on ACF entities.
+ --- @param Entity table The entity to restore
function ACF.RestoreEntity(Entity)
if not IsValid(Entity) then return end
if not Entities[Entity] then return end
@@ -267,12 +284,36 @@ do -- Entity saving and restoring
Entities[Entity] = nil
+ -- Disables the CallOnRemove callback from earlier
Entity:RemoveCallOnRemove("ACF_RestoreEntity")
end
end
do -- Entity linking
+ --[[
+ Example structure of EntityLink:
+
+ EntityLink = {
+ ["acf_engine"] = {
+ ["FuelTanks"] = function(Entity)
+ return GetEntityLinks(Entity, "FuelTanks", nil)
+ end,
+ ["Gearboxes"] = function(Entity)
+ return GetEntityLinks(Entity, "Gearboxes", nil)
+ end
+ }
+ }
+
+ This example demonstrates that any entity of the acf_engine class has the fields FuelTanks and Gearboxes in its entity table that reference their respective link sources.
+ This is done to localize the functions for optimization reasons.
+ ]]--
local EntityLink = {}
+
+ --- Returns links to the entry.
+ --- @param Entity table The entity to check
+ --- @param VarName string The field of the entity that stores link sources (e.g. "Entity.FuelTanks" for engines)
+ --- @param SingleEntry boolean | nil Whether the entity supports a single source link or multiple
+ --- @return table
# A table whose keys are the link source entities and whose values are all true
local function GetEntityLinks(Entity, VarName, SingleEntry)
if not Entity[VarName] then return {} end
@@ -289,7 +330,13 @@ do -- Entity linking
return Result
end
- -- If your entity can link/unlink other entities, you should use this
+ --- Registers that all entities of this class have a field which refers to its link source(s).
+ --- If your entity can link/unlink other entities, you should use this.
+ --- Certain E2/SF functions require this in order to function (e.g. getting linked wheels of a gearbox).
+ --- Example usage: ACF.RegisterLinkSource("acf_engine", "FuelTanks")
+ --- @param Class string The name of the class
+ --- @param VarName string The field referencing one of the class's link source(s)
+ --- @param SingleEntry boolean | nil Whether the entity supports a single source link or multiple
function ACF.RegisterLinkSource(Class, VarName, SingleEntry)
local Data = EntityLink[Class]
@@ -306,6 +353,9 @@ do -- Entity linking
end
end
+ --- Returns all the link source callables for this entity.
+ --- @param Class string The name of the class
+ --- @return table # All the relevant link source callables
function ACF.GetAllLinkSources(Class)
if not EntityLink[Class] then return {} end
@@ -318,12 +368,19 @@ do -- Entity linking
return Result
end
+ --- Returns the link source callable of a given class and VarName.
+ --- @param Class string The name of the class
+ --- @param VarName string The varname for the given class
+ --- @return fun(Entity:table):table | nil # The link source callable, or nil if the class doesn't have one
function ACF.GetLinkSource(Class, VarName)
if not EntityLink[Class] then return end
return EntityLink[Class][VarName]
end
+ --- Returns a table of entities linked to the given entity.
+ --- @param Entity table The entity to get links from
+ --- @return table # A table mapping entities to true
function ACF.GetLinkedEntities(Entity)
if not IsValid(Entity) then return {} end
@@ -342,7 +399,28 @@ do -- Entity linking
return Result
end
+ --[[
+ Example structure of ClassLink:
+
+ ClassLink = {
+ ["Link"] = {
+ ["acf_ammo"] = {
+ ["acf_gun"] = function(Ent1, Ent2) -- Handles linking guns and ammo
+ }
+ },
+ ["Unlink"] = {
+ ["acf_ammo"] = {
+ ["acf_gun"] = function(Ent1, Ent2) -- Handles unlinking guns and ammo
+ }
+ }
+ }
+ ]]--
local ClassLink = { Link = {}, Unlink = {} }
+
+ --- Registers a link or unlink between two classes and how to handle them.
+ --- @param Class1 string The first class in the link
+ --- @param Class2 string The other class in the link
+ --- @param Function fun(Entity1:table, Entity2:table)
local function RegisterNewLink(Action, Class1, Class2, Function)
if not isfunction(Function) then return end
@@ -378,20 +456,36 @@ do -- Entity linking
end
end
+ --- Registers that two classes can be linked, as well as how to handle entities of their class being linked.
+ --- @param Class1 string The first class in the link
+ --- @param Class2 string The other class in the link
+ --- @param Function fun(Entity1:table, Entity2:table) The linking function defined between an entity of Class1 and an entity of Class2; this should always return a boolean for link status and a string for link message
function ACF.RegisterClassLink(Class1, Class2, Function)
RegisterNewLink("Link", Class1, Class2, Function)
end
+ --- Returns the callback defined previously by ACF.RegisterClassLink between Class1 and Class2.
+ --- @param Class1 string The first class in the link
+ --- @param Class2 string The other class in the link
+ --- @return fun(Entity1:table, Entity2:table) | nil # The linking function defined between an entity of Class1 and an entity of Class2, or nil if Class1 has no linking functions
function ACF.GetClassLink(Class1, Class2)
if not ClassLink.Link[Class1] then return end
return ClassLink.Link[Class1][Class2]
end
+ --- Registers that two classes can be unlinked, as well as how to handle entities of their class being unlinked.
+ --- @param Class1 string The first class in the link
+ --- @param Class2 string The other class in the link
+ --- @param Function fun(Entity1:table, Entity2:table) The unlinking function defined between an entity of Class1 and an entity of Class2
function ACF.RegisterClassUnlink(Class1, Class2, Function)
RegisterNewLink("Unlink", Class1, Class2, Function)
end
+ --- Returns the callback defined previously by ACF.RegisterClassUnlink between Class1 and Class2.
+ --- @param Class1 string The first class in the link
+ --- @param Class2 string The other class in the link
+ --- @return fun(Entity1:table, Entity2:table) | nil # The unlinking function defined between an entity of Class1 and an entity of Class2, or nil if Class1 has no unlinking functions
function ACF.GetClassUnlink(Class1, Class2)
if not ClassLink.Unlink[Class1] then return end
@@ -400,8 +494,20 @@ do -- Entity linking
end
do -- Entity inputs
+ --[[
+ Example structure of inputs:
+
+ Inputs = {
+ ["acf_ammo"] = {
+ ["Load"] = function(Entity, Value) -- Handles when the "Load" wire input is triggered
+ }
+ }
+ ]]--
local Inputs = {}
+ --- Returns the table mapping a class's inputs to a function that handles them.
+ --- @param Class string The class to get data from
+ --- @return table # A table of input names to functions that handle them
local function GetClass(Class)
if not Inputs[Class] then
Inputs[Class] = {}
@@ -410,6 +516,10 @@ do -- Entity inputs
return Inputs[Class]
end
+ --- For a given class, add an input action for when an input is triggered.
+ --- @param Class string The class to apply to
+ --- @param Name string The wire input to trigger on
+ --- @param Action fun(Entity:table, Value:any) The function that gets called when the wire input is triggered
function ACF.AddInputAction(Class, Name, Action)
if not Class then return end
if not Name then return end
@@ -420,6 +530,10 @@ do -- Entity inputs
Data[Name] = Action
end
+ --- Returns the callback defined previously by ACF.AddInputAction for the given class and wire input name.
+ --- @param Class string The class to retrieve from
+ --- @param Name string The wire input retrieve from
+ --- @return fun(Entity:table, Value:any) | nil # The callback for the given class and wire input name, or nil if the arguments are invalid
function ACF.GetInputAction(Class, Name)
if not Class then return end
if not Name then return end
@@ -429,6 +543,9 @@ do -- Entity inputs
return Data[Name]
end
+ --- For a given class, returns a table of wire input names mapped to their handlers, defined previously by ACF.AddInputAction.
+ --- @param Class string The class to retrieve from
+ --- @return table | nil # A table of wire input names mapped to their handlers, or nil if Class is invalid
function ACF.GetInputActions(Class)
if not Class then return end
@@ -437,8 +554,24 @@ do -- Entity inputs
end
do -- Extra overlay text
+ --[[
+ Example structure of Classes:
+
+ Classes = {
+ ["acf_ammo"] = {
+ ["Kinematic"] = function(Entity), -- Returns text containing muzzle vel, drag coef, etc.
+ ["Explosive"] = function(Entity) -- Returns text containing explosive mass, blast radius, etc.
+ }
+ }
+
+ *Note that unlike most examples this isn't actually used anywhere at the time of writing.*
+ ]]--
local Classes = {}
+ --- Registers a function that provides text for the overlay, with a given Identifier, for a given class.
+ --- @param ClassName string Name of the class to register for
+ --- @param Identifier string The identitifer to assosciate the function with
+ --- @param Function fun(Entity:table):string A function which takes the entity and returns some text for the identifier
function ACF.RegisterOverlayText(ClassName, Identifier, Function)
if not isstring(ClassName) then return end
if Identifier == nil then return end
@@ -455,6 +588,9 @@ do -- Extra overlay text
end
end
+ --- Removes an overlay callback defined previously by ACF.RegisterOverlayText.
+ --- @param ClassName string Name of the class to affect
+ --- @param Identifier string The identifier of the function to be removed
function ACF.RemoveOverlayText(ClassName, Identifier)
if not isstring(ClassName) then return end
if Identifier == nil then return end
@@ -466,6 +602,9 @@ do -- Extra overlay text
Class[Identifier] = nil
end
+ --- Given an entity, returns its overlay text, made by concatenating the overlay functions for its class.
+ --- @param Entity table The entity to generate overlay text for
+ --- @return string # The overlay text for this entity
function ACF.GetOverlayText(Entity)
local Class = Classes[Entity:GetClass()]
@@ -581,7 +720,7 @@ do -- Special squishy functions
DmgResult:SetThickness(0.01) -- squishy squishy brain matter, no resistance
HitRes = DmgResult:Compute()
- Damage = Damage + (HitRes.Damage * 50 * math.max(1,HitRes.Overkill * 0.25)) -- yuge damage, yo brains just got scrambled by a BOOLET
+ Damage = Damage + (HitRes.Damage * 50 * math.max(1, HitRes.Overkill * 0.25)) -- yuge damage, yo brains just got scrambled by a BOOLET
end
return Damage, HitRes
diff --git a/lua/acf/core/validation_sv.lua b/lua/acf/core/validation_sv.lua
index 6812f7a2a..e21a18365 100644
--- a/lua/acf/core/validation_sv.lua
+++ b/lua/acf/core/validation_sv.lua
@@ -204,6 +204,8 @@ function ACF.Check(Entity, ForceUpdate) -- IsValid but for ACF
return Entity.ACF.Type
end
+--- Initializes the entity's armor properties. If ACF_Activate is defined by the entity, that method is called as well.
+--- @param Recalc boolean Whether or not to recalculate the health
function ACF.Activate(Entity, Recalc)
-- Density of steel = 7.8g cm3 so 7.8kg for a 1mx1m plate 1m thick
local PhysObj = Entity:GetPhysicsObject()
diff --git a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua
index 1daef872a..75037a70f 100644
--- a/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua
+++ b/lua/entities/gmod_wire_expression2/core/custom/acffunctions.lua
@@ -40,6 +40,9 @@ local function GetReloadTime(Entity)
return (Unloading or NewLoad) and Entity.MagReload or Entity.ReloadTime or 0
end
+--- Returns a table of all the linked wheels of a given entity (usually a gearbox?)
+--- @param Target table Entity to get linked entities from
+--- @return table Linked The linked entities
local function GetLinkedWheels(Target)
local Queued = { [Target] = true }
local Checked = {}
@@ -54,8 +57,8 @@ local function GetLinkedWheels(Target)
Queued[Current] = nil
Checked[Current] = true
- for Name, Action in pairs(Sources) do
- for Entity in pairs(Action(Current)) do
+ for Name, Action in pairs(Sources) do -- For all source types
+ for Entity in pairs(Action(Current)) do -- For all entities of this source type
if not (Checked[Entity] or Queued[Entity]) then
if Name == "Wheels" then
Checked[Entity] = true
@@ -77,7 +80,7 @@ end
__e2setcost(2)
---returns current ACF drag divisor
+-- Returns current ACF drag divisor
e2function number acfDragDiv()
return ACF.DragDiv
end