Description
Goal
We need a plugin that implements some game specific behavior of Lua things, like Set/Get generation, auto class naming/detection.
OnSetText implementation
An example of a simple plugin that
- Expands preprocessor macro DEFINE_BASECLASS.
- Automatically classifies scripted ents by folder/filename and solves "duplicate field" inside the sent file.
---@class gmod_hands: ENT
local ENT = {}
... original file code with ENT usage
However, I don't want to use it in this form, because it's working with text, and it's reached the edge of its possibilities. For example, you can see that the first character of sent file is displayed in green, because I am injecting a fake class there.
Implementing a NetworkVar and AccessorFunc already seems impossible with a text.
---@class diff
---@field start integer # The number of bytes at the beginning of the replacement
---@field finish integer # The number of bytes at the end of the replacement
---@field text string # What to replace
local scopeFolders = {
{ "EFFECT", "effects" },
{ "SWEP", "weapons" },
{ "ENT", "entities" }
}
---@param uri string
---@return string?, string?
local function GetScopedClass(uri)
for _, scope in ipairs(scopeFolders) do
-- gamemode based uri:
-- .../gamemodes/my_gamemode/entities/entities/ent_class_name/any.lua
-- .../gamemodes/my_gamemode/entities/entities/ent_class_name.lua
local class = uri:match("%Wentities/" .. scope[2] .. "/([^/]+)/?[^/]*%.lua$")
if not class then
-- addon or root based uri:
-- .../addons/my_addon/lua/entities/ent_class_name/any.lua
-- .../addons/my_addon/lua/entities/ent_class_name.lua
class = uri:match("%Wlua/" .. scope[2] .. "/([^/]+)/?[^/]*%.lua$")
end
if class then
return scope[1], class
end
end
end
---@param uri string # The uri of file
---@param text string # The content of file
---@return diff[]?
function OnSetText(uri, text)
---@type diff[]
local diffs = {}
-- Detect "scripted" scope by folder and localize its global table to @class annotation.
local scope, class = GetScopedClass(uri)
if scope then
diffs[#diffs + 1] = {
start = 1,
finish = 1,
text = ([[
---@class %s: %s
local %s = {}
%s]]):format(class, scope, scope, text:sub(1, 1))
}
end
-- Replace preprocessor keyword DEFINE_BASECLASS.
for start, finish, b, c in text:gmatch("()DEFINE_BASECLASS()") do
diffs[#diffs + 1] = {
---@cast start integer
start = start,
finish = finish - 1,
text = "local BaseClass = baseclass.Get",
}
end
if #diffs == 0 then
return nil
end
return diffs
end
Completed features
- Expands preprocessor macro DEFINE_BASECLASS.
- Automatically classifies scopes of scripted ents (ENT, SWEP, EFFECT) by folder/filename. This is necessary step to add any methods to the class, and also solves "duplicate field" inside the sent file.
- It needs to be rewritten to
OnTransformAst
/VM.OnCompileFunctionParam
. - How to distribute a plugin with an addon?
- Implement NetworkVar/NetworkVarElement. It only works in sent file inside of ENT:SetupDataTables for
self:NetworkVar(...)
andself.NetworkVar(self, ...)
for stack defined arguments, not localized one.
Doesn't supportBaseClass.SetupDataTables(self)
.
Refs
Plugin samples
OnSetText
https://github.com/goldenstein64/lualogging-definitions/blob/13aabcde86b98c3bd3d2cacc0121f288496db045/plugin.lua
https://github.com/goldenstein64/pl-definitions/blob/54bf99b9d6394f6e9bab0fb2029ecf908db9a8cc/plugin.lua
https://github.com/serg3295/nodeMCU-emmylua/blob/232b42845e2f7a32ef8837417b409f5db666ecdf/plugin.lua
https://github.com/RavenfieldCommunity/RavenscriptIDEA/blob/7525a2eb431d27199e8c17aeceb872b1d559c4aa/plugin.lua
https://github.com/ProjectTH/fivem-lls-addon/blob/c93a8d64d0b541feda6b09b86961a7d62db2ee6d/plugin.lua
ResolveRequire
https://github.com/Periapsises/Starfall-LLS/blob/de36268b6218dca73b492176e8ef013b31bf3d6c/plugin.lua
OnCompileFunctionParam, ResolveRequire
https://github.com/Wild-W/smbx2-lunalua-luacats/blob/417401f1e6ade91809067bb2afac84f90109ab08/plugin.lua
OnTransformAst
https://github.com/LuaCATS/dontstarve/blob/42a8810744bb00266d733f9ed84b56b91fe74e94/plugin/dontstave.lua
https://github.com/DeadlyBossMods/LuaLS-Config/blob/main/Plugin/Mod-Class-Plugin.lua
Custom diagnostics:
LuaLS/lua-language-server#2511
https://github.com/DeadlyBossMods/LuaLS-Config/blob/main/Plugin/Event-Diagnostic.lua
TODO
- Implement AccessorFunc.
- Localize Set/Get class to
self: ent_myent
instead ofself: Entity
? - Lookup ents.Find* functions for existing classes instead of
T|Entity
(cannot castent_notdefined|Entity
toEntity
). - PANEL table auto classification by derma.DefineControl, vgui.Register.
- Maybe hook.Add/hook.Call/hook.Run.
- Research support for
BaseClass.SetupDataTables(self)
- Performance check.
I haven't had time for further research yet 😪