-- NOTE by Clavus: glon was removed from GMod 13, replaced by the util.TableToJSON etc functions -- In order to maintain compatability and not rewrite all that shit, I'm including it with the SCK. -- GLON: Garry's Mod Lua Object Notation -- A extension of LON: Lua Object Notation -- Made entirely by Deco Da Man -- Types: -- 2: table -- 3: array -- 4: fasle boolean -- 5: true boolean -- 6: number (NOT COMPRESSED, it isn't worth it) -- 7: string ---- non-LON types start here! -- 8: Vector (NOT COMPRESSED, it isn't worth it) -- 9: Angle (NOT COMPRESSED, it isn't worth it) -- 10: Entity (Can do players, vehicles, npcs, weapons and any other type of entity (-1 for null entity)) -- 11: Player (By UserID) -- 12: CEffectData -- 13: ConVar (Not ClientConVar) -- 15: Color -- 254: The number equal to -math.huge (tostring(math.huge) == "-1.#INF") -- 254: The number equal to math.huge (tostring(math.huge) == "1.#INF") -- 255: reference (Sends the ID of the table to use (for "local t = {} t.a=t")) --[[local pairs = pairs local type = type local string = string local math = math local tostring = tostring local ValidEntity = ValidEntity local error = error local print = print local setmetatable = setmetatable local Vector = Vector local Angle = Angle local Entity = Entity local EffectData = EffectData local GetConVar = GetConVar local tonumber = tonumber local player = player local IsValid = IsValid module("glon")]] glon = {} local encode_types local decode_types local Write local Read local function InDataEscape(s) s = string.gsub(s, "([\1\2])", "\2%1") s = string.gsub(s, "%z", "\2\3") s = string.gsub(s, "\"", "\4") -- escape the " character to simplify client commands return s end encode_types = { ["nil"] = {nil, function() return "", nil end}, table = {2, function(o, rtabs) for k,v in pairs(rtabs) do if v == o then return tostring(k).."\1", 255 end end rtabs[#rtabs+1] = o local is_array = true local i = 0 for k,v in pairs(o) do i = i + 1 if k ~= i or type(k) ~= "number" or math.floor(k) ~= k then is_array = false break end end local s = "" for k,v in pairs(o) do if ( !encode_types[type(v)] ) then continue end if not is_array then s = s..Write(k, rtabs) end s = s..Write(v, rtabs) end return s.."\1", is_array and 3 end}, boolean = {4, function(o) return "", o and 5 end}, number = {6, function(o) o = o == 0 and "" or o return o == ((o == math.huge or o == -math.huge) and "") or tostring(o).."\1", (o == math.huge and 254) or (o == -math.huge and 253) end}, string = {7, function(o) return InDataEscape(o).."\1" end}, -- non-LON types start here! Vector = {8, function(o) return o.x.."\1"..o.y.."\1"..o.z.."\1" end}, Angle = {9, function(o) return o.p.."\1"..o.y.."\1"..o.r.."\1" end}, Entity = {10, function(o) return (ValidEntity(o) and o:EntIndex() or -1).."\1" end}, NPC = {10, function(o) return (ValidEntity(o) and o:EntIndex() or -1).."\1" end}, Weapon = {10, function(o) return (ValidEntity(o) and o:EntIndex() or -1).."\1" end}, Player = {11, function(o) return o:EntIndex().."\1" end}, CEffectData = {12, function(o, rtabs) local t = {} if o:GetAngle() ~= Angle(0,0,0) then t.a = o:GetAngle() end if o:GetAttachment() ~= 0 then t.h = o:GetAttachment() end if o:GetEntity():IsValid() then t.e = o:GetEntity() end if o:GetMagnitude() ~= 0 then t.m = o:GetMagnitude() end if o:GetNormal() ~= Vector(0,0,0) then t.n = o:GetNormal() end if o:GetOrigin() ~= Vector(0,0,0) then t.o = o:GetOrigin() end if o:GetRadius() ~= 0 then t.r = o:GetRadius() end if o:GetScale() ~= 0 then t.c = o:GetScale() end if o:GetStart() ~= 0 then t.s = o:GetStart() end if o:GetSurfaceProp() ~= 0 then t.p = o:GetSurfaceProp() end return encode_types.table[2](t, rtabs) end}, ConVar = {13, function(o) return InDataEscape(o:GetName()).."\1" end}, PhysObj = {14, function(o) local parent, obj, id = o:GetEntity() for i = 1, parent:GetPhysicsObjectCount() do obj = parent:GetPhysicsObjectNum() if obj == o then id = i break end end return parent:EntIndex().."\1"..id.."\1" end}, Color = {15, function(o) return o.r.."\1"..o.g.."\1"..o.b.."\1"..o.a.."\1" end}, } Write = function(data, rtabs) local t = encode_types[type(data)] if t then local data, id_override = t[2](data, rtabs) local char = id_override or t[1] or "" if char ~= "" then char = string.char(char) end return char..(data or "") else error(string.format("Tried to write unwriteable type: %s", type(data))) end end local CEffectDataTranslation = { a = "Angle", h = "Attachment", e = "Entity", m = "Magnitude", n = "Normal", o = "Origin", r = "Radius", c = "Scale", s = "Start", p = "SurfaceProp", } decode_types = { -- \2\6omg\1\6omgavalue\1\1 [2 ] = function(reader, rtabs) -- table local t, c, pos = {}, reader:Next() rtabs[#rtabs+1] = t local stage = false local key while true do c, pos = reader:Peek() if c == "\1" then if stage then error(string.format("Expected value to match key at %s! (Got EO Table)", pos)) else reader:Next() return t end else if stage then t[key] = Read(reader, rtabs) else key = Read(reader, rtabs) end stage = not stage end end end, [3 ] = function(reader, rtabs) -- array local t, i, c, pos = {}, 1, reader:Next() rtabs[#rtabs+1] = t while true do c, pos = reader:Peek() if c == "\1" then reader:Next() return t else t[i] = Read(reader, rtabs) i = i+1 end end end, [4 ] = function(reader) -- false boolean reader:Next() return false end, [5 ] = function(reader) -- true boolean reader:Next() return true end, [6 ] = function(reader) -- number local s, c, pos, e = "", reader:Next() while true do c = reader:Next() if not c then error(string.format("Expected \1 to end number at %s! (Got EOF!)", pos)) elseif c == "\1" then break else s = s..c end end if s == "" then s = "0" end local n = tonumber(s) if not n then error(string.format("Invalid number at %s! (%q)", pos, s)) end return n end, [7 ] = function(reader) -- string local s, c, pos, e = "", reader:Next() while true do c = reader:Next() if not c then error(string.format("Expected unescaped \1 to end string at position %s! (Got EOF)", pos)) elseif e then if c == "\3" then s = s.."\0" else s = s..c end e = false elseif c == "\2" then e = true elseif c == "\1" then s = string.gsub(s, "\4", "\"") -- unescape quotes return s else s = s..c end end end, [8 ] = function(reader) -- Vector local x = decode_types[6](reader) reader:StepBack() local y = decode_types[6](reader) reader:StepBack() local z = decode_types[6](reader) return Vector(x, y, z) end, [9 ] = function(reader) -- Angle local p = decode_types[6](reader) reader:StepBack() local y = decode_types[6](reader) reader:StepBack() local r = decode_types[6](reader) return Angle(p, y, r) end, [10 ] = function(reader) -- Entity return Entity(decode_types[6](reader)) end, [11 ] = function(reader) -- Player local num = decode_types[6](reader) return player.GetByID(num) end, [12 ] = function(reader, rtabs) -- CEffectData local t = decode_types[2](reader, rtabs) local d = EffectData() for k,v in pairs(t) do d["Set"..CEffectDataTranslation[k]](d, v) end return d end, [13 ] = function(reader) -- ConVar return GetConVar(decode_types[7](reader)) end, [14 ] = function(reader) -- PhysicsObject local ent = Entity(decode_types[6](reader)) local bone = decode_types[6](reader) if ( !IsValid( ent ) ) then return nil end; return ent:GetPhysicsObjectNum( bone ) end, [15 ] = function(reader) -- Color local r = decode_types[6](reader) reader:StepBack() local g = decode_types[6](reader) reader:StepBack() local b = decode_types[6](reader) reader:StepBack() local a = decode_types[6](reader) return Color(r, g, b, a) end, [253] = function(reader) -- -math.huge reader:Next() return -math.huge end, [254] = function(reader) -- math.huge reader:Next() return math.huge end, [255] = function(reader, rtabs) -- Reference return rtabs[decode_types[6](reader) - 1] end, } Read = function(reader, rtabs) local t, pos = reader:Peek() if not t then error(string.format("Expected type ID at %s! (Got EOF)", pos)) else local dt = decode_types[string.byte(t)] if not dt then error(string.format("Unknown type ID, %s!", string.byte(t))) else return dt(reader, rtabs or {0}) end end end local reader_meta = {} reader_meta.__index = reader_meta reader_meta.Next = function(self) self.i = self.i+1 self.c = string.sub(self.s, self.i, self.i) if self.c == "" then self.c = nil end self.p = string.sub(self.s, self.i+1, self.i+1) if self.p == "" then self.p = nil end return self.c, self.i end reader_meta.StepBack = function(self) self.i = self.i-1 self.c = string.sub(self.s, self.i, self.i) if self.c == "" then self.c = nil end self.p = string.sub(self.s, self.i+1, self.i+1) if self.p == "" then self.p = nil end return self.c, self.i end reader_meta.Peek = function(self) return self.p, self.i+1 end function glon.decode(data) if type(data) == "nil" then return nil elseif type(data) ~= "string" then error(string.format("Expected string to decode! (Got type %s)", type(data) )) elseif data:len() == 0 then return nil end return Read(setmetatable({ s = data, i = 0, c = string.sub(data, 0, 0), p = string.sub(data, 1, 1), }, reader_meta), {}) end function glon.encode(data) return Write(data, {0}) -- to use the first key, to prevent it from interfereing with \1s. You can have up to 254 unique tables (including arrays) end