add sborka
This commit is contained in:
816
garrysmod/addons/luadev/lua/autorun/easylua.lua
Normal file
816
garrysmod/addons/luadev/lua/autorun/easylua.lua
Normal file
@@ -0,0 +1,816 @@
|
||||
easylua = {} local s = easylua
|
||||
|
||||
local _R = debug.getregistry()
|
||||
|
||||
local function compare(a, b)
|
||||
|
||||
if a == b then return true end
|
||||
if a:find(b, nil, true) then return true end
|
||||
if a:lower() == b:lower() then return true end
|
||||
if a:lower():find(b:lower(), nil, true) then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function comparenick(a, b)
|
||||
local MatchTransliteration = GLib and GLib.UTF8 and GLib.UTF8.MatchTransliteration
|
||||
if not MatchTransliteration then return compare (a, b) end
|
||||
|
||||
if a == b then return true end
|
||||
if a:lower() == b:lower() then return true end
|
||||
if MatchTransliteration(a, b) then return true end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local function compareentity(ent, str)
|
||||
if ent.GetName and compare(ent:GetName(), str) then
|
||||
return true
|
||||
end
|
||||
|
||||
if ent:GetModel() and compare(ent:GetModel(), str) then
|
||||
return true
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
local TagPrintOnServer = "elpos"
|
||||
if CLIENT then
|
||||
function easylua.PrintOnServer(...)
|
||||
local args = {...}
|
||||
local new = {}
|
||||
|
||||
for key, value in pairs(args) do
|
||||
table.insert(new, luadata and luadata.ToString(value) or tostring(value))
|
||||
end
|
||||
net.Start(TagPrintOnServer)
|
||||
local str = table.concat(new," ")
|
||||
local max = 256
|
||||
net.WriteString(str:sub(1,max))
|
||||
net.WriteBool(#str>max)
|
||||
net.SendToServer()
|
||||
end
|
||||
else
|
||||
util.AddNetworkString(TagPrintOnServer)
|
||||
end
|
||||
|
||||
function easylua.Print(...)
|
||||
if CLIENT then
|
||||
easylua.PrintOnServer(...)
|
||||
end
|
||||
if SERVER then
|
||||
local args = {...}
|
||||
local str = ""
|
||||
|
||||
Msg(string.format("[ELua %s] ", IsValid(me) and me:Nick() or "Sv"))
|
||||
|
||||
for key, value in pairs(args) do
|
||||
str = str .. type(value) == "string" and value or luadata.ToString(value) or tostring(value)
|
||||
|
||||
if key ~= #args then
|
||||
str = str .. ","
|
||||
end
|
||||
end
|
||||
|
||||
print(str)
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
-- Rate limiting, still bad
|
||||
local spams=setmetatable({},{__mode='k'})
|
||||
local function canspam(pl,len)
|
||||
local now = RealTime()
|
||||
local nextspam = spams[pl] or 0
|
||||
if now>nextspam then
|
||||
nextspam = now + len>100 and 3 or 1
|
||||
spams[pl] = nextspam
|
||||
return true
|
||||
else
|
||||
local plstr = tostring(pl)
|
||||
timer.Create("easylua_pspam",5,1,function()
|
||||
Msg "[Easylua Print] Lost messages due to spam: " print(plstr)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
function easylua.CMDPrint(ply, cmd, args, fulln)
|
||||
if not canspam(ply,#fulln) then
|
||||
return
|
||||
end
|
||||
args = table.concat(args, ", ")
|
||||
|
||||
Msg(string.format("[ELua %s] ", IsValid(ply) and ply:Nick() or "Sv"))
|
||||
print(args)
|
||||
end
|
||||
concommand.Add("easylua_print", easylua.CMDPrint)
|
||||
|
||||
net.Receive(TagPrintOnServer,function(len,ply)
|
||||
local str = net.ReadString()
|
||||
if not canspam(ply,#str) then return end
|
||||
str=str:sub(1,512)
|
||||
local more = net.ReadBool()
|
||||
Msg(string.format("[ELua %s] ", IsValid(ply) and ply:Nick() or "Sv"))
|
||||
local outstr = ('%s%s'):format(str,more and "..." or ""):gsub("[\r\n]"," ")
|
||||
print(outstr)
|
||||
end)
|
||||
end
|
||||
|
||||
function easylua.FindEntity(str)
|
||||
if not str then return NULL end
|
||||
|
||||
str = tostring(str)
|
||||
|
||||
if str == "#this" and IsEntity(this) and this:IsValid() then
|
||||
return this
|
||||
end
|
||||
|
||||
if str == "#owner" and IsEntity(this) and this:IsValid() then
|
||||
local owner = this.CPPIGetOwner and this:CPPIGetOwner() or this:GetOwner()
|
||||
return owner
|
||||
end
|
||||
|
||||
if str == "#me" and IsEntity(me) and me:IsPlayer() then
|
||||
return me
|
||||
end
|
||||
|
||||
if str == "#all" then
|
||||
return all
|
||||
end
|
||||
|
||||
if str == "#afk" then
|
||||
return afk
|
||||
end
|
||||
|
||||
if str == "#us" then
|
||||
return us
|
||||
end
|
||||
|
||||
if str == "#them" then
|
||||
return them
|
||||
end
|
||||
|
||||
if str == "#friends" then
|
||||
return friends
|
||||
end
|
||||
|
||||
if str == "#humans" then
|
||||
return humans
|
||||
end
|
||||
|
||||
if str == "#bots" then
|
||||
return bots
|
||||
end
|
||||
|
||||
if str == "#randply" then
|
||||
return table.Random(player.GetAll())
|
||||
end
|
||||
|
||||
if str:sub(1,1) == "#" then
|
||||
local str = str:sub(2)
|
||||
|
||||
if #str > 0 then
|
||||
str = str:lower()
|
||||
local found
|
||||
|
||||
for teamid, data in pairs(team.GetAllTeams()) do
|
||||
if data.Name:lower() == str then
|
||||
found = teamid
|
||||
break
|
||||
end
|
||||
end
|
||||
if found then
|
||||
return CreateAllFunction(function()
|
||||
local t = {}
|
||||
for k,v in next,player.GetAll() do
|
||||
if v:IsPlayer() and v:Team() == found then
|
||||
t[#t+1] = v
|
||||
end
|
||||
end
|
||||
return t
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
for key, ent in ipairs(ents.GetAll()) do
|
||||
if ent:GetClass():lower() == str then
|
||||
found = str
|
||||
break
|
||||
end
|
||||
end
|
||||
if found then
|
||||
return CreateAllFunction(function()
|
||||
return ents.FindByClass(found)
|
||||
end)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- unique id
|
||||
local ply = player.GetByUniqueID(str)
|
||||
if ply and ply:IsPlayer() then
|
||||
return ply
|
||||
end
|
||||
|
||||
-- steam id
|
||||
if str:find("STEAM") then
|
||||
for key, _ply in ipairs(player.GetAll()) do
|
||||
if _ply:SteamID() == str then
|
||||
return _ply
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if str:sub(1,1) == "_" and tonumber(str:sub(2)) then
|
||||
str = str:sub(2)
|
||||
end
|
||||
|
||||
if tonumber(str) then
|
||||
ply = Entity(tonumber(str))
|
||||
if ply:IsValid() then
|
||||
return ply
|
||||
end
|
||||
end
|
||||
|
||||
-- community id
|
||||
if #str == 17 and str[1] == "7" then
|
||||
local ply = player.GetBySteamID64(str)
|
||||
if ply and ply:IsValid() then
|
||||
return ply
|
||||
end
|
||||
end
|
||||
|
||||
-- ip
|
||||
if SERVER then
|
||||
if str:find("%d+%.%d+%.%d+%.%d+") then
|
||||
for key, _ply in ipairs(player.GetAll()) do
|
||||
if _ply:IPAddress():find(str) then
|
||||
return _ply
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- search in sensible order
|
||||
|
||||
-- search exact
|
||||
for _,ply in ipairs(player.GetAll()) do
|
||||
if ply:Nick()==str then
|
||||
return ply
|
||||
end
|
||||
end
|
||||
|
||||
-- Search bots so we target those first
|
||||
for key, ply in ipairs(player.GetBots()) do
|
||||
if comparenick(ply:Nick(), str) then
|
||||
return ply
|
||||
end
|
||||
end
|
||||
|
||||
-- search from beginning of nick
|
||||
for _,ply in ipairs(player.GetHumans()) do
|
||||
if ply:Nick():lower():find(str,1,true)==1 then
|
||||
return ply
|
||||
end
|
||||
end
|
||||
|
||||
-- Search normally and search with colorcode stripped
|
||||
for key, ply in ipairs(player.GetAll()) do
|
||||
if comparenick(ply:Nick(), str) then
|
||||
return ply
|
||||
end
|
||||
|
||||
if _G.UndecorateNick and comparenick( UndecorateNick( ply:Nick() ), str) then
|
||||
return ply
|
||||
end
|
||||
end
|
||||
|
||||
-- search RealName
|
||||
if _R.Player.RealName then
|
||||
for _, ply in ipairs(player.GetAll()) do
|
||||
if comparenick(ply:RealNick(), str) then
|
||||
return ply
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if IsValid(me) and me:IsPlayer() then
|
||||
local tr = me:GetEyeTrace()
|
||||
local plpos = tr and tr.HitPos or me:GetPos()
|
||||
local closest,mind = nil,math.huge
|
||||
for key, ent in ipairs(ents.GetAll()) do
|
||||
local d = ent:GetPos():DistToSqr(plpos)
|
||||
if d < mind and compareentity(ent, str) then
|
||||
closest = ent
|
||||
mind = d
|
||||
end
|
||||
end
|
||||
if closest then
|
||||
return closest
|
||||
end
|
||||
else
|
||||
for key, ent in ipairs(ents.GetAll()) do
|
||||
if compareentity(ent, str) then
|
||||
return ent
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do -- class
|
||||
|
||||
local _str, idx = str:match("(.-)(%d+)$")
|
||||
if idx then
|
||||
idx = tonumber(idx)
|
||||
str = _str
|
||||
else
|
||||
str = str
|
||||
idx = (me and me.easylua_iterator) or 0
|
||||
|
||||
if me and isentity(me) and me:IsPlayer() then
|
||||
|
||||
local tr = me:GetEyeTrace()
|
||||
local plpos = tr and tr.HitPos or me:GetPos()
|
||||
local closest,mind = nil,math.huge
|
||||
for key, ent in ipairs(ents.GetAll()) do
|
||||
local d = ent:GetPos():DistToSqr(plpos)
|
||||
if d < mind and compare(ent:GetClass(), str) then
|
||||
closest = ent
|
||||
mind = d
|
||||
end
|
||||
end
|
||||
if closest then
|
||||
return closest
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local found = {}
|
||||
|
||||
for key, ent in ipairs(ents.GetAll()) do
|
||||
if compare(ent:GetClass(), str) then
|
||||
table.insert(found, ent)
|
||||
end
|
||||
end
|
||||
|
||||
return found[math.Clamp(idx%#found, 1, #found)] or NULL
|
||||
end
|
||||
end
|
||||
|
||||
function easylua.CreateEntity(class, callback)
|
||||
local mdl = "error.mdl"
|
||||
|
||||
if IsEntity(class) and class:IsValid() then
|
||||
this = class
|
||||
elseif class:find(".mdl", nil, true) then
|
||||
mdl = class
|
||||
class = "prop_physics"
|
||||
|
||||
this = ents.Create(class)
|
||||
this:SetModel(mdl)
|
||||
else
|
||||
this = ents.Create(class)
|
||||
end
|
||||
|
||||
if callback and type(callback) == 'function' then
|
||||
callback(this);
|
||||
end
|
||||
|
||||
this:Spawn()
|
||||
this:SetPos(there + Vector(0,0,this:BoundingRadius() * 2))
|
||||
this:DropToFloor()
|
||||
this:PhysWake()
|
||||
|
||||
undo.Create(class)
|
||||
undo.SetPlayer(me)
|
||||
undo.AddEntity(this)
|
||||
undo.Finish()
|
||||
|
||||
me:AddCleanup("props", this)
|
||||
|
||||
return this
|
||||
end
|
||||
|
||||
function easylua.CopyToClipboard(var, ply)
|
||||
ply = ply or me
|
||||
if luadata then
|
||||
local str = luadata.ToString(var)
|
||||
|
||||
if not str and IsEntity(var) and var:IsValid() then
|
||||
if var:IsPlayer() then
|
||||
str = string.format("player.GetByUniqueID(--[[%s]] %q)", var:GetName(), var:UniqueID())
|
||||
else
|
||||
str = string.format("Entity(%i)", var:EntIndex())
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
SetClipboardText(str)
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
local str = string.format("SetClipboardText(%q)", str)
|
||||
if #str > 255 then
|
||||
if luadev and luadev.RunOnClient then
|
||||
luadev.RunOnClient(str, ply)
|
||||
else
|
||||
error("Text too long to send and luadev not found",1)
|
||||
end
|
||||
else
|
||||
ply:SendLua(str)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local started = false
|
||||
function easylua.Start(ply)
|
||||
if started then
|
||||
Msg"[ELua] "print("Session not ended for ",_G.me or (s.vars and s.vars.me),", restarting session for",ply)
|
||||
easylua.End()
|
||||
end
|
||||
started = true
|
||||
|
||||
ply = ply or CLIENT and LocalPlayer() or nil
|
||||
|
||||
if not ply or not IsValid(ply) then return end
|
||||
|
||||
local vars = {}
|
||||
local trace = util.QuickTrace(ply:EyePos(), ply:GetAimVector() * 10000, {ply, ply:GetVehicle()})
|
||||
|
||||
if trace.Entity:IsWorld() then
|
||||
trace.Entity = NULL
|
||||
end
|
||||
|
||||
vars.me = ply
|
||||
vars.this = trace.Entity
|
||||
vars.wep = ply:GetActiveWeapon()
|
||||
vars.veh = ply:GetVehicle()
|
||||
|
||||
vars.we = {}
|
||||
|
||||
for k, v in ipairs(ents.FindInSphere(ply:GetPos(), 512)) do
|
||||
if v:IsPlayer() then
|
||||
table.insert(vars.we, v)
|
||||
end
|
||||
end
|
||||
|
||||
vars.there = trace.HitPos
|
||||
vars.here = trace.StartPos
|
||||
vars.dir = ply:GetAimVector()
|
||||
|
||||
vars.trace = trace
|
||||
vars.length = trace.StartPos:Distance(trace.HitPos)
|
||||
|
||||
vars.copy = s.CopyToClipboard
|
||||
vars.create = s.CreateEntity
|
||||
vars.prints = s.PrintOnServer
|
||||
|
||||
if vars.this:IsValid() then
|
||||
vars.phys = vars.this:GetPhysicsObject()
|
||||
vars.model = vars.this:GetModel()
|
||||
end
|
||||
|
||||
vars.E = s.FindEntity
|
||||
vars.last = ply.easylua_lastvars
|
||||
|
||||
|
||||
s.vars = vars
|
||||
local old_G = {}
|
||||
s.oldvars = old_G
|
||||
|
||||
for k, v in pairs(vars) do
|
||||
old_G[k] = rawget(_G, k)
|
||||
rawset(_G, k, v)
|
||||
end
|
||||
|
||||
-- let this gc. maybe allow few more recursions.
|
||||
if vars.last and istable(vars.last) then vars.last.last = nil end
|
||||
|
||||
ply.easylua_lastvars = vars
|
||||
ply.easylua_iterator = (ply.easylua_iterator or 0) + 1
|
||||
end
|
||||
|
||||
function easylua.End()
|
||||
if not started then
|
||||
Msg"[ELua] "print"Ending session without starting"
|
||||
end
|
||||
started = false
|
||||
|
||||
if s.vars then
|
||||
for key, value in pairs(s.vars) do
|
||||
if s.oldvars and s.oldvars[key] then
|
||||
rawset(_G, key, s.oldvars[key])
|
||||
else
|
||||
rawset(_G, key, nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
do -- env meta
|
||||
local META = {}
|
||||
|
||||
local _G = _G
|
||||
local easylua = easylua
|
||||
local tonumber = tonumber
|
||||
|
||||
local nils={
|
||||
["CLIENT"]=true,
|
||||
["SERVER"]=true,
|
||||
}
|
||||
function META:__index(key)
|
||||
local var = _G[key]
|
||||
|
||||
if var ~= nil then
|
||||
return var
|
||||
end
|
||||
|
||||
if not nils [key] then -- uh oh
|
||||
var = easylua.FindEntity(key)
|
||||
if var:IsValid() then
|
||||
return var
|
||||
end
|
||||
end
|
||||
|
||||
return nil
|
||||
end
|
||||
|
||||
function META:__newindex(key, value)
|
||||
_G[key] = value
|
||||
end
|
||||
|
||||
easylua.EnvMeta = setmetatable({}, META)
|
||||
end
|
||||
|
||||
function easylua.RunLua(ply, code, env_name)
|
||||
local data =
|
||||
{
|
||||
error = false,
|
||||
args = {},
|
||||
}
|
||||
|
||||
easylua.Start(ply)
|
||||
if s.vars then
|
||||
local header = ""
|
||||
|
||||
for key, value in next,(s.vars or {}) do
|
||||
header = header .. string.format("local %s = %s ", key, key)
|
||||
end
|
||||
|
||||
code = header .. "; " .. code
|
||||
end
|
||||
|
||||
env_name = env_name or string.format("%s", tostring(
|
||||
IsValid(ply) and ply:IsPlayer()
|
||||
and "["..ply:SteamID():gsub("STEAM_","").."]"..ply:Name()
|
||||
or ply))
|
||||
|
||||
data.env_name = env_name
|
||||
|
||||
local func = CompileString(code, env_name, false)
|
||||
|
||||
if type(func) == "function" then
|
||||
setfenv(func, easylua.EnvMeta)
|
||||
|
||||
local args = {pcall(func)}
|
||||
|
||||
if args[1] == false then
|
||||
data.error = args[2]
|
||||
end
|
||||
|
||||
table.remove(args, 1)
|
||||
data.args = args
|
||||
else
|
||||
data.error = func
|
||||
end
|
||||
easylua.End()
|
||||
|
||||
return data
|
||||
end
|
||||
|
||||
-- legacy luadev compatibility
|
||||
|
||||
local STAGE_PREPROCESS=1
|
||||
local STAGE_COMPILED=2
|
||||
local STAGE_POST=3
|
||||
|
||||
local insession = false
|
||||
hook.Add("LuaDevProcess","easylua",function(stage,script,info,extra,func)
|
||||
if stage==STAGE_PREPROCESS then
|
||||
|
||||
if insession then
|
||||
insession=false
|
||||
easylua.End()
|
||||
end
|
||||
|
||||
if not istable(extra) or not IsValid(extra.ply) or not script or extra.easylua==false then
|
||||
return
|
||||
end
|
||||
|
||||
insession = true
|
||||
easylua.Start(extra.ply)
|
||||
|
||||
local t={}
|
||||
for key, value in pairs(easylua.vars or {}) do
|
||||
t[#t+1]=key
|
||||
end
|
||||
if #t>0 then
|
||||
script=' local '..table.concat(t,", ")..' = '..table.concat(t,", ")..' ; '..script
|
||||
end
|
||||
|
||||
--ErrorNoHalt(script)
|
||||
return script
|
||||
|
||||
elseif stage==STAGE_COMPILED then
|
||||
|
||||
if not istable(extra) or not IsValid(extra.ply) or not isfunction(func) or extra.easylua==false then
|
||||
if insession then
|
||||
insession=false
|
||||
easylua.End()
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if insession then
|
||||
local env = getfenv(func)
|
||||
if not env or env==_G then
|
||||
setfenv(func, easylua.EnvMeta)
|
||||
end
|
||||
end
|
||||
|
||||
elseif stage == STAGE_POST and insession then
|
||||
insession=false
|
||||
easylua.End()
|
||||
end
|
||||
end)
|
||||
|
||||
function easylua.StartWeapon(classname)
|
||||
_G.SWEP = {
|
||||
Primary = {},
|
||||
Secondary = {},
|
||||
ViewModelFlip = false,
|
||||
}
|
||||
|
||||
SWEP.Base = "weapon_base"
|
||||
|
||||
SWEP.ClassName = classname
|
||||
end
|
||||
|
||||
function easylua.EndWeapon(spawn, reinit)
|
||||
if not SWEP then error"missing SWEP" end
|
||||
if not SWEP.ClassName then error"missing classname" end
|
||||
|
||||
weapons.Register(SWEP, SWEP.ClassName)
|
||||
|
||||
for key, entity in ipairs(ents.FindByClass(SWEP.ClassName)) do
|
||||
--if entity:GetTable() then table.Merge(entity:GetTable(), SWEP) end
|
||||
if reinit then
|
||||
entity:Initialize()
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER and spawn then
|
||||
SafeRemoveEntity(me:GetWeapon(SWEP.ClassName))
|
||||
local me = me
|
||||
local class = SWEP.ClassName
|
||||
timer.Simple(0.2, function() if me:IsPlayer() then me:Give(class) end end)
|
||||
end
|
||||
|
||||
SWEP = nil
|
||||
end
|
||||
|
||||
function easylua.StartEntity(classname)
|
||||
_G.ENT = {}
|
||||
|
||||
ENT.ClassName = classname or "no_ent_name_" .. me:Nick() .. "_" .. me:UniqueID()
|
||||
end
|
||||
|
||||
function easylua.EndEntity(spawn, reinit)
|
||||
|
||||
ENT.Model = ENT.Model or Model("models/props_borealis/bluebarrel001.mdl")
|
||||
|
||||
if not ENT.Base then -- there can be Base without Type but no Type without base without redefining every function so um
|
||||
ENT.Base = "base_anim"
|
||||
ENT.Type = ENT.Type or "anim"
|
||||
end
|
||||
|
||||
scripted_ents.Register(ENT, ENT.ClassName)
|
||||
|
||||
for key, entity in ipairs(ents.FindByClass(ENT.ClassName)) do
|
||||
--table.Merge(entity:GetTable(), ENT)
|
||||
if reinit then
|
||||
entity:Initialize()
|
||||
end
|
||||
end
|
||||
|
||||
if SERVER and spawn then
|
||||
create(ENT.ClassName)
|
||||
end
|
||||
|
||||
ENT = nil
|
||||
end
|
||||
|
||||
do -- all
|
||||
include("tinylua.lua") -- Force it to load before we use it
|
||||
local next = next
|
||||
local type = type
|
||||
|
||||
local INTERNAL = {}
|
||||
local META = {}
|
||||
|
||||
function META:__call()
|
||||
error("Undefined __call")
|
||||
end
|
||||
|
||||
function META:__index(key)
|
||||
local wrapped = tinylua(self())
|
||||
return wrapped[key]
|
||||
end
|
||||
|
||||
function META:__newindex(key, value)
|
||||
local wrapped = tinylua(self())
|
||||
wrapped[key] = value
|
||||
end
|
||||
|
||||
function CreateAllFunction(filter, inputTbl)
|
||||
local allMeta = {}
|
||||
|
||||
for ind, metamethod in pairs(META)do
|
||||
allMeta[ind] = metamethod
|
||||
end
|
||||
|
||||
function allMeta:__call()
|
||||
return (isfunction(filter) and filter() or filter)
|
||||
end
|
||||
|
||||
return setmetatable(inputTbl or {}, allMeta)
|
||||
end
|
||||
|
||||
function INTERNAL:get()
|
||||
return self()
|
||||
end
|
||||
|
||||
all = CreateAllFunction(player.GetAll)
|
||||
humans = CreateAllFunction(player.GetHumans)
|
||||
bots = CreateAllFunction(player.GetBots)
|
||||
afk = CreateAllFunction(function()
|
||||
local t = {}
|
||||
for k,v in ipairs(player.GetAll()) do
|
||||
if not v.IsAFK then break end
|
||||
if v:IsAFK() then
|
||||
t[#t+1] = v
|
||||
end
|
||||
end
|
||||
return t
|
||||
end)
|
||||
us = CreateAllFunction(function()
|
||||
if _G.we then return _G.we end
|
||||
if _G.me then return {_G.me} end
|
||||
return {}
|
||||
end)
|
||||
them = CreateAllFunction(function()
|
||||
local me = _G.me
|
||||
local we = _G.we or {}
|
||||
table.RemoveByValue(we, me)
|
||||
return we
|
||||
end)
|
||||
friends = CreateAllFunction(function()
|
||||
local me = _G.me
|
||||
local t = {}
|
||||
for k,v in ipairs(player.GetHumans()) do
|
||||
if v == me then continue end
|
||||
if (me.IsFriend and me:IsFriend(v) or (CLIENT and v:GetFriendStatus() == "friend")) then
|
||||
t[#t+1] = v
|
||||
end
|
||||
end
|
||||
return t
|
||||
end)
|
||||
npcs = CreateAllFunction(function()
|
||||
local t = {}
|
||||
for _, ent in pairs(ents.GetAll())do
|
||||
if ent:IsNPC() then
|
||||
table.insert(t, ent)
|
||||
end
|
||||
end
|
||||
return t
|
||||
end)
|
||||
allof = function(class)
|
||||
if isentity(class) and IsValid(class) then
|
||||
class = class:GetClass()
|
||||
end
|
||||
|
||||
local results = ents.FindByClass(class)
|
||||
return CreateAllFunction(function()
|
||||
return results
|
||||
end, results)
|
||||
end
|
||||
|
||||
props = CreateAllFunction(function() return ents.FindByClass("prop_physics") end)
|
||||
if SERVER then
|
||||
these = CreateAllFunction(function() return constraint.GetAllConstrainedEntities(_G.this) end)
|
||||
end
|
||||
those = CreateAllFunction(function() return ents.FindInSphere(_G.there, 250) end)
|
||||
end
|
||||
18
garrysmod/addons/luadev/lua/autorun/luadev.lua
Normal file
18
garrysmod/addons/luadev/lua/autorun/luadev.lua
Normal file
@@ -0,0 +1,18 @@
|
||||
module("luadev",package.seeall)
|
||||
|
||||
-- I think I finally understood why people make these seemingly silly files with just includes
|
||||
|
||||
include 'luadev/luadev_sh.lua'
|
||||
if SERVER then
|
||||
include 'luadev/luadev_sv.lua'
|
||||
end
|
||||
include 'luadev/luadev.lua'
|
||||
if CLIENT then
|
||||
include 'luadev/socketdev.lua'
|
||||
end
|
||||
|
||||
if SERVER then
|
||||
AddCSLuaFile 'luadev/luadev_sh.lua'
|
||||
AddCSLuaFile 'luadev/luadev.lua'
|
||||
AddCSLuaFile 'luadev/socketdev.lua'
|
||||
end
|
||||
130
garrysmod/addons/luadev/lua/autorun/server/luadev_chatcmds.lua
Normal file
130
garrysmod/addons/luadev/lua/autorun/server/luadev_chatcmds.lua
Normal file
@@ -0,0 +1,130 @@
|
||||
hook.Add("Think","luadev_cmdsinit",function()
|
||||
hook.Remove("Think","luadev_cmdsinit")
|
||||
|
||||
local function add(cmd,callback)
|
||||
if aowl and aowl.AddCommand then
|
||||
aowl.AddCommand(cmd,function(ply,script,param_a,...)
|
||||
|
||||
local a,b
|
||||
|
||||
easylua.End() -- nesting not supported
|
||||
|
||||
local ret,why = callback(ply,script,param_a,...)
|
||||
if not ret then
|
||||
if why==false then
|
||||
a,b = false,why or aowl.TargetNotFound(param_a or "notarget") or "H"
|
||||
elseif isstring(why) then
|
||||
ply:ChatPrint("FAILED: "..tostring(why))
|
||||
a,b= false,tostring(why)
|
||||
end
|
||||
end
|
||||
|
||||
easylua.Start(ply)
|
||||
return a,b
|
||||
|
||||
end,cmd=="lm" and "players" or "developers")
|
||||
end
|
||||
end
|
||||
|
||||
local function X(ply,i) return luadev.GetPlayerIdentifier(ply,'cmd:'..i) end
|
||||
|
||||
add("l", function(ply, line, target)
|
||||
if not line or line=="" then return false,"invalid script" end
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript(line,"l") if not valid then return false,err end end
|
||||
return luadev.RunOnServer(line, X(ply,"l"), {ply=ply})
|
||||
end)
|
||||
|
||||
add("ls", function(ply, line, target)
|
||||
if not line or line=="" then return false,"invalid script" end
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript(line,"ls") if not valid then return false,err end end
|
||||
return luadev.RunOnShared(line, X(ply,"ls"), {ply=ply})
|
||||
end)
|
||||
|
||||
add("lc", function(ply, line, target)
|
||||
if not line or line=="" then return end
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript(line,"lc") if not valid then return false,err end end
|
||||
return luadev.RunOnClients(line, X(ply,"lc"), {ply=ply})
|
||||
end)
|
||||
|
||||
add("lsc", function(ply, line, target)
|
||||
local script = string.sub(line, string.find(line, target, 1, true)+#target+1)
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript(script,'lsc') if not valid then return false,err end end
|
||||
|
||||
easylua.Start(ply) -- for _G.we -> #us
|
||||
local ent = easylua.FindEntity(target)
|
||||
if type(ent) == 'table' then
|
||||
ent = ent.get()
|
||||
end
|
||||
easylua.End()
|
||||
|
||||
return luadev.RunOnClient(script, ent, X(ply,"lsc"), {ply=ply})
|
||||
end)
|
||||
local sv_allowcslua = GetConVar"sv_allowcslua"
|
||||
add("lm", function(ply, line, target)
|
||||
if not line or line=="" then return end
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript(line,'lm') if not valid then return false,err end end
|
||||
|
||||
if not ply:IsAdmin() and not sv_allowcslua:GetBool() then return false,"sv_allowcslua is 0" end
|
||||
|
||||
luadev.RunOnClient(line, ply,X(ply,"lm"), {ply=ply})
|
||||
|
||||
end)
|
||||
|
||||
add("lb", function(ply, line, target)
|
||||
if not line or line=="" then return end
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript(line,'lb') if not valid then return false,err end end
|
||||
|
||||
luadev.RunOnClient(line, ply, X(ply,"lb"), {ply=ply})
|
||||
return luadev.RunOnServer(line, X(ply,"lb"), {ply=ply})
|
||||
end)
|
||||
|
||||
add("print", function(ply, line, target)
|
||||
if not line or line=="" then return end
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript('x('..line..')','print') if not valid then return false,err end end
|
||||
|
||||
return luadev.RunOnServer("print(" .. line .. ")", X(ply,"print"), {ply=ply})
|
||||
end)
|
||||
|
||||
add("table", function(ply, line, target)
|
||||
if not line or line=="" then return end
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript('x('..line..')','table') if not valid then return false,err end end
|
||||
|
||||
return luadev.RunOnServer("PrintTable(" .. line .. ")", X(ply,"table"), {ply=ply})
|
||||
end)
|
||||
|
||||
add("keys", function(ply, line, table, search)
|
||||
if not line or line=="" then return end
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript('x('..table..')','keys') if not valid then return false,err end end
|
||||
|
||||
search = search and search:lower() or ""
|
||||
return luadev.RunOnServer(
|
||||
"local t={} for k,v in pairs(" .. table .. ") do t[#t+1]=tostring(k) end table.sort(t) for k,v in pairs(t) do if string.find(v:lower(),\"" .. search .. "\",1,true) then print(v) end end",
|
||||
X(ply,"keys"), {ply=ply}
|
||||
)
|
||||
end)
|
||||
|
||||
add("printc", function(ply, line, target)
|
||||
if not line or line=="" then return end
|
||||
line = "easylua.PrintOnServer(" .. line .. ")"
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript(line,'printc') if not valid then return false,err end end
|
||||
|
||||
return luadev.RunOnClients(line, X(ply,"printc"), {ply=ply})
|
||||
end)
|
||||
|
||||
add("printm", function(ply, line, target)
|
||||
if not line or line=="" then return end
|
||||
line = "easylua.PrintOnServer(" .. line .. ")"
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript(line,'printm') if not valid then return false,err end end
|
||||
|
||||
luadev.RunOnClient(line, ply, X(ply,"printm"), {ply=ply})
|
||||
end)
|
||||
|
||||
add("printb", function(ply, line, target)
|
||||
if not line or line=="" then return end
|
||||
if luadev.ValidScript then local valid,err = luadev.ValidScript('x('..line..')','printb') if not valid then return false,err end end
|
||||
|
||||
luadev.RunOnClient("easylua.PrintOnServer(" .. line .. ")", ply, X(ply,"printb"), {ply=ply})
|
||||
return luadev.RunOnServer("print(" .. line .. ")", X(ply,"printb"), {ply=ply})
|
||||
end)
|
||||
|
||||
end)
|
||||
202
garrysmod/addons/luadev/lua/autorun/tinylua.lua
Normal file
202
garrysmod/addons/luadev/lua/autorun/tinylua.lua
Normal file
@@ -0,0 +1,202 @@
|
||||
tinylua = setmetatable({}, { __call = function(self, ...) return self.Wrap(...) end})
|
||||
local INTERNAL = {}
|
||||
local META = {}
|
||||
|
||||
local function pack(...) -- Convenient argument packer
|
||||
local len, tbl = select('#', ...), {...}
|
||||
local packFuncs = {}
|
||||
|
||||
function packFuncs.unpack()
|
||||
return unpack(tbl, 1, len)
|
||||
end
|
||||
|
||||
return setmetatable(tbl, {
|
||||
__index = function(self, index)
|
||||
return packFuncs[index] or tbl[index]
|
||||
end,
|
||||
__call = function(...)
|
||||
return len, tbl
|
||||
end
|
||||
})
|
||||
end
|
||||
|
||||
local function Wrap(input)
|
||||
local values = {}
|
||||
local meta = {}
|
||||
|
||||
for ind, val in pairs(input)do
|
||||
values[(tonumber(ind) and val or ind)] = val
|
||||
end
|
||||
|
||||
for ind, val in pairs(META)do
|
||||
meta[ind] = val
|
||||
end
|
||||
|
||||
return setmetatable(values, meta)
|
||||
end
|
||||
|
||||
local function performCall(tbl, callback)
|
||||
local results = {}
|
||||
local errors = {}
|
||||
local calls = 0
|
||||
|
||||
local iKey, iVal = nil, nil
|
||||
while true do
|
||||
local succ, err = pcall(function()
|
||||
while true do
|
||||
iKey, iVal = next(tbl, iKey)
|
||||
if iKey == nil then break end
|
||||
calls = calls + 1
|
||||
|
||||
callback(results, iKey, iVal)
|
||||
end
|
||||
end)
|
||||
|
||||
if not succ then errors[iKey] = err end
|
||||
if iKey == nil then break end
|
||||
end
|
||||
|
||||
if table.Count(errors) == calls then
|
||||
if calls ~= 0 then
|
||||
local _, error = next(errors, nil)
|
||||
MsgC(Color(235, 111, 111), "[tinylua] "..error)
|
||||
else
|
||||
MsgC(Color(235, 111, 111), "[tinylua] No results!\n")
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
local result = Wrap(results)
|
||||
getmetatable(result)["errors"] = errors
|
||||
return result
|
||||
end
|
||||
|
||||
function META:__index(index)
|
||||
if INTERNAL[index] then
|
||||
return function(_, ...)
|
||||
return INTERNAL[index](self, ...)
|
||||
end
|
||||
end
|
||||
|
||||
return performCall(self, function(results, source, ent)
|
||||
local target = ent[index]
|
||||
|
||||
if isfunction(target) then
|
||||
results[source] = function(fArg, ...)
|
||||
return target(ent, ...)
|
||||
end
|
||||
else
|
||||
results[source] = target
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function META:__newindex(index, value)
|
||||
performCall(self, function(results, source, ent)
|
||||
ent[index] = value
|
||||
end)
|
||||
end
|
||||
|
||||
function META:__call(...)
|
||||
local args = pack(...)
|
||||
return performCall(self, function(results, source, ent)
|
||||
if isfunction(ent) then
|
||||
local rets = pack(ent(args:unpack()))
|
||||
if #rets ~= 1 then
|
||||
for _, ret in pairs(rets) do
|
||||
table.insert(results, ret)
|
||||
end
|
||||
else
|
||||
results[source] = rets[1]
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Exposed Functions
|
||||
tinylua.Wrap = Wrap
|
||||
|
||||
-- INTERNAL Extensions
|
||||
local function makePrefix(input)
|
||||
if not input:match("\n") and isfunction(CompileString("return "..input, "", false)) then
|
||||
return "return "..input
|
||||
end
|
||||
|
||||
return input
|
||||
end
|
||||
|
||||
local function buildParser(input)
|
||||
if isfunction(input) then return input end
|
||||
local argStr, funcStr = input:match("(.-)->(.+)")
|
||||
|
||||
if argStr and funcStr then
|
||||
local codeFull = string.format("return function(%s)\n%s\nend", argStr, makePrefix(funcStr))
|
||||
local funcFactory = CompileString(codeFull, "funcfactory")
|
||||
|
||||
if getfenv(1) then
|
||||
setfenv(funcFactory, getfenv(1))
|
||||
end
|
||||
|
||||
if funcFactory then
|
||||
return funcFactory()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function INTERNAL:map(input)
|
||||
local eval = buildParser(input)
|
||||
return performCall(self, function(results, source, ent)
|
||||
local rets = pack(eval(ent, source))
|
||||
if #rets ~= 1 then
|
||||
for _, val in pairs(rets) do
|
||||
table.insert(results, val)
|
||||
end
|
||||
else
|
||||
results[source] = rets[1]
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function INTERNAL:filter(input)
|
||||
local eval = buildParser(input)
|
||||
return performCall(self, function(results, source, ent)
|
||||
if eval(ent, source) then
|
||||
results[source] = ent
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function INTERNAL:set(vars, val)
|
||||
vars = (istable(vars) and vars or {vars})
|
||||
return performCall(self, function(results, source, ent)
|
||||
for _, var in ipairs(vars) do
|
||||
ent[var] = val
|
||||
end
|
||||
|
||||
results[source] = ent
|
||||
end)
|
||||
end
|
||||
|
||||
function INTERNAL:IsValid()
|
||||
return false
|
||||
end
|
||||
|
||||
function INTERNAL:keys()
|
||||
return performCall(self, function(results, source, ent)
|
||||
results[source] = source
|
||||
end)
|
||||
end
|
||||
|
||||
function INTERNAL:first()
|
||||
for _, ent in pairs(self) do
|
||||
return ent
|
||||
end
|
||||
end
|
||||
|
||||
function INTERNAL:errors()
|
||||
return (getmetatable(self).errors or {})
|
||||
end
|
||||
|
||||
function INTERNAL:get()
|
||||
return table.ClearKeys(self)
|
||||
end
|
||||
BIN
garrysmod/addons/luadev/lua/bin/gmcl_luasocket_win32.dll
Normal file
BIN
garrysmod/addons/luadev/lua/bin/gmcl_luasocket_win32.dll
Normal file
Binary file not shown.
BIN
garrysmod/addons/luadev/lua/bin/gmcl_luasocket_win64.dll
Normal file
BIN
garrysmod/addons/luadev/lua/bin/gmcl_luasocket_win64.dll
Normal file
Binary file not shown.
507
garrysmod/addons/luadev/lua/luadev/luadev.lua
Normal file
507
garrysmod/addons/luadev/lua/luadev/luadev.lua
Normal file
@@ -0,0 +1,507 @@
|
||||
module("luadev",package.seeall)
|
||||
|
||||
local function CMD(who)
|
||||
return CLIENT and "CMD" or who or "CMD"
|
||||
end
|
||||
|
||||
COMMAND('run_sv',function(ply,_,script,who)
|
||||
RunOnServer(script,CMD(who),MakeExtras(ply))
|
||||
end,true)
|
||||
|
||||
COMMAND('run_sh',function(ply,_,script,who)
|
||||
RunOnShared(script,CMD(who),MakeExtras(ply))
|
||||
end,true)
|
||||
|
||||
COMMAND('run_clients',function(ply,_,script,who)
|
||||
RunOnClients(script,CMD(who),MakeExtras(ply))
|
||||
end,true)
|
||||
|
||||
COMMAND('run_self',function(ply,_,script,who)
|
||||
RunOnSelf(script,CMD(who),MakeExtras(ply))
|
||||
end,true)
|
||||
|
||||
COMMAND('run_client',function(ply,tbl,script,who)
|
||||
|
||||
if !tbl[1] or !tbl[2] then Print("Syntax: lua_run_client (steamid/userid/accountid/part of name) script") return end
|
||||
|
||||
local cl=FindPlayer(tbl[1])
|
||||
|
||||
if !cl then Print("Client not found!\n") return end
|
||||
if CLIENT then
|
||||
Print("Running script on "..tostring(cl:Name()))
|
||||
end
|
||||
|
||||
local _, e = script:find('^%s*"[^"]+')
|
||||
if e then
|
||||
script = script:sub(e+2)
|
||||
else
|
||||
local _, e = script:find('^%s*[^%s]+%s')
|
||||
if not e then
|
||||
Print("Invalid Command syntax.")
|
||||
return
|
||||
end
|
||||
script = script:sub(e)
|
||||
end
|
||||
|
||||
script = script:Trim()
|
||||
|
||||
RunOnClient(script,cl,CMD(who),MakeExtras(ply))
|
||||
|
||||
end)
|
||||
|
||||
COMMAND('send_cl',function(ply,tbl,cmd,who)
|
||||
|
||||
if !tbl[1] or !tbl[2] then Print("Syntax: lua_send_cl (steamid/userid/accountid/part of name) \"path\"") return end
|
||||
|
||||
local cl=FindPlayer(tbl[1])
|
||||
|
||||
if !cl then Print("Client not found!\n") return end
|
||||
Print("Running script on "..tostring(cl:Name()))
|
||||
|
||||
|
||||
table.remove(tbl,1)
|
||||
local path=TableToString(tbl)
|
||||
|
||||
local Path,searchpath=RealFilePath(path)
|
||||
if !Path then Print("Could not find the file\n") return end
|
||||
|
||||
local content = Path and GiveFileContent(Path,searchpath)
|
||||
if !content then Print("Could not read the file\n") return end
|
||||
|
||||
RunOnClient(content,cl,who or CMD(who),MakeExtras(ply))
|
||||
|
||||
end)
|
||||
|
||||
COMMAND('send_sv',function(ply,c,cmd,who)
|
||||
|
||||
local Path,searchpath=RealFilePath(c[2] and TableToString(c) or c[1])
|
||||
if !Path then Print("Could not find the file\n") return end
|
||||
|
||||
local content = Path and GiveFileContent(Path,searchpath)
|
||||
if !content then Print("Could not read the file\n") return end
|
||||
|
||||
local who=string.GetFileFromFilename(Path)
|
||||
|
||||
RunOnServer(content,who or CMD(who),MakeExtras(ply))
|
||||
|
||||
end)
|
||||
|
||||
COMMAND('send_clients',function(ply,c,cmd,who)
|
||||
|
||||
local Path,searchpath=RealFilePath(c[2] and TableToString(c) or c[1])
|
||||
if !Path then Print("Could not find the file\n") return end
|
||||
|
||||
local content = Path and GiveFileContent(Path,searchpath)
|
||||
if !content then Print("Could not read the file\n") return end
|
||||
|
||||
local who=string.GetFileFromFilename(Path)
|
||||
|
||||
RunOnClients(content,who or CMD(who),MakeExtras(ply))
|
||||
|
||||
end)
|
||||
|
||||
COMMAND('send_sh',function(ply,c,cmd,who)
|
||||
|
||||
local Path,searchpath=RealFilePath(c[2] and TableToString(c) or c[1])
|
||||
if !Path then Print("Could not find the file\n") return end
|
||||
|
||||
local content = Path and GiveFileContent(Path,searchpath)
|
||||
if !content then Print("Could not read the file\n") return end
|
||||
|
||||
local who=string.GetFileFromFilename(Path)
|
||||
|
||||
RunOnShared(content,who or CMD(who),MakeExtras(ply))
|
||||
|
||||
end)
|
||||
|
||||
local function Guess(name,Path)
|
||||
|
||||
if name=="init" or name=="shared" or name=="cl_init" then
|
||||
local newname = Path:gsub("\\","/"):match("^.+%/([^%/]-)/.-%.lua$")
|
||||
Print("Guessing identifier: "..tostring(newname or "<Failed>"))
|
||||
return newname or name
|
||||
end
|
||||
|
||||
return name
|
||||
end
|
||||
|
||||
local function SendEFFECT(cl,Path,ply,c,cmd,who)
|
||||
local who=string.GetFileFromFilename(Path)
|
||||
|
||||
local effectname=string.GetFileFromFilename(Path):gsub("%.lua","")
|
||||
|
||||
effectname = Guess(effectname,Path)
|
||||
|
||||
if cl then
|
||||
RunOnClients(cl,who or CMD(who),MakeExtras(ply,{effect=effectname}))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
COMMAND('send_effect',function(ply,c,cmd,who)
|
||||
local path = c[2] and TableToString(c) or c[1]
|
||||
|
||||
local Path,searchpath=RealFilePath(path)
|
||||
if not Path then
|
||||
Print("Could not find the file\n")
|
||||
return
|
||||
end
|
||||
|
||||
local content = GiveFileContent(Path,searchpath)
|
||||
if content then
|
||||
local sh = content
|
||||
SendEFFECT(content,Path,ply,c,cmd,who)
|
||||
return
|
||||
end
|
||||
|
||||
local cl = GiveFileContent(Path..'/init.lua',searchpath)
|
||||
|
||||
if cl then
|
||||
SendEFFECT(cl,Path,ply,c,cmd,who)
|
||||
return
|
||||
else
|
||||
Print("Could not find required files from the folder\n")
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
|
||||
|
||||
local function SendSWEP(cl,sh,sv,Path,ply,c,cmd,who)
|
||||
local who=string.GetFileFromFilename(Path)
|
||||
|
||||
local swepname=string.GetFileFromFilename(Path):gsub("%.lua","")
|
||||
swepname=Guess(swepname,Path)
|
||||
|
||||
if cl then
|
||||
RunOnClients(cl,who or CMD(who),MakeExtras(ply,{swep=swepname}))
|
||||
end
|
||||
if sh then
|
||||
RunOnShared(sh,who or CMD(who),MakeExtras(ply,{swep=swepname}))
|
||||
end
|
||||
if sv then
|
||||
RunOnServer(sv,who or CMD(who),MakeExtras(ply,{swep=swepname}))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
COMMAND('send_wep',function(ply,c,cmd,who)
|
||||
local path = c[2] and TableToString(c) or c[1]
|
||||
|
||||
local Path,searchpath=RealFilePath(path)
|
||||
if not Path then
|
||||
Print("Could not find the file\n")
|
||||
return
|
||||
end
|
||||
|
||||
local content = GiveFileContent(Path,searchpath)
|
||||
if content then
|
||||
local sh = content
|
||||
SendSWEP(nil,sh,nil,Path,ply,c,cmd,who)
|
||||
return
|
||||
end
|
||||
|
||||
local cl = GiveFileContent(Path..'/cl_init.lua',searchpath)
|
||||
local sh = GiveFileContent(Path..'/shared.lua',searchpath)
|
||||
local sv = GiveFileContent(Path..'/init.lua',searchpath)
|
||||
|
||||
if sv or sh or cl then
|
||||
SendSWEP(cl,sh,sv,Path,ply,c,cmd,who)
|
||||
return
|
||||
else
|
||||
Print("Could not find required files from the folder\n")
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
|
||||
local function SendENT(cl,sh,sv,Path,ply,c,cmd,who)
|
||||
local who=string.GetFileFromFilename(Path)
|
||||
|
||||
local entname=string.GetFileFromFilename(Path):gsub("%.lua","")
|
||||
entname = Guess(entname,Path)
|
||||
if cl then
|
||||
RunOnClients(cl,who or CMD(who),MakeExtras(ply,{sent=entname}))
|
||||
end
|
||||
if sh then
|
||||
RunOnShared(sh,who or CMD(who),MakeExtras(ply,{sent=entname}))
|
||||
end
|
||||
if sv then
|
||||
RunOnServer(sv,who or CMD(who),MakeExtras(ply,{sent=entname}))
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
COMMAND('send_ent',function(ply,c,cmd,who)
|
||||
local path = c[2] and TableToString(c) or c[1]
|
||||
|
||||
local Path,searchpath=RealFilePath(path)
|
||||
if not Path then
|
||||
Print("Could not find the file\n")
|
||||
return
|
||||
end
|
||||
|
||||
local content = GiveFileContent(Path,searchpath)
|
||||
if content then
|
||||
local sh = content
|
||||
SendENT(nil,sh,nil,Path,ply,c,cmd,who)
|
||||
return
|
||||
end
|
||||
|
||||
local cl = GiveFileContent(Path..'/cl_init.lua',searchpath)
|
||||
local sh = GiveFileContent(Path..'/shared.lua',searchpath)
|
||||
local sv = GiveFileContent(Path..'/init.lua',searchpath)
|
||||
|
||||
if sv or sh or cl then
|
||||
SendENT(cl,sh,sv,Path,ply,c,cmd,who)
|
||||
return
|
||||
else
|
||||
Print("Could not find required files from the folder\n")
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
|
||||
COMMAND('watch_kill',function(ply,c,cmd,wholeline)
|
||||
|
||||
local watchlist = GetWatchList()
|
||||
|
||||
if c[1]=="" or not c[1] then
|
||||
Print"Killing all"
|
||||
table.Empty(watchlist)
|
||||
return
|
||||
end
|
||||
|
||||
local t= table.remove(watchlist,tonumber(c[1]))
|
||||
Print("killing",t and tostring(t.path) or "(not found)")
|
||||
end,true)
|
||||
|
||||
COMMAND('watch',function(ply,c,cmd,wholeline)
|
||||
|
||||
local path_orig = c[1]
|
||||
table.remove(c,1)
|
||||
|
||||
local fpath,searchpath=RealFilePath(path_orig,findpath)
|
||||
if not fpath then Print("Could not find the file\n") return end
|
||||
|
||||
local content = fpath and GiveFileContent(fpath,searchpath)
|
||||
local time = content and fpath and FileTime(fpath,searchpath)
|
||||
if not content or not time then Print("File not readable\n") return end
|
||||
|
||||
local found
|
||||
for k,v in next,c do
|
||||
if v=="PATH" then
|
||||
c[k] = path_orig
|
||||
found = true
|
||||
end
|
||||
if v=="FILE" then
|
||||
c[k] = path_orig
|
||||
found = true
|
||||
end
|
||||
if v=="RPATH" then
|
||||
c[k] = fpath
|
||||
found = true
|
||||
end
|
||||
if v=="NOPATH" then
|
||||
c[k] = false
|
||||
found=true
|
||||
end
|
||||
end
|
||||
|
||||
for i=#c,1,-1 do
|
||||
if c[i]==false then
|
||||
table.remove(c,i)
|
||||
end
|
||||
end
|
||||
|
||||
if not c[1] then
|
||||
Print"Missing command, assuming lua_send_self"
|
||||
c[1] = 'lua_send_self'
|
||||
end
|
||||
|
||||
if not found then
|
||||
table.insert(c,path_orig)
|
||||
end
|
||||
|
||||
local cmdd = {}
|
||||
for k,v in next,c do
|
||||
cmdd[k]=('%q'):format(tostring(v))
|
||||
end
|
||||
Print("Watching '"..tostring(fpath).."': ",table.concat(cmdd," "))
|
||||
|
||||
local entry = {
|
||||
path = fpath,
|
||||
searchpath = searchpath,
|
||||
time = time,
|
||||
cmd = c,
|
||||
}
|
||||
|
||||
local watchlist = GetWatchList()
|
||||
watchlist[#watchlist+1] = entry
|
||||
|
||||
end)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
COMMAND('send_self',function(ply,c,cmd,who)
|
||||
|
||||
local Path,searchpath=RealFilePath(c[2] and TableToString(c) or c[1])
|
||||
if !Path then Print("Could not find the file\n") return end
|
||||
|
||||
local content = GiveFileContent(Path,searchpath)
|
||||
if !content then Print("Could not read the file\n") return end
|
||||
|
||||
local who=string.GetFileFromFilename(Path)
|
||||
|
||||
RunOnSelf(content,who or CMD(who),MakeExtras(ply))
|
||||
|
||||
end)
|
||||
|
||||
|
||||
if SERVER then return end
|
||||
|
||||
net.Receive(Tag,function(...) _ReceivedData(...) end)
|
||||
|
||||
function _ReceivedData(len)
|
||||
|
||||
local script = ReadCompressed()
|
||||
local decoded=net.ReadTable()
|
||||
|
||||
local info=decoded.info
|
||||
local extra=decoded.extra
|
||||
|
||||
local ok,ret = Run(script,tostring(info),extra)
|
||||
|
||||
if not ok then
|
||||
ErrorNoHalt(tostring(ret)..'\n')
|
||||
end
|
||||
|
||||
--[[ -- Not done
|
||||
if extra.retid then
|
||||
net.Start(net_retdata)
|
||||
net.WriteUInt(extra.retid,32)
|
||||
net.WriteBool(ok)
|
||||
net.WriteTable(ret)
|
||||
net.SendToServer()
|
||||
end --]]
|
||||
|
||||
end
|
||||
|
||||
function CheckStore(src)
|
||||
if not ShouldStore() then return end
|
||||
local crc = util.CRC(src)
|
||||
local path = "luadev_hist/".. crc ..'.txt'
|
||||
|
||||
if file.Exists(path,'DATA') then return end
|
||||
if not file.IsDir("luadev_hist",'DATA') then file.CreateDir("luadev_hist",'DATA') end
|
||||
|
||||
file.Write(path,tostring(src),'DATA')
|
||||
end
|
||||
|
||||
function ToServer(data)
|
||||
if TransmitHook(data)~=nil then return end
|
||||
|
||||
CheckStore(data.src)
|
||||
|
||||
net.Start(Tag)
|
||||
WriteCompressed(data.src or "")
|
||||
|
||||
-- clear extra data
|
||||
data.src = nil
|
||||
if data.extra then
|
||||
data.extra.ply = nil
|
||||
if table.Count(data.extra)==0 then data.extra=nil end
|
||||
end
|
||||
|
||||
net.WriteTable(data)
|
||||
if net.BytesWritten()==65536 then
|
||||
Print("Unable to send lua code (too big)\n")
|
||||
return nil,"Unable to send lua code (too big)"
|
||||
end
|
||||
|
||||
net.SendToServer()
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function RunOnClients(script,who,extra)
|
||||
|
||||
if not who and extra and isentity(extra) then extra = {ply=extra} end
|
||||
|
||||
local data={
|
||||
src=script,
|
||||
dst=TO_CLIENTS,
|
||||
info=who,
|
||||
extra=extra,
|
||||
}
|
||||
|
||||
return ToServer(data)
|
||||
|
||||
end
|
||||
|
||||
|
||||
function RunOnSelf(script,who,extra)
|
||||
if not isstring(who) then who = nil end
|
||||
if not who and extra and isentity(extra) then extra = {ply=extra} end
|
||||
--if luadev_selftoself:GetBool() then
|
||||
-- Run
|
||||
--end
|
||||
return RunOnClient(script,LocalPlayer(),who,extra)
|
||||
end
|
||||
|
||||
function RunOnClient(script,targets,who,extra)
|
||||
-- compat
|
||||
if not targets and isentity(who) then
|
||||
targets=who
|
||||
who = nil
|
||||
end
|
||||
|
||||
if extra and isentity(extra) and who==nil then extra={ply=extra} end
|
||||
|
||||
if (not istable(targets) and !IsValid(targets))
|
||||
or (istable(targets) and table.Count(targets)==0)
|
||||
then error"Invalid player(s)" end
|
||||
|
||||
local data={
|
||||
src=script,
|
||||
dst=TO_CLIENT,
|
||||
dst_ply=targets,
|
||||
info=who,
|
||||
extra=extra,
|
||||
}
|
||||
|
||||
return ToServer(data)
|
||||
|
||||
end
|
||||
|
||||
function RunOnServer(script,who,extra)
|
||||
if not who and extra and isentity(extra) then extra = {ply=extra} end
|
||||
|
||||
local data={
|
||||
src=script,
|
||||
dst=TO_SERVER,
|
||||
--dst_ply=pl
|
||||
info=who,
|
||||
extra=extra,
|
||||
}
|
||||
return ToServer(data)
|
||||
|
||||
end
|
||||
|
||||
function RunOnShared(script,who,extra)
|
||||
if not who and extra and isentity(extra) then extra = {ply=extra} end
|
||||
|
||||
local data={
|
||||
src=script,
|
||||
dst=TO_SHARED,
|
||||
--dst_ply=pl
|
||||
info=who,
|
||||
extra=extra,
|
||||
}
|
||||
|
||||
return ToServer(data)
|
||||
|
||||
end
|
||||
592
garrysmod/addons/luadev/lua/luadev/luadev_sh.lua
Normal file
592
garrysmod/addons/luadev/lua/luadev/luadev_sh.lua
Normal file
@@ -0,0 +1,592 @@
|
||||
module("luadev",package.seeall)
|
||||
Tag=_NAME..'1'
|
||||
|
||||
--net_retdata = Tag..'_retdata'
|
||||
|
||||
if SERVER then
|
||||
util.AddNetworkString(Tag)
|
||||
--util.AddNetworkString(net_retdata)
|
||||
end
|
||||
|
||||
|
||||
-- Enums
|
||||
|
||||
local enums={
|
||||
TO_CLIENTS=1,
|
||||
TO_CLIENT=2,
|
||||
TO_SERVER=3,
|
||||
TO_SHARED=4,
|
||||
}
|
||||
|
||||
local revenums={} -- lookup
|
||||
_M.revenums=revenums
|
||||
|
||||
for k,v in pairs(enums) do
|
||||
_M[k]=v
|
||||
revenums[v]=k
|
||||
end
|
||||
|
||||
STAGE_PREPROCESS=1
|
||||
STAGE_COMPILED=2
|
||||
STAGE_POST=3
|
||||
STAGE_PREPROCESSING=4
|
||||
|
||||
-- Figure out what to put to extra table
|
||||
function MakeExtras(pl,extrat)
|
||||
if pl and isentity(pl) and pl:IsPlayer() then
|
||||
extrat = extrat or {}
|
||||
extrat.ply = pl
|
||||
end
|
||||
return extrat
|
||||
end
|
||||
|
||||
-- Helpers
|
||||
|
||||
function TransmitHook(stage,...)
|
||||
return hook.Run("LuaDevTransmit",stage,...)
|
||||
end
|
||||
|
||||
function IsOneLiner(script)
|
||||
return script and not script:find("\n",1,true)
|
||||
end
|
||||
|
||||
function GiveFileContent(fullpath,searchpath)
|
||||
--Print("Reading: "..tostring(fullpath))
|
||||
if fullpath==nil or fullpath=="" then return false end
|
||||
|
||||
local content=file.Read(fullpath,searchpath or "MOD")
|
||||
if content==0 then return false end
|
||||
return content
|
||||
end
|
||||
|
||||
function TableToString(tbl)
|
||||
return string.Implode(" ",tbl)
|
||||
end
|
||||
|
||||
function Print(...)
|
||||
if metalog then
|
||||
metalog.info("Luadev", SERVER and "Server" or "Client", ...)
|
||||
else
|
||||
Msg("[Luadev"..(SERVER and ' Server' or '').."] ")
|
||||
print(...)
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
luadev_store = CreateClientConVar( "luadev_store", "1",true)
|
||||
function ShouldStore()
|
||||
return luadev_store:GetBool()
|
||||
end
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
luadev_verbose = CreateClientConVar( "luadev_verbose", "1",true)
|
||||
else
|
||||
luadev_verbose = CreateConVar( "luadev_verbose", "1", { FCVAR_NOTIFY ,FCVAR_ARCHIVE} )
|
||||
end
|
||||
function Verbose(lev)
|
||||
return (luadev_verbose:GetInt() or 99)>=(lev or 1)
|
||||
end
|
||||
|
||||
function PrintX(script,...)
|
||||
local oneline = IsOneLiner(script) and 2
|
||||
local verb = Verbose(oneline)
|
||||
if metalog then
|
||||
metalog[verb and "info" or "debug"]("Luadev", SERVER and "Server" or "Client", ...)
|
||||
else
|
||||
local Msg=not verb and _Msg or Msg
|
||||
local print=not verb and _print or print
|
||||
Msg("[Luadev"..(SERVER and ' Server' or '').."] ")
|
||||
print(...)
|
||||
end
|
||||
end
|
||||
|
||||
specials = {
|
||||
swep = {
|
||||
function(val,extra,script,info)
|
||||
local SWEP=weapons.GetStored(val)
|
||||
if not SWEP then
|
||||
SWEP = {Primary={}, Secondary={},Base = "weapon_base",ClassName = val, Folder = 'weapons/'..val }
|
||||
end
|
||||
_G.SWEP = SWEP
|
||||
end,
|
||||
function(val,extra,script,info)
|
||||
local tbl = _G.SWEP
|
||||
_G.SWEP = nil
|
||||
if istable(tbl) then
|
||||
--local table_ForEach=table.ForEach table.ForEach=function()end timer.Simple(0,function() table.ForEach=table_ForEach end)
|
||||
if Verbose() then
|
||||
Print("Registering weapon "..tostring(val))
|
||||
end
|
||||
weapons.Register(tbl, val, true)
|
||||
--table.ForEach=table_ForEach
|
||||
end
|
||||
end,
|
||||
},
|
||||
sent = {
|
||||
function(val,extra,script,info)
|
||||
local ENT=scripted_ents.GetStored(val)
|
||||
if ENT and ENT.t then
|
||||
ENT=ENT.t
|
||||
else
|
||||
ENT = {ClassName=val , Folder = 'entities/'..val}
|
||||
end
|
||||
_G.ENT = ENT
|
||||
end,
|
||||
function(val,extra,script,info)
|
||||
local tbl = _G.ENT
|
||||
_G.ENT = nil
|
||||
if istable(tbl) then
|
||||
|
||||
tbl.Model = tbl.Model or Model("models/props_borealis/bluebarrel001.mdl")
|
||||
if not tbl.Base then
|
||||
tbl.Base = "base_anim"
|
||||
tbl.Type = tbl.Type or "anim"
|
||||
end
|
||||
if Verbose() then
|
||||
Print("Registering entity "..tostring(val))
|
||||
end
|
||||
scripted_ents.Register(tbl, val)
|
||||
end
|
||||
end,
|
||||
},
|
||||
stool = {
|
||||
function(toolmode,extra,script,info)
|
||||
local gmod_tool=weapons.GetStored("gmod_tool")
|
||||
if gmod_tool and gmod_tool.Tool and gmod_tool.Tool[toolmode] then
|
||||
_G.TOOL=gmod_tool.Tool[toolmode]
|
||||
assert(_G.TOOL and _G.TOOL.Mode == toolmode)
|
||||
else
|
||||
|
||||
assert(ToolObj,"Need ToolObj from gamemode to create new tools")
|
||||
|
||||
_G.TOOL = ToolObj:Create(toolmode)
|
||||
_G.TOOL.Mode = toolmode
|
||||
|
||||
end
|
||||
|
||||
_G.TOOL = TOOL
|
||||
end,
|
||||
function(val,extra,script,info)
|
||||
local tbl = _G.TOOL
|
||||
_G.TOOL = nil
|
||||
if not istable(tbl) then return end
|
||||
|
||||
Print("Registering tool "..tostring(val))
|
||||
|
||||
if tbl.CreateConVars then
|
||||
tbl:CreateConVars()
|
||||
end
|
||||
|
||||
local gmod_tool=weapons.GetStored("gmod_tool")
|
||||
if _G.TOOL and gmod_tool and gmod_tool.Tool then
|
||||
gmod_tool.Tool[val] = _G.TOOL
|
||||
end
|
||||
|
||||
|
||||
end,
|
||||
},
|
||||
-- TODO --
|
||||
effect = {
|
||||
function(val,extra,script,info)
|
||||
if SERVER then return end
|
||||
_G.EFFECT = {ClassName=val,Folder = 'effects/'..val }
|
||||
end,
|
||||
function(val,extra,script,info)
|
||||
if Verbose() then
|
||||
Print("Registering effect "..tostring(val))
|
||||
end
|
||||
if CLIENT then
|
||||
local tbl = _G.EFFECT _G.EFFECT = nil
|
||||
if tbl then
|
||||
effects.Register(_G.EFFECT,val)
|
||||
end
|
||||
end
|
||||
end,
|
||||
},
|
||||
}
|
||||
local specials = specials
|
||||
|
||||
|
||||
function ProcessSpecial(mode,script,info,extra)
|
||||
|
||||
if not extra then return end
|
||||
for special_type,funcs in next,specials do
|
||||
local val = extra[special_type]
|
||||
if val then
|
||||
if Verbose(10) then
|
||||
Print("ProcessSpecial",mode,special_type," -> ",val)
|
||||
end
|
||||
local func = funcs[mode]
|
||||
if func then return func(val,extra,script,info) end
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function FindPlayer(plyid)
|
||||
if not plyid or not isstring(plyid) then return end
|
||||
|
||||
local cl
|
||||
for k,v in pairs(player.GetHumans()) do
|
||||
if v:SteamID()==plyid or tostring(v:AccountID())==plyid or tostring(v:UserID())==plyid then
|
||||
cl=v
|
||||
break
|
||||
end
|
||||
end
|
||||
if not cl then
|
||||
for k,v in pairs(player.GetAll()) do
|
||||
if v:Name():lower():find(plyid:lower(),1,true)==1 then
|
||||
cl=v
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not cl then
|
||||
for k,v in pairs(player.GetAll()) do
|
||||
if string.find(v:Name(),plyid) then
|
||||
cl=v
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not cl then
|
||||
for k,v in pairs(player.GetAll()) do
|
||||
if v:Name():lower():find(plyid:lower(),1,true) then
|
||||
cl=v
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
if not cl and easylua and easylua.FindEntity then
|
||||
cl = easylua.FindEntity(plyid)
|
||||
end
|
||||
return IsValid(cl) and cl:IsPlayer() and cl or nil
|
||||
end
|
||||
|
||||
|
||||
-- Watch system
|
||||
|
||||
function FileTime(fullpath,searchpath)
|
||||
--Print("Reading: "..tostring(fullpath))
|
||||
if fullpath==nil or fullpath=="" then return false end
|
||||
|
||||
local t=file.Time(fullpath,searchpath or "MOD")
|
||||
|
||||
if not t or t==0 then return false end
|
||||
|
||||
return t
|
||||
end
|
||||
|
||||
local watchlist = rawget(_M,"GetWatchList") and GetWatchList() or {} function GetWatchList() return watchlist end
|
||||
local i=0
|
||||
hook.Add("Think",Tag.."_watchlist",function()
|
||||
if not watchlist[1] then return end
|
||||
|
||||
i=i+1
|
||||
local entry = watchlist[i]
|
||||
if not entry then
|
||||
i=0
|
||||
entry = watchlist[1]
|
||||
if not entry then return end
|
||||
end
|
||||
|
||||
local newtime = FileTime(entry.path,entry.searchpath)
|
||||
local oldtime = entry.time
|
||||
if newtime and newtime~=oldtime then
|
||||
|
||||
entry.time = newtime
|
||||
|
||||
Msg"[LuaDev] Refresh " print(unpack(entry.cmd))
|
||||
|
||||
RunConsoleCommand(unpack(entry.cmd))
|
||||
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
-- compression
|
||||
|
||||
function Compress( data )
|
||||
return util.Compress( data )
|
||||
end
|
||||
|
||||
function Decompress(data)
|
||||
return util.Decompress( data )
|
||||
end
|
||||
|
||||
function WriteCompressed(data)
|
||||
if #data==0 then
|
||||
net.WriteUInt( 0, 24 )
|
||||
return false
|
||||
end
|
||||
|
||||
local compressed = Compress( data )
|
||||
local len = compressed:len()
|
||||
net.WriteUInt( len, 24 )
|
||||
net.WriteData( compressed, len )
|
||||
return compressed
|
||||
end
|
||||
|
||||
function ReadCompressed()
|
||||
local len = net.ReadUInt( 24 )
|
||||
if len==0 then return "" end
|
||||
|
||||
return Decompress( net.ReadData( len ) )
|
||||
end
|
||||
|
||||
-- Compiler / runner
|
||||
local function ValidCode(src,who)
|
||||
local ret = CompileString(src,who or "",false)
|
||||
if type(ret)=='string' then
|
||||
return nil,ret
|
||||
end
|
||||
return ret or true
|
||||
end
|
||||
_M.ValidScript=ValidCode
|
||||
_M.ValidCode=ValidCode
|
||||
|
||||
function ProcessHook(stage,...)
|
||||
return hook.Run("LuaDevProcess",stage,...)
|
||||
end
|
||||
local LuaDevProcess=ProcessHook
|
||||
|
||||
local LUADEV_EXECUTE_STRING=RunStringEx
|
||||
local LUADEV_EXECUTE_FUNCTION=xpcall
|
||||
local LUADEV_COMPILE_STRING=CompileString
|
||||
local mt= {
|
||||
__tostring=function(self) return self[1] end,
|
||||
|
||||
__index={
|
||||
set=function(self,what) self[1]=what end,
|
||||
get=function(self,what) return self[1] end,
|
||||
},
|
||||
--__newindex=function(self,what) rawset(self,1,what) end,
|
||||
}
|
||||
local strobj=setmetatable({""},mt)
|
||||
|
||||
function Run(script,info,extra)
|
||||
--compat
|
||||
if CLIENT and not extra and info and istable(info) then
|
||||
return luadev.RunOnSelf(script,"COMPAT",{ply=info.ply})
|
||||
end
|
||||
|
||||
info = info or "??ANONYMOUS??"
|
||||
if not isstring(info) then
|
||||
debug.Trace()
|
||||
ErrorNoHalt("LuaDev Warning: info type mismatch: "..type(info)..': '..tostring(info))
|
||||
end
|
||||
|
||||
-- STAGE_PREPROCESS
|
||||
local ret,newinfo = LuaDevProcess(STAGE_PREPROCESS,script,info,extra,nil)
|
||||
|
||||
if ret == false then return end
|
||||
if ret ~=nil and ret~=true then script = ret end
|
||||
|
||||
if newinfo then info = newinfo end
|
||||
|
||||
-- STAGE_PREPROCESSING
|
||||
rawset(strobj,1,script)
|
||||
local ret = LuaDevProcess(STAGE_PREPROCESSING,strobj,info,extra,nil)
|
||||
script = rawget(strobj,1)
|
||||
|
||||
if not script then
|
||||
return false,"no script"
|
||||
end
|
||||
|
||||
-- Compiling
|
||||
|
||||
local func = LUADEV_COMPILE_STRING(script,tostring(info),false)
|
||||
if not func or isstring( func ) then compileerr = func or true func = false end
|
||||
|
||||
local ret = LuaDevProcess(STAGE_COMPILED,script,info,extra,func)
|
||||
-- replace function
|
||||
if ret == false then return end
|
||||
if ret ~=nil and isfunction(ret) then
|
||||
func = ret
|
||||
compileerr = false
|
||||
end
|
||||
|
||||
if not func then
|
||||
if compileerr then
|
||||
return false,"Syntax error: "..tostring(compileerr)
|
||||
end
|
||||
end
|
||||
|
||||
lastextra = extra
|
||||
lastinfo = info
|
||||
lastscript = script
|
||||
lastfunc = func
|
||||
|
||||
ProcessSpecial(1,script,info,extra)
|
||||
|
||||
local args = extra and extra.args and (istable(extra.args) and extra.args or {extra.args})
|
||||
if not args then args=nil end
|
||||
|
||||
|
||||
-- Run the stuff
|
||||
-- because garry's runstring has social engineer sexploits and such
|
||||
local errormessage
|
||||
local function LUADEV_TRACEBACK(errmsg)
|
||||
errormessage = errmsg
|
||||
local tracestr = debug.traceback(errmsg,2)
|
||||
|
||||
-- Tidy up the damn long trace
|
||||
local p1=tracestr:find("LUADEV_EXECUTE_FUNCTION",1,true)
|
||||
if p1 then
|
||||
local p2=0
|
||||
while p2 and p2<p1 do
|
||||
local new=tracestr:find("\n",p2+1,true)
|
||||
|
||||
if new>p1 then
|
||||
tracestr=tracestr:sub(1,new)
|
||||
break
|
||||
end
|
||||
p2=new
|
||||
end
|
||||
end
|
||||
|
||||
ErrorNoHalt('[ERROR] '..tracestr )-- ..'\n')
|
||||
end
|
||||
|
||||
local LUADEV_EXECUTE_FUNCTION=xpcall
|
||||
local returnvals = {LUADEV_EXECUTE_FUNCTION(func,LUADEV_TRACEBACK,args and unpack(args) or nil)}
|
||||
local ok = returnvals[1] table.remove(returnvals,1)
|
||||
|
||||
-- STAGE_POST
|
||||
local ret = LuaDevProcess(STAGE_POST,script,info,extra,func,args,ok,returnvals)
|
||||
ProcessSpecial(2,script,info,extra)
|
||||
|
||||
if not ok then
|
||||
return false,errormessage
|
||||
end
|
||||
|
||||
return ok,returnvals
|
||||
end
|
||||
|
||||
|
||||
function RealFilePath(name)
|
||||
local searchpath = "MOD"
|
||||
|
||||
local RelativePath='lua/'..name
|
||||
|
||||
if name:find("^lua/") then -- search cache
|
||||
name=name:gsub("^lua/","")
|
||||
RelativePath=name
|
||||
searchpath = "LUA"
|
||||
elseif name:find("^%.%./") then -- whole shit
|
||||
name=name:gsub("^%.%./","")
|
||||
RelativePath=name
|
||||
elseif name:find("^data/") then -- whatever
|
||||
name=name:gsub("^data/","")
|
||||
RelativePath='data/'..name
|
||||
end
|
||||
|
||||
if not file.Exists(RelativePath,searchpath) then return nil end
|
||||
return RelativePath,searchpath
|
||||
end
|
||||
|
||||
|
||||
function AutoComplete(cmd,commandName,args)
|
||||
|
||||
local name = string.Explode(' ',args)
|
||||
|
||||
name=name[#name] or ""
|
||||
|
||||
local path = string.GetPathFromFilename(name)
|
||||
|
||||
local searchpath = "MOD"
|
||||
|
||||
local RelativePath='lua/'..(name or "")
|
||||
|
||||
if name:find("^lua/") then -- search cache
|
||||
name=name:gsub("^lua/","")
|
||||
RelativePath=name
|
||||
searchpath = "LUA"
|
||||
elseif name:find("^%.%./") then -- whole shit
|
||||
name=name:gsub("^%.%./","")
|
||||
RelativePath=name
|
||||
elseif name:find("^data/") then -- whatever
|
||||
name=name:gsub("^data/","")
|
||||
RelativePath='data/'..name
|
||||
end
|
||||
|
||||
local searchstr = RelativePath.."*"
|
||||
|
||||
local files,folders=file.Find(searchstr,searchpath or "MOD")
|
||||
files=files or {}
|
||||
-- Filter out any files that don't end in ".lua".
|
||||
for i = #files, 1, -1 do
|
||||
if not string.match(files[i], "%.lua$") then
|
||||
table.remove(files, i)
|
||||
end
|
||||
end
|
||||
folders=folders or {}
|
||||
for k,v in pairs(folders) do
|
||||
table.insert(files,v)
|
||||
end
|
||||
local candidates=files
|
||||
candidates=candidates or {}
|
||||
for i,_ in pairs(candidates) do
|
||||
candidates[i]=commandName.." "..path..candidates[i]
|
||||
end
|
||||
|
||||
return candidates
|
||||
|
||||
end
|
||||
|
||||
local sv_allowcslua = GetConVar 'sv_allowcslua'
|
||||
|
||||
function CanLuaDev(ply,script,command,target,target_ply,extra)
|
||||
if SERVER and not ply:IsFullyAuthenticated() then
|
||||
return false, "Your SteamID wasn't fully authenticated, try restarting Steam."
|
||||
end
|
||||
local ret,x = hook.Run("CanLuaDev",ply,script,command,target,target_ply,extra)
|
||||
if ret~=nil then return ret,x end
|
||||
local ret,x = hook.Run("LuaDevIsPlayerAllowed", ply, script or "")
|
||||
if ret~=nil then return ret,x end
|
||||
if ply:IsSuperAdmin() then return true end
|
||||
if target == TO_CLIENT and
|
||||
(target_ply == ply
|
||||
or (target_ply
|
||||
and istable(target_ply)
|
||||
and target_ply[1]==ply
|
||||
and table.Count(target_ply)==1))
|
||||
then
|
||||
if sv_allowcslua:GetBool() then return true end
|
||||
end
|
||||
end
|
||||
local luadev_show_access_attempt = SERVER and CreateConVar("luadev_show_access_attempt", '1', {FCVAR_ARCHIVE})
|
||||
|
||||
function RejectCommand(pl, msg)
|
||||
if msg == true or msg == "" then return end -- suppress error in case we want to process luadev command ourselves in a hook
|
||||
|
||||
if SERVER and luadev_show_access_attempt:GetBool() and not pl.luadevaccessfail then
|
||||
pl.luadevaccessfail = true
|
||||
Msg"[LuaDev] " print(pl, "was rejected luadev access", msg)
|
||||
end
|
||||
|
||||
S2C(pl, "No Access" .. (msg and (": " .. tostring(msg)) or ""))
|
||||
end
|
||||
function COMMAND(str,func,complete)
|
||||
if SERVER then
|
||||
concommand.Add('lua_'..str,function(pl,command,cmds,strcmd)
|
||||
local id=pl
|
||||
if IsValid(pl) then
|
||||
local ok,err = CanLuaDev(pl,strcmd,command,nil,nil,nil)
|
||||
if not ok then
|
||||
return RejectCommand (pl,err or command)
|
||||
end
|
||||
id = GetPlayerIdentifier(pl,str) or pl
|
||||
else
|
||||
pl = "Console"
|
||||
id = pl
|
||||
end
|
||||
func(pl,cmds,strcmd,id)
|
||||
end)
|
||||
else
|
||||
concommand.Add('lua_'..str,function(_,_,cmds,strcmd)
|
||||
func(pl,cmds,strcmd,str)
|
||||
end,(not complete and function(...) return AutoComplete(str,...) end) or nil)
|
||||
end
|
||||
end
|
||||
187
garrysmod/addons/luadev/lua/luadev/luadev_sv.lua
Normal file
187
garrysmod/addons/luadev/lua/luadev/luadev_sv.lua
Normal file
@@ -0,0 +1,187 @@
|
||||
module("luadev",package.seeall)
|
||||
|
||||
|
||||
-- inform the client of the version
|
||||
_luadev_version = CreateConVar( "_luadev_version", "1.6", FCVAR_NOTIFY )
|
||||
|
||||
function S2C(cl,msg)
|
||||
if cl and cl:IsValid() and cl:IsPlayer() then
|
||||
cl:ChatPrint("[LuaDev] "..tostring(msg))
|
||||
end
|
||||
end
|
||||
|
||||
function RunOnClients(script,who,extra)
|
||||
if not who and extra and isentity(extra) then extra = {ply=extra} end
|
||||
|
||||
local data={
|
||||
--src=script,
|
||||
info=who,
|
||||
extra=extra,
|
||||
}
|
||||
|
||||
if Verbose() then
|
||||
PrintX(script,tostring(who).." running on clients")
|
||||
end
|
||||
|
||||
net.Start(Tag)
|
||||
WriteCompressed(script)
|
||||
net.WriteTable(data)
|
||||
if net.BytesWritten()==65536 then
|
||||
return nil,"too big"
|
||||
end
|
||||
net.Broadcast()
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
local function ClearTargets(targets)
|
||||
local i=1
|
||||
local target=targets[i]
|
||||
while target do
|
||||
if not IsValid(target) then
|
||||
table.remove(targets,i)
|
||||
i=i-1
|
||||
end
|
||||
i=i+1
|
||||
target=targets[i]
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function RunOnClient(script,targets,who,extra)
|
||||
-- compat
|
||||
if not targets and isentity(who) then
|
||||
targets=who
|
||||
who = nil
|
||||
end
|
||||
|
||||
if extra and isentity(extra) and who==nil then
|
||||
extra={ply=extra}
|
||||
who="COMPAT"
|
||||
end
|
||||
|
||||
local data={
|
||||
--src=script,
|
||||
info=who,
|
||||
extra=extra,
|
||||
}
|
||||
|
||||
if not istable(targets) then
|
||||
targets = {targets}
|
||||
end
|
||||
|
||||
ClearTargets(targets)
|
||||
|
||||
if table.Count(targets)==0 then return nil,"no players" end
|
||||
|
||||
local targetslist
|
||||
for _,target in pairs(targets) do
|
||||
local pre = targetslist and ", " or ""
|
||||
targetslist=(targetslist or "")..pre..tostring(target)
|
||||
end
|
||||
|
||||
|
||||
if Verbose() then
|
||||
if type(who) == "string" and #who > 50 then
|
||||
who = who:sub(1,50).."...>"
|
||||
end
|
||||
PrintX(script,tostring(who).." running on "..tostring(targetslist or "NONE"))
|
||||
end
|
||||
|
||||
net.Start(Tag)
|
||||
WriteCompressed(script)
|
||||
net.WriteTable(data)
|
||||
if net.BytesWritten()==65536 then
|
||||
return nil,"too big"
|
||||
end
|
||||
net.Send(targets)
|
||||
|
||||
return #targets
|
||||
end
|
||||
|
||||
function RunOnServer(script,who,extra)
|
||||
if not who and extra and isentity(extra) then extra = {ply=extra} end
|
||||
|
||||
if Verbose() then
|
||||
PrintX(script,tostring(who).." running on server")
|
||||
end
|
||||
|
||||
return Run(script,tostring(who),extra)
|
||||
end
|
||||
|
||||
function RunOnSelf(script,who,extra)
|
||||
if not isstring(who) then who = nil end
|
||||
if not who and extra and isentity(extra) then extra = {ply=extra} end
|
||||
|
||||
return RunOnServer(script,who,extra)
|
||||
end
|
||||
|
||||
|
||||
function RunOnShared(...)
|
||||
RunOnClients(...)
|
||||
return RunOnServer(...)
|
||||
end
|
||||
|
||||
|
||||
function GetPlayerIdentifier(ply,extrainfo)
|
||||
if type(ply)=="Player" then
|
||||
|
||||
local info=ply:Name()
|
||||
|
||||
if Verbose(3) then
|
||||
local sid=ply:SteamID():gsub("^STEAM_","")
|
||||
info=('<%s|%s>'):format(sid,info:sub(1,24))
|
||||
elseif Verbose(2) then
|
||||
info=ply:SteamID():gsub("^STEAM_","")
|
||||
end
|
||||
if extrainfo then
|
||||
info=('%s<%s>'):format(info,tostring(extrainfo))
|
||||
end
|
||||
|
||||
info = info:gsub("%]","}"):gsub("%[","{"):gsub("%z","_") -- GMod bug
|
||||
|
||||
return info
|
||||
else
|
||||
return "??"..tostring(ply)
|
||||
end
|
||||
end
|
||||
|
||||
function _ReceivedData(len, ply)
|
||||
|
||||
local script = ReadCompressed() -- WriteCompressed(data)
|
||||
local decoded=net.ReadTable()
|
||||
decoded.src=script
|
||||
|
||||
|
||||
local target=decoded.dst
|
||||
local info = decoded.info
|
||||
local target_ply=decoded.dst_ply
|
||||
local extra=decoded.extra or {}
|
||||
if not istable(extra) then
|
||||
return RejectCommand(ply,"bad extra table")
|
||||
end
|
||||
extra.ply=ply
|
||||
|
||||
local can, msg = CanLuaDev(ply,script,nil,target,target_ply,extra)
|
||||
if not can then
|
||||
return RejectCommand(ply,msg)
|
||||
end
|
||||
|
||||
if TransmitHook(data)~=nil then return end
|
||||
|
||||
local identifier = GetPlayerIdentifier(ply,info)
|
||||
local ok,err
|
||||
if target==TO_SERVER then ok,err=RunOnServer (script, identifier,extra)
|
||||
elseif target==TO_CLIENT then ok,err=RunOnClient (script,target_ply, identifier,extra)
|
||||
elseif target==TO_CLIENTS then ok,err=RunOnClients(script, identifier,extra)
|
||||
elseif target==TO_SHARED then ok,err=RunOnShared (script, identifier,extra)
|
||||
else S2C(ply,"Unknown target")
|
||||
end
|
||||
|
||||
-- no callback system yet
|
||||
if not ok then
|
||||
ErrorNoHalt(tostring(err)..'\n')
|
||||
end
|
||||
|
||||
end
|
||||
net.Receive(Tag, function(...) _ReceivedData(...) end)
|
||||
146
garrysmod/addons/luadev/lua/luadev/socketdev.lua
Normal file
146
garrysmod/addons/luadev/lua/luadev/socketdev.lua
Normal file
@@ -0,0 +1,146 @@
|
||||
-- luacheck: globals luadev socket easylua chatbox
|
||||
|
||||
local function requireExists(moduleName)
|
||||
local osSuffix = assert(
|
||||
(system.IsWindows() and (jit.arch~="x64" and "win32" or "win64"))
|
||||
or (system.IsLinux() and "linux")
|
||||
or (system.IsOSX() and "osx"),
|
||||
"couldn't determine system type?"
|
||||
)
|
||||
local dllFiles = file.Find(string.format("lua/bin/gmcl_%s_%s.dll", moduleName, osSuffix), "GAME")
|
||||
local luaFileExists = file.Exists(string.format("includes/modules/%s.lua", moduleName), "LCL")
|
||||
|
||||
return #dllFiles > 0 or luaFileExists
|
||||
end
|
||||
|
||||
local function luadevPrint(...)
|
||||
Msg"[LuaDev] "
|
||||
print(...)
|
||||
end
|
||||
|
||||
local moduleLoaded = false
|
||||
for _, moduleName in ipairs({ "socket", "luasocket" }) do
|
||||
if requireExists(moduleName) then
|
||||
local ok, err = pcall(require, moduleName)
|
||||
if not ok then
|
||||
luadevPrint(
|
||||
string.format("Unable to load module %s: %s", moduleName, err)
|
||||
)
|
||||
else
|
||||
if not socket then
|
||||
luadevPrint(string.format("_G.socket not found, but module %s loaded?", moduleName))
|
||||
else
|
||||
moduleLoaded = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not moduleLoaded then
|
||||
luadevPrint("No socket module found")
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local methods = {
|
||||
self = function(sock)
|
||||
local who = sock:receive("*l")
|
||||
luadev.RunOnSelf(sock:receive("*a"), who)
|
||||
system.FlashWindow()
|
||||
end,
|
||||
sv = function(sock)
|
||||
local who = sock:receive("*l")
|
||||
luadev.RunOnServer(sock:receive("*a"), who)
|
||||
system.FlashWindow()
|
||||
end,
|
||||
sh = function(sock)
|
||||
local who = sock:receive("*l")
|
||||
luadev.RunOnShared(sock:receive("*a"), who)
|
||||
system.FlashWindow()
|
||||
end,
|
||||
cl = function(sock)
|
||||
local who = sock:receive("*l")
|
||||
luadev.RunOnClients(sock:receive("*a"), who)
|
||||
system.FlashWindow()
|
||||
end,
|
||||
ent = function(sock)
|
||||
local who = sock:receive("*l")
|
||||
local contents = string.format("ENT = {}; local ENT=ENT; %s; scripted_ents.Register(ENT, '%s')", sock:receive("*a"), who:sub(0, -5))
|
||||
luadev.RunOnShared(contents, who)
|
||||
system.FlashWindow()
|
||||
end,
|
||||
wep = function(sock)
|
||||
local who = sock:receive("*l")
|
||||
local contents = string.format("SWEP = {}; local SWEP=SWEP; %s; weapons.Register(SWEP, '%s')", sock:receive("*a"), who:sub(0, -5))
|
||||
luadev.RunOnShared(contents, who)
|
||||
system.FlashWindow()
|
||||
end,
|
||||
client = function(sock)
|
||||
local who = sock:receive("*l")
|
||||
local to = sock:receive("*l")
|
||||
to = easylua and easylua.FindEntity(to) or player.GetByID(tonumber(to))
|
||||
to = { to }
|
||||
luadev.RunOnClient(sock:receive("*a"), to, who)
|
||||
system.FlashWindow()
|
||||
end,
|
||||
chatTextChanged = function(sock)
|
||||
local contents = sock:receive("*a")
|
||||
if not contents then return end
|
||||
|
||||
if chatbox then
|
||||
chatbox.StartChat_override = true
|
||||
end
|
||||
hook.Run("StartChat")
|
||||
if chatbox then
|
||||
chatbox.StartChat_override = false
|
||||
end
|
||||
|
||||
hook.Run("ChatTextChanged", contents, true)
|
||||
end,
|
||||
finishChat = function(sock)
|
||||
hook.Run("FinishChat")
|
||||
end,
|
||||
requestPlayers = function(sock)
|
||||
local plys = {}
|
||||
for _, ply in next, player.GetAll() do
|
||||
table.insert(plys, ply:Nick())
|
||||
end
|
||||
|
||||
sock:send(table.concat(plys, "\n"))
|
||||
end
|
||||
}
|
||||
|
||||
local sock = assert(socket.tcp())
|
||||
assert(sock:bind("127.0.0.1", 27099))
|
||||
sock:settimeout(0)
|
||||
sock:setoption("reuseaddr", true)
|
||||
assert(sock:listen(0))
|
||||
|
||||
hook.Add("Think", "LuaDev-Socket", function()
|
||||
local cl = sock:accept()
|
||||
if not cl then return end
|
||||
|
||||
if cl:getpeername() ~= "127.0.0.1" then
|
||||
luadevPrint("Refused", cl:getpeername())
|
||||
cl:shutdown()
|
||||
return
|
||||
end
|
||||
|
||||
cl:settimeout(0)
|
||||
|
||||
local protocol = cl:receive("*l")
|
||||
local method
|
||||
|
||||
if protocol == "extension" then
|
||||
method = cl:receive("*l")
|
||||
else
|
||||
method = protocol
|
||||
end
|
||||
|
||||
if method and methods[method] then
|
||||
methods[method](cl)
|
||||
end
|
||||
|
||||
cl:shutdown()
|
||||
end)
|
||||
Reference in New Issue
Block a user