Skip to content

Commit

Permalink
Remove Link Store, Link Symmetry and Fix Issues
Browse files Browse the repository at this point in the history
- Removes LinkStore variables
- Link information is now stored in the direction registered, but retrieval will try either so to keep the way we link things the same
- Link functions will now be called with an additional `FromChip` parameter which specifies if the linkage comes from a chip.
- Links will now support a `ChipDelay` property which will apply the linkage a set time after the initial call. This should be used with the `RegisterClassCheck` function.
  • Loading branch information
LengthenedGradient committed Aug 29, 2024
1 parent ac3b9e9 commit 12e0443
Show file tree
Hide file tree
Showing 5 changed files with 116 additions and 74 deletions.
105 changes: 51 additions & 54 deletions lua/acf/core/utilities/util_sv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -415,81 +415,78 @@ do -- Entity linking
}
}
]]--
local ClassLink = { Link = {}, Unlink = {} }

--- Registers a link or unlink between two classes and how to handle them.
--- @class LinkFunction
--- @field Ent1 table The first entity in the link
--- @field Ent2 table The second entity in the link
--- @field FromChip boolean If the link is from a chip
--- @return boolean? Success Whether the link was successful
--- @return string? Message A message about the link status

--- @class LinkData
--- @field Link LinkFunction? The function to handle linking
--- @field Unlink LinkFunction? The function to handle unlinking
--- @field Check LinkFunction? The function to check the link status
--- @field ChipDelay number? The delay associated with the link if done via chip

--- @type table<string,table<string,LinkData>>
local ClassLink = { }

--- Initializes a link in the ClassLink table if it doesn't already exist and returns the result.
--- The Link is initialized directionally (InitLink(Class1,Class2) != InitLink(Class2,Class1))
--- @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

local Target = ClassLink[Action]
local Data1 = Target[Class1]

if not Data1 then
Target[Class1] = {
[Class2] = function(Ent1, Ent2)
return Function(Ent1, Ent2)
end
}
else
Data1[Class2] = function(Ent1, Ent2)
return Function(Ent1, Ent2)
end
end

if Class1 == Class2 then return end

local Data2 = Target[Class2]

if not Data2 then
Target[Class2] = {
[Class1] = function(Ent2, Ent1)
return Function(Ent1, Ent2)
end
}
else
Data2[Class1] = function(Ent2, Ent1)
return Function(Ent1, Ent2)
end
end
--- @return LinkData? LinkData The returned link
function ACF.InitLink(Class1, Class2)
if not ClassLink[Class1] then ClassLink[Class1] = {} end
if not ClassLink[Class1][Class2] then ClassLink[Class1][Class2] = {} end
return ClassLink[Class1][Class2]
end

--- Registers that two classes can be linked, as well as how to handle entities of their class being linked.
--- Attempts to retrieve link information from Class 1 to Class2, otherwise tries Class 2 to Class1. If link exists in either direction, return nil.
--- @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)
--- @return LinkData? LinkData The returned link
--- @return boolean Reversed Whether you should reverse your entity arguments when calling with entities
function ACF.GetClassLink(Class1, Class2)
if ClassLink[Class1] ~= nil and ClassLink[Class1][Class2] ~= nil then return ClassLink[Class1][Class2], false end
if ClassLink[Class2] ~= nil and ClassLink[Class2][Class1] ~= nil then return ClassLink[Class2][Class1], true end
return nil, false
end

--- Returns the callback defined previously by ACF.RegisterClassLink between Class1 and Class2.
--- 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
--- @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]
--- @param Function LinkFunction 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)
local LinkData = ACF.InitLink(Class1,Class2)
LinkData.Link = Function
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
--- @param Function LinkFunction The unlinking function defined between an entity of Class1 and an entity of Class2

Check warning on line 468 in lua/acf/core/utilities/util_sv.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Space after comma"

Style: Please add a space after the comma
function ACF.RegisterClassUnlink(Class1, Class2, Function)
RegisterNewLink("Unlink", Class1, Class2, Function)
local LinkData = ACF.InitLink(Class1, Class2)
LinkData.Unlink = Function
end

--- Returns the callback defined previously by ACF.RegisterClassUnlink between Class1 and Class2.
--- Registers a validation check between two classes.
--- @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
--- @param Function LinkFunction The checking function defined between an entity of Class1 and an entity of Class2
function ACF.RegisterClassCheck(Class1, Class2, Function)
local LinkData = ACF.InitLink(Class1, Class2)
LinkData.Check = Function
end

return ClassLink.Unlink[Class1][Class2]
--- Registers a chip delay between two classes.
--- @param Class1 string The first class in the link
--- @param Class2 string The other class in the link
--- @param ChipDelay number If the link happens from the chip, then delay it by this amount
function ACF.RegisterClassDelay(Class1, Class2, ChipDelay)
local LinkData = ACF.InitLink(Class1, Class2)
LinkData.ChipDelay = ChipDelay
end
end

Expand Down
40 changes: 31 additions & 9 deletions lua/entities/acf_base_scalable/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,35 @@ do -- Entity linking and unlinking --------------
local LinkText = "%s can't be linked to %s."
local UnlinkText = "%s can't be unlinked from %s."

function ENT:Link(Target)
function ENT:Link(Target, FromChip)
if not IsValid(Target) then return false, "Attempted to link an invalid entity." end
if self == Target then return false, "Can't link an entity to itself." end

