dobrograd-13-06-2022/garrysmod/gamemodes/darkrp/gamemode/libraries/interfaceloader.lua

214 lines
6 KiB
Lua
Raw Normal View History

2023-11-16 15:01:19 +05:00
DarkRP = DarkRP or {}
DarkRP.PLAYER = FindMetaTable 'Player'
DarkRP.VECTOR = FindMetaTable 'Vector'
DarkRP.MetaName = "DarkRP"
-- Variables that maintain the existing stubs and hooks
local stubs = {}
local hookStubs = {}
-- Contains the functions that the hooks call by default
DarkRP.hooks = {}
-- Delay the calling of methods until the functions are implemented
local delayedCalls = {}
local returnsLayout, isreturns
local parameterLayout, isparameters
local isdeprecated
local checkStub
local hookLayout
local realm -- State variable to manage the realm of the stubs
/*---------------------------------------------------------------------------
Methods that check whether certain fields are valid
---------------------------------------------------------------------------*/
isreturns = function(tbl)
if not istable(tbl) then return false end
for k,v in pairs(tbl) do
if not checkStub(v, returnsLayout) then return false end
end
return true
end
isparameters = function(tbl)
if not istable(tbl) then return false end
for k,v in pairs(tbl) do
if not checkStub(v, parameterLayout) then return false end
end
return true
end
isdeprecated = function(val)
return val == nil or isstring(val)
end
/*---------------------------------------------------------------------------
The layouts of stubs
---------------------------------------------------------------------------*/
local stubLayout = {
name = isstring,
description = isstring,
deprecated = isdeprecated,
parameters = isparameters, -- the parameters of a method
returns = isreturns, -- the return values of a method
metatable = istable -- DarkRP, Player, Entity, Vector, ...
}
hookLayout = {
name = isstring,
description = isstring,
deprecated = isdeprecated,
parameters = isreturns, -- doesn't have the 'optional' field
returns = isreturns,
}
returnsLayout = {
name = isstring,
description = isstring,
type = isstring
}
parameterLayout = {
name = isstring,
description = isstring,
type = isstring,
optional = isbool
}
/*---------------------------------------------------------------------------
Check the validity of a stub
---------------------------------------------------------------------------*/
checkStub = function(tbl, stub)
if not istable(tbl) then return false, "table" end
for name, check in pairs(stub) do
if not check(tbl[name]) then
return false, name
end
end
return true
end
/*---------------------------------------------------------------------------
When a stub is called, the calling of the method is delayed
---------------------------------------------------------------------------*/
local function notImplemented(name, args, thisFunc)
if stubs[name] and stubs[name].metatable[name] ~= thisFunc then -- when calling the not implemented function after the function was implemented
return stubs[name].metatable[name](unpack(args))
end
delayedCalls[name] = delayedCalls[name] or {}
table.insert(delayedCalls[name], args)
return nil -- no return value because the method is not implemented
end
/*---------------------------------------------------------------------------
Generate a stub
---------------------------------------------------------------------------*/
function DarkRP.stub(tbl)
local isStub, field = checkStub(tbl, stubLayout)
if not isStub then
error("Invalid DarkRP method stub! Field \"" .. field .. "\" is invalid!", 2)
end
tbl.realm = tbl.realm or realm
stubs[tbl.name] = tbl
local function retNotImpl(...)
return notImplemented(tbl.name, {...}, retNotImpl)
end
return retNotImpl
end
/*---------------------------------------------------------------------------
Generate a hook stub
---------------------------------------------------------------------------*/
function DarkRP.hookStub(tbl)
local isStub, field = checkStub(tbl, hookLayout)
if not isStub then
error("Invalid DarkRP hook! Field \"" .. field .. "\" is invalid!", 2)
end
tbl.realm = tbl.realm or realm
hookStubs[tbl.name] = tbl
end
/*---------------------------------------------------------------------------
Retrieve the stubs
---------------------------------------------------------------------------*/
function DarkRP.getStubs()
return table.Copy(stubs)
end
/*---------------------------------------------------------------------------
Retrieve the hooks
---------------------------------------------------------------------------*/
function DarkRP.getHooks()
return table.Copy(hookStubs)
end
/*---------------------------------------------------------------------------
Call the cached methods
---------------------------------------------------------------------------*/
function DarkRP.finish()
local calls = table.Copy(delayedCalls) -- Loop through a copy, so the notImplemented function doesn't get called again
for name, log in pairs(calls) do
if not stubs[name] then ErrorNoHalt("Calling non-existing stub \"" .. name .. "\"") continue end
for _, args in pairs(log) do
stubs[name].metatable[name](unpack(args))
end
end
delayedCalls = {}
end
/*---------------------------------------------------------------------------
Load the interface files
---------------------------------------------------------------------------*/
local function loadInterfaces()
local root = GM.FolderName .. "/gamemode/modules"
local _, folders = file.Find(root .. "/*", "LUA")
ENTITY = FindMetaTable("Entity")
PLAYER = FindMetaTable("Player")
VECTOR = FindMetaTable("Vector")
for _, folder in SortedPairs(folders, true) do
local interfacefile = string.format("%s/%s/%s_interface.lua", root, folder, "%s")
local client = string.format(interfacefile, "cl")
local shared = string.format(interfacefile, "sh")
local server = string.format(interfacefile, "sv")
if file.Exists(shared, "LUA") then
if SERVER then AddCSLuaFile(shared) end
realm = "Shared"
include(shared)
end
if SERVER and file.Exists(client, "LUA") then
AddCSLuaFile(client)
end
if SERVER and file.Exists(server, "LUA") then
realm = "Server"
include(server)
end
if CLIENT and file.Exists(client, "LUA") then
realm = "Client"
include(client)
end
end
ENTITY, PLAYER, VECTOR = nil, nil, nil
end
loadInterfaces()