local Class = Target:GetClass()
local Function = ACF.GetClassLink(self:GetClass(), Class)
local LinkData, Reversed = ACF.GetClassLink(self:GetClass(), Class)

if LinkData == nil then return false, "Links between these two entities are impossible" end

local Function = LinkData.Link
local Check = LinkData.Check
local ChipDelay = LinkData.ChipDelay

local A, B = self, Target -- Default argument order
if Reversed then A, B = Target, self end -- If reversed, reverse argument order

if Function then
return Function(self, Target)
elseif self.DefaultLink then
return self:DefaultLink(Target)
if Check then
local result, message = Check(A, B)
if result then
if FromChip and ChipDelay then
timer.Simple(ChipDelay,function()

Check warning on line 86 in lua/entities/acf_base_scalable/init.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Space after comma"

Style: Please add a space after the comma
if Check(A, B) then Function(A, B) end
end)
else Function(A,B) end

Check warning on line 89 in lua/entities/acf_base_scalable/init.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Space after comma"

Style: Please add a space after the comma
end
return result, message
end
return Function(A, B)
end

return false, LinkText:format(self.PluralName, Target.PluralName or Class)
Expand All @@ -83,12 +101,16 @@ do -- Entity linking and unlinking --------------
if self == Target then return false, "Can't unlink an entity from itself." end

local Class = Target:GetClass()
local Function = ACF.GetClassUnlink(self:GetClass(), Class)
local LinkData, Reversed = ACF.GetClassLink(self:GetClass(), Class)
local Function = LinkData.Unlink

if LinkData == nil then return false, "Links between these two entities are impossible" end

local A, B = self, Target -- Default argument order
if Reversed then A, B = Target, self end -- If reversed, reverse argument order

if Function then
return Function(self, Target)
elseif self.DefaultUnlink then
return self:DefaultUnlink(Target)
return Function(A, B)
end

return false, UnlinkText:format(self.PluralName, Target.PluralName or Class)
Expand Down
41 changes: 32 additions & 9 deletions lua/entities/acf_base_simple/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -62,17 +62,35 @@ do -- Entity linking and unlinking --------------
local LinkText = "%s can't be linked to %s."
local UnlinkText = "%s can't be unlinked from %s."

function ENT:Link(Target)
function ENT:Link(Target, FromChip)
if not IsValid(Target) then return false, "Attempted to link an invalid entity." end
if self == Target then return false, "Can't link an entity to itself." end

local Class = Target:GetClass()
local Function = ACF.GetClassLink(self:GetClass(), Class)
local LinkData, Reversed = ACF.GetClassLink(self:GetClass(), Class)

if LinkData == nil then return false, "Links between these two entities are impossible" end

local Function = LinkData.Link
local Check = LinkData.Check
local ChipDelay = LinkData.ChipDelay

local A, B = self, Target -- Default argument order
if Reversed then A, B = Target, self end -- If reversed, reverse argument order

if Function then
return Function(self, Target)
elseif self.DefaultLink then
return self:DefaultLink(Target)
if Check then
local result, message = Check(A, B)
if result then
if FromChip and ChipDelay then
timer.Simple(ChipDelay,function()

Check warning on line 86 in lua/entities/acf_base_simple/init.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Space after comma"

Style: Please add a space after the comma
if Check(A, B) then Function(A, B) end
end)
else Function(A,B) end

Check warning on line 89 in lua/entities/acf_base_simple/init.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Space after comma"

Style: Please add a space after the comma
end
return result, message
end
return Function(A, B)
end

return false, LinkText:format(self.PluralName, Target.PluralName or Class)
Expand All @@ -83,12 +101,17 @@ do -- Entity linking and unlinking --------------
if self == Target then return false, "Can't unlink an entity from itself." end

local Class = Target:GetClass()
local Function = ACF.GetClassUnlink(self:GetClass(), Class)
local LinkData, Reversed = ACF.GetClassLink(self:GetClass(), Class)

if LinkData == nil then return false, "Links between these two entities are impossible" end

local Function = LinkData.Unlink

local A, B = self, Target -- Default argument order
if Reversed then A, B = Target, self end -- If reversed, reverse argument order

if Function then
return Function(self, Target)
elseif self.DefaultUnlink then
return self:DefaultUnlink(Target)
return Function(A, B)
end

return false, UnlinkText:format(self.PluralName, Target.PluralName or Class)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -348,7 +348,7 @@ e2function number entity:acfLinkTo(entity Target, number Notify)
return 0
end

local Sucess, Message = this:Link(Target)
local Sucess, Message = this:Link(Target,true)

if Notify ~= 0 then
ACF.SendNotify(self.player, Sucess, Message)
Expand Down
2 changes: 1 addition & 1 deletion lua/starfall/libs_sh/acffunctions.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1105,7 +1105,7 @@ if SERVER then
CheckPerms(instance, This, "entities.acf")
CheckPerms(instance, Target, "entities.acf")

local Success, Message = This:Link(Target)
local Success, Message = This:Link(Target,true)

Check warning on line 1108 in lua/starfall/libs_sh/acffunctions.lua

View workflow job for this annotation

GitHub Actions / Lint / lint

"Space after comma"

Style: Please add a space after the comma

if notify then
ACF.SendNotify(instance.player, Success, Message)
Expand Down

0 comments on commit 12e0443

Please sign in to comment.