diff --git a/lua/entities/gmod_wire_egp/lib/egplib/objectcontrol.lua b/lua/entities/gmod_wire_egp/lib/egplib/objectcontrol.lua index ede1040ff9..8778b38f07 100644 --- a/lua/entities/gmod_wire_egp/lib/egplib/objectcontrol.lua +++ b/lua/entities/gmod_wire_egp/lib/egplib/objectcontrol.lua @@ -3,47 +3,91 @@ -------------------------------------------------------- local EGP = EGP -EGP.Objects = {} -EGP.Objects.Names = {} -EGP.Objects.Names_Inverted = {} +local egpObjects = {} +egpObjects.Names = {} +egpObjects.Names_Inverted = {} +EGP.Objects = egpObjects -- This object is not used. It's only a base -EGP.Objects.Base = {} -EGP.Objects.Base.ID = 0 -EGP.Objects.Base.x = 0 -EGP.Objects.Base.y = 0 -EGP.Objects.Base.w = 0 -EGP.Objects.Base.h = 0 -EGP.Objects.Base.r = 255 -EGP.Objects.Base.g = 255 -EGP.Objects.Base.b = 255 -EGP.Objects.Base.a = 255 -EGP.Objects.Base.filtering = TEXFILTER.ANISOTROPIC -EGP.Objects.Base.material = "" -if CLIENT then EGP.Objects.Base.material = false end -EGP.Objects.Base.parent = 0 -EGP.Objects.Base.Transmit = function( self ) - EGP:SendPosSize( self ) +local baseObj = {} +baseObj.ID = 0 +baseObj.x = 0 +baseObj.y = 0 +baseObj.angle = 0 +baseObj.r = 255 +baseObj.g = 255 +baseObj.b = 255 +baseObj.a = 255 +baseObj.filtering = TEXFILTER.ANISOTROPIC +baseObj.parent = 0 +if SERVER then + baseObj.material = "" + baseObj.EGP = NULL -- EGP entity parent +else + baseObj.material = false +end +function baseObj:Transmit() + EGP.SendPosAng(self) EGP:SendColor( self ) - EGP:SendMaterial( self ) - net.WriteUInt(math.Clamp(self.filtering,0,3), 2) + EGP:SendMaterial(self) + if self.filtering then net.WriteUInt(math.Clamp(self.filtering,0,3), 2) end net.WriteInt( self.parent, 16 ) end -EGP.Objects.Base.Receive = function( self ) +function baseObj:Receive() local tbl = {} - EGP:ReceivePosSize( tbl ) + EGP.ReceivePosAng(tbl) EGP:ReceiveColor( tbl, self ) EGP:ReceiveMaterial( tbl ) - tbl.filtering = net.ReadUInt(2) + if self.filtering then tbl.filtering = net.ReadUInt(2) end tbl.parent = net.ReadInt(16) return tbl end -EGP.Objects.Base.DataStreamInfo = function( self ) - return { x = self.x, y = self.y, w = self.w, h = self.h, r = self.r, g = self.g, b = self.b, a = self.a, material = self.material, filtering = self.filtering, parent = self.parent } +function baseObj:DataStreamInfo() + return { x = self.x, y = self.y, angle = self.angle, w = self.w, h = self.h, r = self.r, g = self.g, b = self.b, a = self.a, material = self.material, parent = self.parent } end -function EGP.Objects.Base:Contains(point) +function baseObj:Contains(x, y) return false end +function baseObj:EditObject(args) + local ret = false + if args.x or args.y or args.angle then + ret = self:SetPos(args.x or self.x, args.y or self.y, args.angle or self.angle) + args.x, args.y, args.angle = nil, nil, nil + end + for k, v in pairs(args) do + if self[k] ~= nil and self[k] ~= v then + self[k] = v + ret = true + end + end + return ret +end +baseObj.Initialize = baseObj.EditObject +function baseObj:SetPos(x, y, angle) + local ret = false + if x and self.x ~= x then self.x, ret = x, true end + if y and self.y ~= y then self.y, ret = y, true end + if angle then + angle = angle % 360 + if self.angle ~= angle then self.angle, ret = angle, true end + end + return ret +end +function baseObj:Set(member, value) + if self[member] and self[member] ~= value then + self[member] = value + return true + else + return false + end +end +local M_EGPObject = {__tostring = function(self) return "[EGPObject] ".. self.Name end} +setmetatable(baseObj, M_EGPObject) +EGP.Objects.Base = baseObj + +local M_NULL_EGPOBJECT = { __tostring = function(self) return "[EGPObject] NULL" end, __eq = function(a, b) return getmetatable(a) == getmetatable(b) end } +local NULL_EGPOBJECT = setmetatable({}, M_NULL_EGPOBJECT) +EGP.NULL_EGPOBJECT = NULL_EGPOBJECT ---------------------------- -- Get Object @@ -60,32 +104,54 @@ end -- Load all objects ---------------------------- -function EGP:NewObject( Name ) - if self.Objects[Name] then return self.Objects[Name] end +function EGP:NewObject(name, super) + local lower = name:lower() -- Makes my life easier + if not super then super = baseObj end + if self.Objects[lower] then return self.Objects[lower] end -- Create table - self.Objects[Name] = {} + self.Objects[lower] = {} -- Set info - self.Objects[Name].Name = Name - table.Inherit( self.Objects[Name], self.Objects.Base ) + self.Objects[lower].Name = name + table.Inherit(self.Objects[lower], super) -- Create lookup table local ID = table.Count(self.Objects) - self.Objects[Name].ID = ID - self.Objects.Names[Name] = ID + self.Objects[lower].ID = ID + self.Objects.Names[name] = ID -- Inverted lookup table - self.Objects.Names_Inverted[ID] = Name + self.Objects.Names_Inverted[ID] = lower - return self.Objects[Name] + return setmetatable(self.Objects[lower], M_EGPObject) end local folder = "entities/gmod_wire_egp/lib/objects/" -local files = file.Find(folder.."*.lua", "LUA") -table.sort( files ) -for _,v in pairs( files ) do - include(folder..v) - if (SERVER) then AddCSLuaFile(folder..v) end + +function EGP.ObjectInherit(to, from) + local super = egpObjects[from:lower()] + if super then + return EGP:NewObject(to, super) + else + local path = folder .. from .. ".lua" + if file.Exists(path, "LUA") then + super = include(path) + AddCSLuaFile(path) + return EGP:NewObject(to, super) + else + ErrorNoHalt(string.format("EGP couldn't find object '%s' to inherit from (to object '%s').\n", from, to)) + end + end +end + +do + local files = file.Find(folder.."*.lua", "LUA") + for _, v in ipairs(files) do + if not egpObjects[v:sub(1, #v - 4):lower()] then -- Remove the extension and check if the object already exists. + include(folder .. v) + AddCSLuaFile(folder .. v) + end + end end ---------------------------- @@ -193,44 +259,38 @@ end ---------------------------- function EGP:CreateObject( Ent, ObjID, Settings ) - if not self:ValidEGP(Ent) then return false end + if not self:ValidEGP(Ent) then return false, NULL_EGPOBJECT end if not self.Objects.Names_Inverted[ObjID] then ErrorNoHalt("Trying to create nonexistant object! Please report this error to Divran at wiremod.com. ObjID: " .. ObjID .. "\n") - return false + return false, NULL_EGPOBJECT end if SERVER then Settings.index = math.Round(math.Clamp(Settings.index or 1, 1, self.ConVars.MaxObjects:GetInt())) end + Settings.EGP = Ent local bool, k, v = self:HasObject( Ent, Settings.index ) if (bool) then -- Already exists. Change settings: if v.ID ~= ObjID then -- Not the same kind of object, create new local Obj = self:GetObjectByID( ObjID ) - self:EditObject( Obj, Settings ) + Obj:Initialize(Settings) Obj.index = Settings.index Ent.RenderTable[k] = Obj return true, Obj else - return self:EditObject( v, Settings ), v + return v:EditObject(Settings), v end else -- Did not exist. Create: local Obj = self:GetObjectByID( ObjID ) - self:EditObject( Obj, Settings ) + Obj:Initialize(Settings) Obj.index = Settings.index table.insert( Ent.RenderTable, Obj ) return true, Obj end end -function EGP:EditObject( Obj, Settings ) - local ret = false - for k,v in pairs( Settings ) do - if (Obj[k] ~= nil and Obj[k] ~= v) then - Obj[k] = v - ret = true - end - end - return ret +function EGP:EditObject(obj, settings) + return obj:EditObject(settings) end diff --git a/lua/entities/gmod_wire_egp/lib/egplib/parenting.lua b/lua/entities/gmod_wire_egp/lib/egplib/parenting.lua index 71331bace6..1f6a623a53 100644 --- a/lua/entities/gmod_wire_egp/lib/egplib/parenting.lua +++ b/lua/entities/gmod_wire_egp/lib/egplib/parenting.lua @@ -18,7 +18,7 @@ EGP.ParentingFuncs.addUV = addUV local function makeArray( v, fakepos ) local ret = {} if isstring(v.verticesindex) then - if (not fakepos) then + if not fakepos then if (not v["_"..v.verticesindex]) then EGP:AddParentIndexes( v ) end for k,v in ipairs( v["_"..v.verticesindex] ) do ret[#ret+1] = v.x @@ -31,7 +31,7 @@ local function makeArray( v, fakepos ) end end else - if (not fakepos) then + if fakepos then for k,v2 in ipairs( v.verticesindex ) do ret[#ret+1] = v["_"..v2[1]] ret[#ret+1] = v["_"..v2[2]] @@ -77,7 +77,7 @@ end EGP.ParentingFuncs.getCenter = getCenter -- Uses the output of GetGlobalPos instead. -local function getCenterFromPos(data) +local function getCenterFrom(data) local centerx, centery = 0, 0 local vertices = data.vertices local n = #vertices @@ -87,103 +87,71 @@ local function getCenterFromPos(data) end return centerx / n, centery / n end -EGP.ParentingFuncs.getCenterFromPos = getCenterFromPos +EGP.getCenterFrom = getCenterFrom -- (returns true if obj has vertices, false if not, followed by the new position data) -function EGP:GetGlobalPos( Ent, index ) - local bool, k, v = self:HasObject( Ent, index ) - if (bool) then - if (v.verticesindex) then -- Object has vertices - if (v.parent and v.parent ~= 0) then -- Object is parented - if (v.parent == -1) then -- object is parented to the cursor - local xy = {0,0} - if (CLIENT) then - xy = self:EGPCursor( Ent, LocalPlayer() ) - end - local x, y = xy[1], xy[2] - local r = makeArray( v ) - for i=1,#r,2 do - local x_ = r[i] - local y_ = r[i+1] - local vec, ang = LocalToWorld( Vector( x_, y_, 0 ), Angle(), Vector( x, y, 0 ), Angle() ) - r[i] = vec.x - r[i+1] = vec.y - end - local ret = {} - if isstring(v.verticesindex) then - local temp = makeTable( v, r ) - addUV( v, temp ) - ret = { [v.verticesindex] = temp } - else ret = makeTable( v, r ) end - return true, ret - else - local hasVertices, data = self:GetGlobalPos( Ent, v.parent ) - if (hasVertices) then -- obj and parent have vertices - local _, _, prnt = self:HasObject( Ent, v.parent ) - local centerx, centery = getCenter( makeArray( prnt, true ) ) - local temp = makeArray( v ) - for i=1,#temp,2 do - temp[i] = centerx + temp[i] - temp[i+1] = centery + temp[i+1] - end - local ret = {} - if isstring(v.verticesindex) then ret = { [v.verticesindex] = makeTable( v, temp ) } else ret = makeTable( v, temp ) end - return true, ret - else -- obj has vertices, parent does not - local x, y, ang = data.x, data.y, data.angle - local r = makeArray( v ) - for i=1,#r,2 do - local x_ = r[i] - local y_ = r[i+1] - local vec, ang = LocalToWorld( Vector( x_, y_, 0 ), Angle( 0, 0, 0 ), Vector( x, y, 0 ), Angle( 0, -ang, 0 ) ) - r[i] = vec.x - r[i+1] = vec.y - end - local ret = {} - if isstring(v.verticesindex) then - local temp = makeTable( v, r ) - addUV( v, temp ) - ret = { [v.verticesindex] = temp } - else ret = makeTable( v, r ) end - return true, ret - end - end - local ret = {} - if isstring(v.verticesindex) then ret = { [v.verticesindex] = makeTable( v, makeArray( v ) ) } else ret = makeTable( v, makeArray( v ) ) end - return true, ret - end - local ret = {} - if isstring(v.verticesindex) then ret = { [v.verticesindex] = makeTable( v, makeArray(v, true) ) } else ret = makeTable( v, makeArray(v, true) ) end - return true, ret - else -- Object does not have vertices, parent does not - if (v.parent and v.parent ~= 0) then -- Object is parented - if (v.parent == -1) then -- Object is parented to the cursor - local xy = {0,0} - if (CLIENT) then - xy = self:EGPCursor( Ent, LocalPlayer() ) - end - local x, y = xy[1], xy[2] - local vec, ang = LocalToWorld( Vector( v._x, v._y, 0 ), Angle( 0, v._angle or 0, 0 ), Vector( x, y, 0 ), Angle() ) - return false, { x = vec.x, y = vec.y, angle = -ang.y } - else - local hasVertices, data = self:GetGlobalPos( Ent, v.parent ) - if (hasVertices) then -- obj does not have vertices, parent does - local _, _, prnt = self:HasObject( Ent, v.parent ) - local centerx, centery = getCenter( makeArray( prnt, true ) ) - return false, { x = (v._x or v.x) + centerx, y = (v._y or v.y) + centery, angle = -(v._angle or v.angle) } - else -- Niether have vertices - local x, y, ang = data.x, data.y, data.angle - local vec, ang = LocalToWorld( Vector( v._x, v._y, 0 ), Angle( 0, v._angle or 0, 0 ), Vector( x, y, 0 ), Angle( 0, -(ang or 0), 0 ) ) - return false, { x = vec.x, y = vec.y, angle = -ang.y } - end +local function GetGlobalPos(self, Ent, index) + if self ~= EGP then Ent, index = self, Ent end + local bool, obj + if istable(index) then + obj = index + bool = true + else + bool, _, obj = self:HasObject(Ent, index) + end + if bool then + if obj.parent and obj.parent ~= 0 then -- Object is parented + if obj.parent == -1 then -- Object is parented to the cursor + local x, y = 0, 0 + if CLIENT then + xy = EGP:EGPCursor( Ent, LocalPlayer() ) + x, y = xy[1], xy[2] end + + local vec, ang = LocalToWorld(Vector(obj._x, obj._y, 0), Angle(0, obj._angle or 0, 0), Vector(x, y, 0), angle_zero) + return obj.verticesindex ~= nil, { x = vec.x, y = vec.y, angle = -ang.y } + else + local _, data = GetGlobalPos(Ent, select(3, EGP:HasObject(Ent, obj.parent))) + local vec, ang = LocalToWorld(Vector(obj._x, obj._y, 0), Angle(0, -obj._angle or 0, 0), Vector(data.x, data.y, 0), Angle(0, -data.angle or 0, 0)) + return obj.verticesindex ~= nil, { x = vec.x, y = vec.y, angle = -ang.y } end - return false, { x = v.x, y = v.y, angle = v.angle or 0 } end + return obj.verticesindex ~= nil, { x = obj.x, y = obj.y, angle = obj.angle or 0 } end - return false, {x=0,y=0,angle=0} + return false, { x = 0, y = 0, angle = 0 } end +EGP.GetGlobalPos = GetGlobalPos + + +local function getGlobalVertices(ent, obj) + if obj.verticesindex then + local _, globalpos = GetGlobalPos(ent, obj) + local gx, gy, gang = globalpos.x, globalpos.y, globalpos.angle + + local r = makeArray(obj, obj.parent ~= NULL_EGPOBJECT) + local globalvec, globalang = Vector(gx, gy, 0), Angle(0, -gang, 0) + local objang = obj._angle or obj.angle or 0 + for i = 1, #r, 2 do + local x_ = r[i] + local y_ = r[i + 1] + local vec = LocalToWorld(Vector(x_, y_, 0), Angle(0, objang, 0), globalvec, globalang) + r[i] = vec.x + r[i + 1] = vec.y + end + + local ret + if isstring(obj.verticesindex) then + local temp = makeTable(obj, r) + addUV(obj, temp) + ret = { [obj.verticesindex] = temp } + else + ret = makeTable(obj, r) + end + return ret + end +end +EGP.GetGlobalVertices = getGlobalVertices -------------------------------------------------------- -- Parenting functions @@ -200,11 +168,10 @@ function EGP:AddParentIndexes( v ) v["_"..v2[2]] = v[v2[2]] end end - else - v._x = v.x - v._y = v.y - v._angle = v.angle end + v._x = v.x + v._y = v.y + v._angle = v.angle v.IsParented = true end @@ -237,14 +204,23 @@ local function CheckParents( Ent, Obj, parentindex, checked ) end function EGP:SetParent( Ent, index, parentindex ) - local bool, k, v = self:HasObject( Ent, index ) + local bool, v + if isnumber(index) then + bool, _, v = self:HasObject(Ent, index) + else + bool, v = index ~= nil, index + end if (bool) then if (parentindex == -1) then -- Parent to cursor? if (self:EditObject( v, { parent = parentindex } )) then return true, v end else - local bool2, k2, v2 = self:HasObject( Ent, parentindex ) - if (bool2) then - self:AddParentIndexes( v ) + if isnumber(parentindex) then + bool = self:HasObject(Ent, parentindex) + else + bool, parentindex = parentindex ~= nil, parentindex.index + end + if (bool) then + EGP:AddParentIndexes( v ) if (SERVER) then parentindex = math.Clamp(parentindex,1,self.ConVars.MaxObjects:GetInt()) end @@ -255,7 +231,7 @@ function EGP:SetParent( Ent, index, parentindex ) -- If the user is trying to create a circle of parents, causing an infinite loop if (not CheckParents( Ent, v, parentindex, {} )) then return false end - if (self:EditObject( v, { parent = parentindex } )) then return true, v end + if v:Set("parent", parentindex) then return true, v end end end end @@ -272,31 +248,30 @@ function EGP:RemoveParentIndexes( v, hasVertices ) v["_"..v2[2]] = nil end end - else - v._x = nil - v._y = nil - v._angle = nil end + v._x = nil + v._y = nil + v._angle = nil v.IsParented = nil end function EGP:UnParent( Ent, index ) - local bool, k, v = false + local bool, v = false if isnumber(index) then - bool, k, v = self:HasObject( Ent, index ) - elseif istable(index) then - bool = true + bool, _, v = self:HasObject( Ent, index ) + else + bool = istable(index) v = index index = v.index end if (bool) then - local hasVertices, data = self:GetGlobalPos( Ent, index ) - self:RemoveParentIndexes( v, hasVertices ) + local hasVertices, data = EGP:GetGlobalPos( Ent, index ) + EGP:RemoveParentIndexes( v, hasVertices ) if (not v.parent or v.parent == 0) then return false end data.parent = 0 - if (self:EditObject( v, data, Ent:GetPlayer() )) then return true, v end + if v:EditObject(data) then return true, v end end end diff --git a/lua/entities/gmod_wire_egp/lib/egplib/queuesystem.lua b/lua/entities/gmod_wire_egp/lib/egplib/queuesystem.lua index bf82455fa9..215e2f1f4d 100644 --- a/lua/entities/gmod_wire_egp/lib/egplib/queuesystem.lua +++ b/lua/entities/gmod_wire_egp/lib/egplib/queuesystem.lua @@ -22,13 +22,13 @@ function EGP:AddQueueObject( Ent, ply, Function, Object ) found = true if (v.OnRemove) then v:OnRemove() end local Obj = self:GetObjectByID( Object.ID ) - self:EditObject( Obj, Object:DataStreamInfo() ) + Obj:EditObject(Object:DataStreamInfo()) Obj.index = v.index if (Obj.OnCreate) then Obj:OnCreate() end LastItem.Args[1][k] = Obj else -- Edit found = true - self:EditObject( v, Object:DataStreamInfo() ) + v:EditObject(Object:DataStreamInfo()) end break diff --git a/lua/entities/gmod_wire_egp/lib/egplib/transmitreceive.lua b/lua/entities/gmod_wire_egp/lib/egplib/transmitreceive.lua index 0833203d55..05812e7579 100644 --- a/lua/entities/gmod_wire_egp/lib/egplib/transmitreceive.lua +++ b/lua/entities/gmod_wire_egp/lib/egplib/transmitreceive.lua @@ -91,7 +91,7 @@ if (SERVER) then return end - local bool, k, v = EGP:HasObject( Ent, index ) + local bool, _, v = EGP:HasObject( Ent, index ) if (bool) then if not EGP.umsg.Start("EGP_Transmit_Data", ply) then return end net.WriteEntity( Ent ) @@ -123,7 +123,7 @@ if (SERVER) then return end - local bool, k, v = EGP:HasObject( Ent, index ) + local bool, _, v = EGP:HasObject( Ent, index ) if (bool) then if not EGP.umsg.Start("EGP_Transmit_Data", ply) then return end net.WriteEntity( Ent ) @@ -149,13 +149,12 @@ if (SERVER) then util.AddNetworkString( "AddText" ) local function AddText( Ent, ply, index, text ) if not IsValid(ply) or not ply:IsPlayer() then return end - if (EGP:CheckInterval( ply ) == false) then + if EGP:CheckInterval( ply ) == false then EGP:InsertQueue( Ent, ply, AddText, "AddText", index, text ) return end - local bool, k, v = EGP:HasObject( Ent, index ) - if (bool) then + if EGP:HasObject(Ent, index) then if not EGP.umsg.Start("EGP_Transmit_Data", ply) then return end net.WriteEntity( Ent ) net.WriteString( "AddText" ) @@ -176,8 +175,7 @@ if (SERVER) then return end - local bool, k, v = EGP:HasObject( Ent, index ) - if (bool) then + if EGP:HasObject(Ent, index) then if not EGP.umsg.Start("EGP_Transmit_Data", ply) then return end net.WriteEntity( Ent ) net.WriteString( "SetText" ) @@ -265,7 +263,10 @@ if (SERVER) then net.WriteUInt(v.ID, 8) -- Else send the ID of the object if (Ent.Scaling or Ent.TopLeft) then + local original = v v = table.Copy(v) -- Make a copy of the table so it doesn't overwrite the serverside object + -- Todo: Make transmit only used for server join/leave/"newframes"/etc, not every time it updates + if original.VerticesUpdate then original.VerticesUpdate = false end end -- Scale the positions and size @@ -275,7 +276,7 @@ if (SERVER) then -- Move the object to draw from the top left if (Ent.TopLeft) then - EGP:MoveTopLeft( Ent, v ) + EGP.MoveTopLeft( Ent, v ) end if v.ChangeOrder then -- We want to change the order of this object, send the index to where we wish to move it @@ -306,16 +307,17 @@ if (SERVER) then function EGP:DoAction( Ent, E2, Action, ... ) if (Action == "SendObject") then local Data = {...} - if not Data[1] then return end + local obj = Data[1] + if not obj or obj._nodraw then return end if (E2 and E2.entity and E2.entity:IsValid()) then E2.prf = E2.prf + 30 end - self:AddQueueObject( Ent, E2.player, SendObjects, Data[1] ) + self:AddQueueObject( Ent, E2.player, SendObjects, obj) elseif (Action == "RemoveObject") then local Data = {...} - if not Data[1] then return end + local obj = Data[1] if (E2 and E2.entity and E2.entity:IsValid()) then E2.prf = E2.prf + 20 @@ -323,7 +325,7 @@ if (SERVER) then for i=1,#Ent.RenderTable do E2.prf = E2.prf + 0.3 - if Ent.RenderTable[i].index == Data[1] then + if Ent.RenderTable[i].index == obj then table.remove( Ent.RenderTable, i ) break end @@ -407,53 +409,49 @@ else -- SERVER/CLIENT elseif (Action == "SetText") then local index = net.ReadInt(16) local text = net.ReadString() - local bool,k,v = EGP:HasObject( Ent, index ) + local bool,_,v = EGP:HasObject( Ent, index ) if (bool) then if (EGP:EditObject( v, { text = text } )) then Ent:EGP_Update() end end elseif (Action == "AddText") then local index = net.ReadInt(16) local text = net.ReadString() - local bool,k,v = EGP:HasObject( Ent, index ) + local bool,_,v = EGP:HasObject( Ent, index ) if (bool) then if (EGP:EditObject( v, { text = v.text .. text } )) then Ent:EGP_Update() end end elseif (Action == "SetVertex") then local index = net.ReadInt(16) - local bool, k,v = EGP:HasObject( Ent, index ) + local bool, _, v = EGP:HasObject( Ent, index ) if (bool) then local vertices = {} if (v.HasUV) then - local n = 0 for i=1,net.ReadUInt(8) do local x, y, u, _v = net.ReadInt(16), net.ReadInt(16), net.ReadFloat(), net.ReadFloat() vertices[i] = { x=x, y=y, u=u, v=_v } end else - local n = 0 for i=1,net.ReadUInt(8) do local x, y = net.ReadInt(16), net.ReadInt(16) vertices[i] = { x=x, y=y } end end - if (EGP:EditObject( v, { vertices = vertices })) then Ent:EGP_Update() end + if v:EditObject({ vertices = vertices }) then Ent:EGP_Update() end end elseif (Action == "AddVertex") then local index = net.ReadInt(16) - local bool, k, v = EGP:HasObject( Ent, index ) + local bool, _, v = EGP:HasObject( Ent, index ) if (bool) then local vertices = table.Copy(v.vertices) if (v.HasUV) then - local n = 0 for i=1,net.ReadUInt(8) do local x, y, u, _v = net.ReadInt(16), net.ReadInt(16), net.ReadFloat(), net.ReadFloat() vertices[#vertices+1] = { x=x, y=y, u=u, v=_v } end else - local n = 0 for i=1,net.ReadUInt(8) do local x, y = net.ReadInt(16), net.ReadInt(16) vertices[#vertices+1] = { x=x, y=y } @@ -505,14 +503,14 @@ else -- SERVER/CLIENT if (v.OnRemove) then v:OnRemove() end local Obj = self:GetObjectByID( ID ) local data = Obj:Receive() - self:EditObject( Obj, data ) + Obj:Initialize(data) Obj.index = index Ent.RenderTable[k] = Obj if (Obj.OnCreate) then Obj:OnCreate() end current_obj = Obj else -- Edit - self:EditObject( v, v:Receive() ) + v:EditObject(v:Receive()) -- If parented, reset the parent indexes if (v.parent and v.parent ~= 0) then @@ -525,7 +523,7 @@ else -- SERVER/CLIENT v.res = nil else -- Object does not exist. Create new local Obj = self:GetObjectByID( ID ) - self:EditObject( Obj, Obj:Receive() ) + Obj:Initialize(Obj:Receive()) Obj.index = index if (Obj.OnCreate) then Obj:OnCreate() end Ent.RenderTable[#Ent.RenderTable+1] = Obj--table.insert( Ent.RenderTable, Obj ) @@ -625,7 +623,7 @@ if (SERVER) then -- Move the object to draw from the top left if (v.TopLeft) then - EGP:MoveTopLeft( v, obj ) + EGP.MoveTopLeft( v, obj ) end DataToSend[#DataToSend+1] = { ID = obj.ID, index = obj.index, Settings = obj:DataStreamInfo() } @@ -676,7 +674,7 @@ else end for _,v in pairs( Objects ) do local Obj = self:GetObjectByID(v.ID) - self:EditObject( Obj, v.Settings ) + Obj:Initialize(v.Settings) -- If parented, reset the parent indexes if (Obj.parent and Obj.parent ~= 0) then self:AddParentIndexes( Obj ) diff --git a/lua/entities/gmod_wire_egp/lib/egplib/usefulfunctions.lua b/lua/entities/gmod_wire_egp/lib/egplib/usefulfunctions.lua index c3b7cff819..7636c1b6bb 100644 --- a/lua/entities/gmod_wire_egp/lib/egplib/usefulfunctions.lua +++ b/lua/entities/gmod_wire_egp/lib/egplib/usefulfunctions.lua @@ -59,8 +59,7 @@ function EGP:ScaleObject( ent, v ) end local settings = makeTable(v, r) addUV(v, settings) - if isstring(v.verticesindex) then settings = { [v.verticesindex] = settings } end - self:EditObject( v, settings ) + if isstring(v.verticesindex) then v.vertices = settings else v:EditObject(settings) end else if (v.x) then v.x = (v.x - xMin) * xMul @@ -81,8 +80,8 @@ end -- Draw from top left -------------------------------------------------------- -function EGP:MoveTopLeft(ent, obj) - if not self:ValidEGP(ent) then return end +function EGP.MoveTopLeft(ent, obj) + if not EGP:ValidEGP(ent) then return end local t = nil if obj.CanTopLeft and obj.x and obj.y and obj.w and obj.h then @@ -91,34 +90,18 @@ function EGP:MoveTopLeft(ent, obj) if obj.angle then t.angle = -ang.yaw end end if obj.IsParented then - local bool, _, parent = self:HasObject(ent, obj.parent) + local bool, _, parent = EGP:HasObject(ent, obj.parent) if bool and parent.CanTopLeft and parent.w and parent.h then - if isstring(obj.verticesindex) then - local vertices = {} - local w, h = parent.w / 2, parent.h / 2 - for i, v in ipairs(obj[obj.verticesindex]) do - vertices[i] = { x = v.x - w, y = v.y - h } - end - t = { vertices = vertices } - elseif obj.verticesindex ~= nil then - t = {} - local w, h = parent.w / 2, parent.h / 2 - for i, v in ipairs(obj.verticesindex) do - t[v[1]] = obj[v[1]] - w - t[v[2]] = obj[v[2]] - h - end - else - if not t then t = { x = obj.x, y = obj.y, angle = obj.angle } end - t.x = t.x - parent.w / 2 - t.y = t.y - parent.h / 2 - end + if not t then t = { x = obj.x, y = obj.y, angle = obj.angle } end + t.x = t.x - parent.w / 2 + t.y = t.y - parent.h / 2 + + if t.angle then t.angle = t.angle end end - if not t then t = { angle = obj.angle } end - if t.angle then t.angle = -t.angle end end if t then - self:EditObject(obj, t) + obj:EditObject(t) end end @@ -206,11 +189,15 @@ end ----------------------- -- Other ----------------------- -function EGP:SendPosSize( obj ) - net.WriteInt( obj.w, 16 ) - net.WriteInt( obj.h, 16 ) +function EGP.SendPosAng(obj) net.WriteInt( obj.x, 16 ) net.WriteInt( obj.y, 16 ) + net.WriteInt(obj.angle * 64, 16) +end + +function EGP.SendSize(obj) + net.WriteInt(obj.w, 16) + net.WriteInt(obj.h, 16) end function EGP:SendColor( obj ) @@ -220,11 +207,15 @@ function EGP:SendColor( obj ) if (obj.a) then net.WriteUInt( math.Clamp( obj.a, 0, 255 ) , 8) end end -function EGP:ReceivePosSize( tbl ) -- Used with SendPosSize - tbl.w = net.ReadInt(16) - tbl.h = net.ReadInt(16) +function EGP.ReceivePosAng(tbl) tbl.x = net.ReadInt(16) tbl.y = net.ReadInt(16) + tbl.angle = net.ReadInt(16) / 64 +end + +function EGP.ReceiveSize(tbl) + tbl.w = net.ReadInt(16) + tbl.h = net.ReadInt(16) end function EGP:ReceiveColor( tbl, obj ) -- Used with SendColor @@ -238,7 +229,7 @@ end -- Other -------------------------------------------------------- function EGP:ValidEGP( Ent ) - return (IsValid( Ent ) and (Ent:GetClass() == "gmod_wire_egp" or Ent:GetClass() == "gmod_wire_egp_hud" or Ent:GetClass() == "gmod_wire_egp_emitter")) + return IsValid( Ent ) and (Ent:GetClass() == "gmod_wire_egp" or Ent:GetClass() == "gmod_wire_egp_hud" or Ent:GetClass() == "gmod_wire_egp_emitter") end @@ -473,8 +464,8 @@ function EGP:EGPCursor( this, ply ) return ReturnFailure( this ) end -function EGP.WorldToLocal(egp, object, x, y) - local _, realpos = EGP:GetGlobalPos(egp, object.index) +function EGP.WorldToLocal(object, x, y) + local _, realpos = EGP:GetGlobalPos(object.EGP, object) x, y = x - realpos.x, y - realpos.y local theta = math.rad(realpos.angle) @@ -496,9 +487,9 @@ function EGP.Draw(ent) for _, obj in ipairs(rt) do if obj.parent == -1 or obj.NeedsConstantUpdate then ent.NeedsUpdate = true end if obj.parent ~= 0 then - if not obj.IsParented then EGP:SetParent(ent, obj.index, obj.parent) end - local _, data = EGP:GetGlobalPos(ent, obj.index) - EGP:EditObject(obj, data) + if not obj.IsParented then EGP:SetParent(ent, obj, obj.parent) end + local _, data = EGP.GetGlobalPos(ent, obj) + obj:SetPos(data.x, data.y, data.angle) elseif obj.IsParented then EGP:UnParent(ent, obj) end diff --git a/lua/entities/gmod_wire_egp/lib/objects/3dtracker.lua b/lua/entities/gmod_wire_egp/lib/objects/3dtracker.lua index 84c07fbe75..2d6478368a 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/3dtracker.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/3dtracker.lua @@ -2,8 +2,6 @@ local Obj = EGP:NewObject( "3DTracker" ) Obj.material = nil Obj.filtering = nil -Obj.w = nil -Obj.h = nil Obj.target_x = 0 Obj.target_y = 0 Obj.target_z = 0 @@ -13,7 +11,6 @@ Obj.b = nil Obj.a = nil Obj.parententity = NULL Obj.NeedsConstantUpdate = true -Obj.angle = 0 Obj.directionality = 0 function Obj:Draw(egp) @@ -91,7 +88,7 @@ function Obj:Transmit() net.WriteFloat( self.target_y ) net.WriteFloat( self.target_z ) net.WriteEntity( self.parententity ) - net.WriteInt((self.angle%360)*64, 16) + net.WriteInt(self.angle * 64, 16) net.WriteInt( self.directionality, 2 ) end @@ -110,3 +107,5 @@ end function Obj:DataStreamInfo() return { target_x = self.target_x, target_y = self.target_y, target_z = self.target_z, parententity = self.parententity, directionality = self.directionality } end + +return Obj \ No newline at end of file diff --git a/lua/entities/gmod_wire_egp/lib/objects/box.lua b/lua/entities/gmod_wire_egp/lib/objects/box.lua index 26837d01c3..d4a7815e3d 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/box.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/box.lua @@ -1,35 +1,44 @@ -- Author: Divran local Obj = EGP:NewObject( "Box" ) -Obj.angle = 0 Obj.CanTopLeft = true +Obj.w = 0 +Obj.h = 0 + +local base = Obj.BaseClass + Obj.Draw = function( self ) if (self.a>0) then surface.SetDrawColor( self.r, self.g, self.b, self.a ) surface.DrawTexturedRectRotated( self.x, self.y, self.w, self.h, self.angle ) end end + Obj.Transmit = function( self ) - net.WriteInt((self.angle%360)*20, 16) - self.BaseClass.Transmit( self ) + EGP.SendSize(self) + base.Transmit(self) end + Obj.Receive = function( self ) - local tbl = {} - tbl.angle = net.ReadInt(16)/20 - table.Merge( tbl, self.BaseClass.Receive( self ) ) + tbl = {} + EGP.ReceiveSize(tbl) + table.Merge(tbl, base.Receive(self)) return tbl end -Obj.DataStreamInfo = function( self ) - local tbl = {} - table.Merge( tbl, self.BaseClass.DataStreamInfo( self ) ) - table.Merge( tbl, { angle = self.angle } ) + +function Obj:DataStreamInfo() + local tbl = { w = self.w, h = self.h } + table.Merge(tbl, base.DataStreamInfo(self)) return tbl end -function Obj:Contains(egp, x, y) - x, y = EGP.WorldToLocal(egp, self, x, y) + +function Obj:Contains(x, y) + x, y = EGP.WorldToLocal(self, x, y) local w, h = self.w / 2, self.h / 2 - if egp.TopLeft then x, y = x - w, y - h end + if self.EGP.TopLeft then x, y = x - w, y - h end return -w <= x and x <= w and -h <= y and y <= h end + +return Obj \ No newline at end of file diff --git a/lua/entities/gmod_wire_egp/lib/objects/boxoutline.lua b/lua/entities/gmod_wire_egp/lib/objects/boxoutline.lua index 2eac0a8d66..cee45e7c2b 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/boxoutline.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/boxoutline.lua @@ -1,8 +1,9 @@ -- Author: Divran -local Obj = EGP:NewObject( "BoxOutline" ) +local Obj = EGP.ObjectInherit("BoxOutline", "Box") Obj.size = 1 -Obj.angle = 0 -Obj.CanTopLeft = true + +local base = Obj.BaseClass + local function rotate( x, y, a ) local a = a * math.pi / 180 local _x = math.cos(a) * x - math.sin(a) * y @@ -49,20 +50,19 @@ end Obj.Transmit = function( self ) net.WriteInt( self.size, 16 ) - net.WriteInt( (self.angle%360)*20, 16 ) - self.BaseClass.Transmit( self ) + base.Transmit(self) end + Obj.Receive = function( self ) - local tbl = {} - tbl.size = net.ReadInt(16) - tbl.angle = net.ReadInt(16)/20 - table.Merge( tbl, self.BaseClass.Receive( self ) ) + local tbl = { size = net.ReadInt(16) } + table.Merge(tbl, base.Receive(self)) return tbl end + Obj.DataStreamInfo = function( self ) - local tbl = {} - tbl.size = self.size - tbl.angle = self.angle - table.Merge( tbl, self.BaseClass.DataStreamInfo( self ) ) + local tbl = { size = self.size } + table.Merge(tbl, base.DataStreamInfo(self)) return tbl end + +return Obj diff --git a/lua/entities/gmod_wire_egp/lib/objects/circle.lua b/lua/entities/gmod_wire_egp/lib/objects/circle.lua index da3a1b6ffa..5227605c7c 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/circle.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/circle.lua @@ -1,7 +1,10 @@ -- Author: Divran -local Obj = EGP:NewObject( "Circle" ) +local Obj = EGP.ObjectInherit("Circle", "Box") Obj.angle = 0 Obj.fidelity = 180 + +local base = Obj.BaseClass + local cos, sin, rad, floor = math.cos, math.sin, math.rad, math.floor Obj.Draw = function( self ) if (self.a>0 and self.w > 0 and self.h > 0) then @@ -30,27 +33,31 @@ Obj.Draw = function( self ) surface.DrawPoly( self.vert_cache.verts ) end end -Obj.Transmit = function( self ) - net.WriteInt( (self.angle%360)*20, 16 ) - net.WriteUInt( self.fidelity, 8 ) - self.BaseClass.Transmit( self ) + +Obj.Transmit = function(self) + if not self then self = this end + net.WriteUInt(self.fidelity, 8) + base.Transmit(self) end + Obj.Receive = function( self ) local tbl = {} - tbl.angle = net.ReadInt(16)/20 tbl.fidelity = net.ReadUInt(8) - table.Merge( tbl, self.BaseClass.Receive( self ) ) + table.Merge(tbl, base.Receive(self)) return tbl end + Obj.DataStreamInfo = function( self ) - local tbl = {} - table.Merge( tbl, self.BaseClass.DataStreamInfo( self ) ) - table.Merge( tbl, { angle = self.angle, fidelity = self.fidelity } ) + local tbl = { fidelity = self.fidelity } + table.Merge(tbl, base.DataStreamInfo(self)) return tbl end -function Obj:Contains(egp, x, y) + +function Obj:Contains(x, y) -- Just do this directly since angle doesn't affect circles - local _, realpos = EGP:GetGlobalPos(egp, self.index) + local _, realpos = EGP:GetGlobalPos(self.EGP, self) x, y = (x - realpos.x) / self.w, (y - realpos.y) / self.h return x * x + y * y <= 1 end + +return Obj \ No newline at end of file diff --git a/lua/entities/gmod_wire_egp/lib/objects/circleoutline.lua b/lua/entities/gmod_wire_egp/lib/objects/circleoutline.lua index c0620b760b..1e0e70f7b8 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/circleoutline.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/circleoutline.lua @@ -1,8 +1,9 @@ -- Author: Divran -local Obj = EGP:NewObject( "CircleOutline" ) -Obj.angle = 0 +local Obj = EGP.ObjectInherit("CircleOutline", "Circle") Obj.size = 1 -Obj.fidelity = 180 + +local base = Obj.BaseClass + local cos, sin, rad = math.cos, math.sin, math.rad Obj.Draw = function( self ) if (self.a>0 and self.w > 0 and self.h > 0) then @@ -28,23 +29,24 @@ Obj.Draw = function( self ) EGP:DrawPath(self.vert_cache.verts, self.size, true) end end + Obj.Transmit = function( self ) - net.WriteInt( (self.angle%360)*20, 16 ) - net.WriteInt( self.size, 16 ) - net.WriteUInt(self.fidelity, 8) - self.BaseClass.Transmit( self ) + net.WriteInt(self.size, 16) + base.Transmit(self) end + Obj.Receive = function( self ) local tbl = {} - tbl.angle = net.ReadInt(16)/20 tbl.size = net.ReadInt(16) - tbl.fidelity = net.ReadUInt(8) - table.Merge( tbl, self.BaseClass.Receive( self ) ) + table.Merge(tbl, base.Receive( self)) return tbl end + Obj.DataStreamInfo = function( self ) local tbl = {} - table.Merge( tbl, self.BaseClass.DataStreamInfo( self ) ) - table.Merge( tbl, { angle = self.angle, size = self.size, fidelity = self.fidelity } ) + tbl.size = self.size + table.Merge(tbl, base.DataStreamInfo(self)) return tbl end + +return Obj \ No newline at end of file diff --git a/lua/entities/gmod_wire_egp/lib/objects/line.lua b/lua/entities/gmod_wire_egp/lib/objects/line.lua index f4258b62e8..365c9320c7 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/line.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/line.lua @@ -1,12 +1,12 @@ -- Author: Divran local Obj = EGP:NewObject( "Line" ) -Obj.w = nil -Obj.h = nil +Obj.material = nil Obj.filtering = nil Obj.x2 = 0 Obj.y2 = 0 Obj.size = 1 Obj.verticesindex = { { "x", "y" }, { "x2", "y2" } } + Obj.Draw = function( self ) if (self.a>0) then surface.SetDrawColor( self.r, self.g, self.b, self.a ) @@ -14,27 +14,65 @@ Obj.Draw = function( self ) end end Obj.Transmit = function( self ) - net.WriteInt( self.x, 16 ) - net.WriteInt( self.y, 16 ) + EGP.SendPosAng(self) net.WriteInt( self.x2, 16 ) net.WriteInt( self.y2, 16 ) net.WriteInt( self.size, 16 ) net.WriteInt( self.parent, 16 ) - EGP:SendMaterial( self ) EGP:SendColor( self ) end Obj.Receive = function( self ) local tbl = {} - tbl.x = net.ReadInt(16) - tbl.y = net.ReadInt(16) + EGP.ReceivePosAng(tbl) tbl.x2 = net.ReadInt(16) tbl.y2 = net.ReadInt(16) tbl.size = net.ReadInt(16) tbl.parent = net.ReadInt(16) - EGP:ReceiveMaterial( tbl ) EGP:ReceiveColor( tbl, self ) return tbl end Obj.DataStreamInfo = function( self ) - return { x = self.x, y = self.y, x2 = self.x2, y2 = self.y2, r = self.r, g = self.g, b = self.b, a = self.a, size = self.size, parent = self.parent } + return { x = self.x, y = self.y, x2 = self.x2, y2 = self.y2, angle = self.angle, r = self.r, g = self.g, b = self.b, a = self.a, size = self.size, parent = self.parent } end + +function Obj:EditObject(args) + local ret = false + if args.x or args.y or args.angle or args.x2 or args.y2 then + ret = self:SetPos(args.x or self.x, args.y or self.y, args.angle or self.angle, args.x2 or self.x2, args.y2 or self.y2) + args.x = nil + args.x2 = nil + args.y = nil + args.y2 = nil + args.angle = nil + if args._x then args._x, args._x2, args._y, args._y2, args._angle = nil, nil, nil, nil, nil end + end + for k, v in pairs(args) do + if self[k] ~= nil and self[k] ~= v then + self[k] = v + ret = true + end + end + return ret +end + +function Obj:SetPos(x, y, angle, x2, y2) + local sx, sx2, sy, sy2, sa = self.x, self.x2, self.y, self.y2, self.angle + if not angle then angle = sa end + if sx == x and sy == y and sa == angle and sx2 == x2 and sy2 == y2 then return false end + local vec + if not (x2 or y2) then + x2 = x2 or sx2 + y2 = y2 or sy2 + vec = LocalToWorld(Vector(sx2 - sx, sy2 - sy, 0), angle_zero, Vector(x, y, 0), Angle(0, sa - angle, 0)) + self.x2, self.y2 = vec.x, vec.y + else + self.x2, self.y2 = x2, y2 + end + + self.x, self.y, self.angle = x, y, angle + + if self._x then self._x, self._y, self._angle, self._x2, self._y2 = x, y, angle, x2, y2 end + return true +end + +return Obj \ No newline at end of file diff --git a/lua/entities/gmod_wire_egp/lib/objects/linestrip.lua b/lua/entities/gmod_wire_egp/lib/objects/linestrip.lua index 580791fd80..02102fd448 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/linestrip.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/linestrip.lua @@ -1,13 +1,6 @@ -- Author: sk8 (& Divran) -local Obj = EGP:NewObject( "LineStrip" ) -Obj.w = nil -Obj.h = nil -Obj.x = nil -Obj.y = nil -Obj.filtering = nil -Obj.vertices = {} -Obj.verticesindex = "vertices" -Obj.size = 1 +local Obj = EGP.ObjectInherit("LineStrip", "PolyOutline") + Obj.Draw = function( self ) local n = #self.vertices if (self.a>0 and n>0 and self.size>0) then @@ -16,29 +9,5 @@ Obj.Draw = function( self ) EGP:DrawPath(self.vertices, self.size, false) end end -Obj.Transmit = function( self, Ent, ply ) - net.WriteUInt( #self.vertices, 16 ) - for i=1,#self.vertices do - net.WriteInt( self.vertices[i].x, 16 ) - net.WriteInt( self.vertices[i].y, 16 ) - end - net.WriteInt(self.parent, 16) - net.WriteInt(self.size, 16) - EGP:SendMaterial( self ) - EGP:SendColor( self ) -end -Obj.Receive = function( self ) - local tbl = {} - tbl.vertices = {} - for i=1,net.ReadUInt(16) do - tbl.vertices[ i ] = { x = net.ReadInt(16), y = net.ReadInt(16) } - end - tbl.parent = net.ReadInt(16) - tbl.size = net.ReadInt(16) - EGP:ReceiveMaterial( tbl ) - EGP:ReceiveColor( tbl, self ) - return tbl -end -Obj.DataStreamInfo = function( self ) - return { vertices = self.vertices, material = self.material, r = self.r, g = self.g, b = self.b, a = self.a, parent = self.parent } -end + +return Obj \ No newline at end of file diff --git a/lua/entities/gmod_wire_egp/lib/objects/poly.lua b/lua/entities/gmod_wire_egp/lib/objects/poly.lua index e0a2355dd2..222dfd99a7 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/poly.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/poly.lua @@ -1,12 +1,11 @@ -- Author: Divran -local Obj = EGP:NewObject( "Poly" ) -Obj.w = nil -Obj.h = nil -Obj.x = nil -Obj.y = nil +local Obj = EGP:NewObject("Poly") Obj.vertices = {} Obj.verticesindex = "vertices" Obj.HasUV = true +if SERVER then Obj.VerticesUpdate = true end + +local base = Obj.BaseClass -- Returns whether c is to the left of the line from a to b. local function counterclockwise( a, b, c ) @@ -23,44 +22,45 @@ Obj.Draw = function( self ) end end Obj.Transmit = function( self, Ent, ply ) - if (#self.vertices <= 28) then - net.WriteUInt( #self.vertices, 8 ) - for i=1,#self.vertices do - net.WriteInt( self.vertices[i].x, 16 ) - net.WriteInt( self.vertices[i].y, 16 ) - net.WriteFloat( self.vertices[i].u or 0 ) - net.WriteFloat( self.vertices[i].v or 0 ) + net.WriteBool(self.VerticesUpdate) + if self.VerticesUpdate then + if (#self.vertices <= 255) then + net.WriteUInt( #self.vertices, 8 ) + for i=1,#self.vertices do + net.WriteInt( self.vertices[i].x, 16 ) + net.WriteInt( self.vertices[i].y, 16 ) + net.WriteFloat( self.vertices[i].u or 0 ) + net.WriteFloat( self.vertices[i].v or 0 ) + end + self.VerticesUpdate = false + else + net.WriteUInt( 0, 8 ) + EGP:InsertQueue( Ent, ply, EGP._SetVertex, "SetVertex", self.index, self.vertices ) end - else - net.WriteUInt( 0, 8 ) - EGP:InsertQueue( Ent, ply, EGP._SetVertex, "SetVertex", self.index, self.vertices ) end - net.WriteUInt(math.Clamp(self.filtering,0,3), 2) - net.WriteInt( self.parent, 16 ) - EGP:SendMaterial( self ) - EGP:SendColor( self ) + base.Transmit(self) end + Obj.Receive = function( self ) local tbl = {} - tbl.vertices = {} - for i = 1, net.ReadUInt(8) do - tbl.vertices[ i ] = { x = net.ReadInt(16), y = net.ReadInt(16), u = net.ReadFloat(), v = net.ReadFloat() } + if net.ReadBool() then + tbl.vertices = {} + for i = 1, net.ReadUInt(8) do + tbl.vertices[ i ] = { x = net.ReadInt(16), y = net.ReadInt(16), u = net.ReadFloat(), v = net.ReadFloat() } + end end - tbl.filtering = net.ReadUInt(2) - tbl.parent = net.ReadInt(16) - EGP:ReceiveMaterial( tbl ) - EGP:ReceiveColor( tbl, self ) + table.Merge(tbl, base.Receive(self)) return tbl end Obj.DataStreamInfo = function( self ) - return { vertices = self.vertices, material = self.material, r = self.r, g = self.g, b = self.b, a = self.a, filtering = self.filtering, parent = self.parent } + return { material = self.material, r = self.r, g = self.g, b = self.b, a = self.a, filtering = self.filtering, parent = self.parent, x = self.x, y = self.y, angle = self.angle } end -function Obj:Contains(egp, x, y) +function Obj:Contains(x, y) if #self.vertices < 3 then return false end -- Convert into {x,y} format that poly uses. local point = { x = x, y = y } - local _, realpos = EGP:GetGlobalPos(egp, self.index) + local _, realpos = EGP:GetGlobalPos(self.EGP, self) local vertices = realpos.vertices -- To check whether a point is in the polygon, we check whether it's to the @@ -79,3 +79,79 @@ function Obj:Contains(egp, x, y) end return inside(vertices[#vertices], vertices[1], point) end + +function Obj:EditObject(args) + local ret = false + if args.vertices then + self.vertices = args.vertices + if self.IsParented then + self._x, self._y = EGP.getCenterFrom(self) + else + self.x, self.y = EGP.getCenterFrom(self) + end + args.vertices = nil + self.angle = 0 + if SERVER then self.VerticesUpdate = true end + ret = true + end + if args.x or args.y or args.angle then + ret = self:SetPos(args.x or self.x, args.y or self.y, args.angle or self.angle) + args.x = nil + args.y = nil + args.angle = nil + if self._x then args._x, args._y, args._angle = nil, nil, nil end + end + for k, v in pairs(args) do + if self[k] ~= nil and self[k] ~= v then + self[k] = v + ret = true + end + end + return ret +end + +Obj.Initialize = Obj.EditObject + +function Obj:SetPos(x, y, angle) + local sx, sy, sa = self.x, self.y, self.angle + if not x then x = sx end + if not y then y = sy end + if not angle then angle = sa else angle = angle % 360 end + if sx == x and sy == y and sa == angle then return false end + + for i, v in ipairs(self.vertices) do + local vec = LocalToWorld(Vector(v.x - sx, v.y - sy, 0), angle_zero, Vector(x, y, 0), Angle(0, sa - angle, 0)) + v.x = vec.x + v.y = vec.y + end + self.x, self.y, self.angle = x, y, angle + if self._x then self._x, self._y, self._angle = x, y, angle end + return true +end + +function Obj:Set(key, value) + if key == "vertices" then + self.vertices = value + self.x, self.y = EGP.getCenterFrom(self) + self.angle = 0 + if SERVER then self.VerticesUpdate = true end + return true + elseif key == "x" then + ret = self:SetPos(value, self.y, self.angle) + return true + elseif key == "y" then + ret = self:SetPos(self.x, value, self.angle) + return true + elseif key == "angle" then + ret = self:SetPos(self.x, self.y, value) + return true + else + if self[key] ~= nil and self[key] ~= value then + self[key] = value + return true + end + end + return false +end + +return Obj \ No newline at end of file diff --git a/lua/entities/gmod_wire_egp/lib/objects/polyoutline.lua b/lua/entities/gmod_wire_egp/lib/objects/polyoutline.lua index d894410f94..d59d7622f0 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/polyoutline.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/polyoutline.lua @@ -1,13 +1,10 @@ -- Author: sk8 (& Divran) -local Obj = EGP:NewObject( "PolyOutline" ) -Obj.w = nil -Obj.h = nil -Obj.x = nil -Obj.y = nil -Obj.filtering = nil -Obj.vertices = {} -Obj.verticesindex = "vertices" +local Obj = EGP.ObjectInherit("PolyOutline", "Poly") Obj.size = 1 +Obj.HasUV = nil + +local base = Obj.BaseClass + Obj.Draw = function( self ) local n = #self.vertices if (self.a>0 and n>0 and self.size>0) then @@ -15,29 +12,22 @@ Obj.Draw = function( self ) EGP:DrawPath(self.vertices, self.size, true) end end + Obj.Transmit = function( self, Ent, ply ) - net.WriteUInt( #self.vertices, 16 ) - for i=1,#self.vertices do - net.WriteInt( self.vertices[i].x, 16 ) - net.WriteInt( self.vertices[i].y, 16 ) - end - net.WriteInt(self.parent, 16) net.WriteInt(self.size, 16) - EGP:SendMaterial( self ) - EGP:SendColor( self ) + base.Transmit(self) end + Obj.Receive = function( self ) - local tbl = {} - tbl.vertices = {} - for i=1,net.ReadUInt(16) do - tbl.vertices[ i ] = { x = net.ReadInt(16), y = net.ReadInt(16) } - end - tbl.parent = net.ReadInt(16) - tbl.size = net.ReadInt(16) - EGP:ReceiveMaterial( tbl ) - EGP:ReceiveColor( tbl, self ) + local tbl = { size = net.ReadInt(16) } + table.Merge(tbl, base.Receive(self)) return tbl end + Obj.DataStreamInfo = function( self ) - return { vertices = self.vertices, material = self.material, r = self.r, g = self.g, b = self.b, a = self.a, parent = self.parent } + return table.Merge({ size = self.size }, base.DataStreamInfo(self)) end + +Obj.Contains = EGP.Objects.Base.Contains + +return Obj \ No newline at end of file diff --git a/lua/entities/gmod_wire_egp/lib/objects/roundedbox.lua b/lua/entities/gmod_wire_egp/lib/objects/roundedbox.lua index 0c1c10f1e2..9f666b88d7 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/roundedbox.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/roundedbox.lua @@ -1,64 +1,68 @@ -- Author: sk8 (& Divran) -local Obj = EGP:NewObject( "RoundedBox" ) -Obj.angle = 0 +local Obj = EGP.ObjectInherit("RoundedBox", "Box") Obj.radius = 16 -Obj.CanTopLeft = true Obj.fidelity = 36 -Obj.Draw = function( self ) - if EGP:CacheNeedsUpdate(self, {"x", "y", "w", "h", "angle", "fidelity", "radius"}) then - local xs,ys , sx,sy = self.x,self.y , self.w, self.h - local polys = {} - local source = { {x=-1,y=-1} , {x=1,y=-1} , {x=1,y=1} , {x=-1,y=1} } - local radius = math.max(0,math.min((math.min(sx,sy)/2), self.radius )) - local div,angle = 360/self.fidelity, -self.angle - for x=1,4 do - for i=0,(self.fidelity+1)/4 do - local srx,sry = source[x].x,source[x].y - local scx,scy = srx*(sx-(radius*2))/2 , sry*(sy-(radius*2))/2 - scx,scy = scx*math.cos(math.rad(angle)) - scy*math.sin(math.rad(angle)), - scx*math.sin(math.rad(angle)) + scy*math.cos(math.rad(angle)) - local a,r = math.rad(div*i+(x*90)), radius - local dir = {x=math.sin(-(a+math.rad(angle))),y=math.cos(-(a+math.rad(angle)))} - local dirUV = {x=math.sin(-a),y=math.cos(-a)} - local ru,rv = (radius/sx),(radius/sy) - local u,v = 0.5 + (dirUV.x*ru) + (srx/2)*(1-(ru*2)), - 0.5 + (dirUV.y*rv) + (sry/2)*(1-(rv*2)) - polys[#polys+1] = {x=xs+scx+(dir.x*r), y=ys+scy+(dir.y*r) , u=u,v=v} + +local base = Obj.BaseClass +local max, min, sin, cos, rad = math.max, math.min, math.sin, math.cos, math.rad + +function Obj:Calculate() + if EGP:CacheNeedsUpdate(self, {"x", "y", "w", "h", "angle", "fidelity", "radius"}) then + local xs,ys , sx,sy = self.x,self.y , self.w, self.h + local polys = {} + local source = { {x=-1,y=-1} , {x=1,y=-1} , {x=1,y=1} , {x=-1,y=1} } + local radius = max(0, min(min(sx, sy) / 2, self.radius)) + local div, angle = 360/self.fidelity, rad(-self.angle) + for x=1,4 do + for i = 0, (self.fidelity + 1) / 4 do + local srx,sry = source[x].x,source[x].y + local scx,scy = srx*(sx-(radius*2))/2 , sry*(sy-(radius*2))/2 + scx,scy = scx * cos(angle) - scy * sin(angle), + scx * sin(angle) + scy * cos(angle) + local a, r = rad(div*i+(x*90)), radius + local dir = {x = sin(-(a + angle)),y = cos(-(a + angle))} + local dirUV = {x = sin(-a),y = cos(-a)} + local ru,rv = (radius/sx), (radius/sy) + local u,v = 0.5 + (dirUV.x*ru) + (srx/2)*(1-(ru*2)), + 0.5 + (dirUV.y*rv) + (sry/2)*(1-(rv*2)) + polys[#polys+1] = {x=xs+scx+(dir.x*r), y=ys+scy+(dir.y*r) , u=u,v=v} end end self.vert_cache.verts = polys end +end + +Obj.Draw = function( self ) + self:Calculate() surface.SetDrawColor(self.r,self.g,self.b,self.a) surface.DrawPoly(self.vert_cache.verts) end Obj.Transmit = function( self ) - net.WriteInt((self.angle%360)*20, 16) net.WriteInt(self.radius, 16) net.WriteUInt(self.fidelity, 8) - self.BaseClass.Transmit( self ) + base.Transmit(self) end Obj.Receive = function( self ) local tbl = {} - tbl.angle = net.ReadInt(16)/20 tbl.radius = net.ReadInt(16) tbl.fidelity = net.ReadUInt(8) - table.Merge( tbl, self.BaseClass.Receive( self ) ) + table.Merge(tbl, base.Receive(self)) return tbl end Obj.DataStreamInfo = function( self ) local tbl = {} - table.Merge( tbl, self.BaseClass.DataStreamInfo( self ) ) - table.Merge( tbl, { angle = self.angle, radius = self.radius, fidelity = self.fidelity } ) + table.Merge( tbl, base.DataStreamInfo( self ) ) + table.Merge( tbl, { radius = self.radius, fidelity = self.fidelity } ) return tbl end -function Obj:Contains(egp, x, y) - x, y = EGP.WorldToLocal(egp, self, x, y) +function Obj:Contains(x, y) + x, y = EGP.WorldToLocal(self, x, y) local w, h = self.w / 2, self.h / 2 - if egp.TopLeft then x, y = x - w, y - h end + if self.EGP.TopLeft then x, y = x - w, y - h end - local r = math.min(math.min(w, h), self.radius) + local r = min(min(w, h), self.radius) x, y = math.abs(x), math.abs(y) if x > w or y > h then return false end x, y = x - w + r, y - h + r @@ -66,3 +70,5 @@ function Obj:Contains(egp, x, y) x, y = x / h, y / h return x * x + y * y <= 1 end + +return Obj \ No newline at end of file diff --git a/lua/entities/gmod_wire_egp/lib/objects/roundedboxoutline.lua b/lua/entities/gmod_wire_egp/lib/objects/roundedboxoutline.lua index 5919657569..e73eda9bba 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/roundedboxoutline.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/roundedboxoutline.lua @@ -1,52 +1,32 @@ -- Author: sk8 (& Divran) -local Obj = EGP:NewObject( "RoundedBoxOutline" ) -Obj.angle = 0 -Obj.radius = 16 +local Obj = EGP.ObjectInherit("RoundedBoxOutline", "RoundedBox") Obj.size = 1 -Obj.CanTopLeft = true -Obj.fidelity = 36 +Obj.filtering = nil + +local base = Obj.BaseClass + Obj.Draw = function( self ) - if EGP:CacheNeedsUpdate(self, {"x", "y", "w", "h", "angle", "fidelity", "radius"}) then - local xs,ys , sx,sy = self.x,self.y , self.w, self.h - local polys = {} - local source = { {x=-1,y=-1} , {x=1,y=-1} , {x=1,y=1} , {x=-1,y=1} } - local radius = math.max(0,math.min((math.min(sx,sy)/2), self.radius )) - local div,angle = 360/self.fidelity, -self.angle - for x=1,4 do - for i=0,(self.fidelity+1)/4 do - local srx,sry = source[x].x,source[x].y - local scx,scy = srx*(sx-(radius*2))/2 , sry*(sy-(radius*2))/2 - scx,scy = scx*math.cos(math.rad(angle)) - scy*math.sin(math.rad(angle)), - scx*math.sin(math.rad(angle)) + scy*math.cos(math.rad(angle)) - local a,r = math.rad(div*i+(x*90)), radius - local dir = {x=math.sin(-(a+math.rad(angle))),y=math.cos(-(a+math.rad(angle)))} - polys[#polys+1] = {x=xs+scx+(dir.x*r), y=ys+scy+(dir.y*r)} - end - end - self.vert_cache.verts = polys - end + self:Calculate() + surface.SetDrawColor(self.r,self.g,self.b,self.a) EGP:DrawPath(self.vert_cache.verts, self.size, true) end Obj.Transmit = function( self ) - net.WriteInt((self.angle%360)*20, 16) - net.WriteInt(self.radius, 16) net.WriteInt(self.size, 16) - net.WriteUInt(self.fidelity, 8) - self.BaseClass.Transmit( self ) + base.Transmit(self) end Obj.Receive = function( self ) local tbl = {} - tbl.angle = net.ReadInt(16)/20 - tbl.radius = net.ReadInt(16) tbl.size = net.ReadInt(16) - tbl.fidelity = net.ReadUInt(8) - table.Merge( tbl, self.BaseClass.Receive( self ) ) + table.Merge(tbl, base.Receive(self)) return tbl end Obj.DataStreamInfo = function( self ) - local tbl = {} - table.Merge( tbl, self.BaseClass.DataStreamInfo( self ) ) - table.Merge( tbl, { angle = self.angle, radius = self.radius, fidelity = self.fidelity } ) + local tbl = { size = self.size } + table.Merge(tbl, base.DataStreamInfo(self)) return tbl end + +Obj.Contains = nil + +return Obj \ No newline at end of file diff --git a/lua/entities/gmod_wire_egp/lib/objects/text.lua b/lua/entities/gmod_wire_egp/lib/objects/text.lua index 5a7d1ff34b..155a26131f 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/text.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/text.lua @@ -1,13 +1,11 @@ -- Author: Divran local Obj = EGP:NewObject( "Text" ) -Obj.h = nil -Obj.w = nil +Obj.material = nil Obj.text = "" Obj.font = "WireGPU_ConsoleFont" Obj.size = 18 Obj.valign = 0 Obj.halign = 0 -Obj.angle = 0 local surface_SetTextPos local surface_DrawText @@ -98,30 +96,36 @@ function Obj:Draw(ent, drawMat) end end Obj.Transmit = function( self, Ent, ply ) - net.WriteInt( self.x, 16 ) - net.WriteInt( self.y, 16 ) - EGP:InsertQueue( Ent, ply, EGP._SetText, "SetText", self.index, self.text ) + EGP.SendPosAng(self) + local len = #self.text + if len <= 1024 then + net.WriteUInt(len, 11) + net.WriteData(self.text, len) + else + net.WriteUInt(0, 11) + EGP:InsertQueue(Ent, ply, EGP._SetText, "SetText", self.index, self.text) + end net.WriteString(self.font) - net.WriteUInt(math.Clamp(self.size,0,256), 8) + net.WriteUInt(math.Clamp(self.size, 0, 255), 8) net.WriteUInt(math.Clamp(self.valign,0,2), 2) net.WriteUInt(math.Clamp(self.halign,0,2), 2) - net.WriteInt( self.parent, 16 ) - EGP:SendColor( self ) - net.WriteInt((self.angle%360)*20, 16) + net.WriteInt(self.parent, 16) + EGP:SendColor(self) end Obj.Receive = function( self ) local tbl = {} - tbl.x = net.ReadInt(16) - tbl.y = net.ReadInt(16) + EGP.ReceivePosAng(tbl) + local len = net.ReadUInt(11) + local text = net.ReadData(len) + tbl.text = #text > 0 and text or nil tbl.font = net.ReadString() tbl.size = net.ReadUInt(8) tbl.valign = net.ReadUInt(2) tbl.halign = net.ReadUInt(2) tbl.parent = net.ReadInt(16) EGP:ReceiveColor( tbl, self ) - tbl.angle = net.ReadInt(16)/20 return tbl end Obj.DataStreamInfo = function( self ) - return { x = self.x, y = self.y, valign = self.valign, halign = self.halign, size = self.size, r = self.r, g = self.g, b = self.b, a = self.a, text = self.text, font = self.font, parent = self.parent, angle = self.angle } + return { x = self.x, y = self.y, angle = self.angle, valign = self.valign, halign = self.halign, size = self.size, r = self.r, g = self.g, b = self.b, a = self.a, text = self.text, font = self.font, parent = self.parent } end diff --git a/lua/entities/gmod_wire_egp/lib/objects/textlayout.lua b/lua/entities/gmod_wire_egp/lib/objects/textlayout.lua index d9d183a586..1d0b0656ae 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/textlayout.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/textlayout.lua @@ -1,13 +1,9 @@ -- Author: Divran -local Obj = EGP:NewObject( "TextLayout" ) +local Obj = EGP.ObjectInherit("TextLayout", "Text") Obj.h = 512 Obj.w = 512 -Obj.text = "" -Obj.font = "WireGPU_ConsoleFont" -Obj.size = 18 -Obj.valign = 0 -Obj.halign = 0 -Obj.angle = 0 + +local base = Obj.BaseClass local cam_PushModelMatrix local cam_PopModelMatrix @@ -93,28 +89,14 @@ function Obj:Draw(ent, drawMat) end end Obj.Transmit = function( self, Ent, ply ) - EGP:SendPosSize( self ) - EGP:InsertQueue( Ent, ply, EGP._SetText, "SetText", self.index, self.text ) - net.WriteString(self.font) - net.WriteUInt(math.Clamp(self.size,0,256), 8) - net.WriteUInt(math.Clamp(self.valign,0,2), 2) - net.WriteUInt(math.Clamp(self.halign,0,2), 2) - net.WriteInt( self.parent, 16 ) - EGP:SendColor( self ) - net.WriteInt((self.angle%360)*20, 16) + EGP.SendSize(self) + base.Transmit(self) end Obj.Receive = function( self ) local tbl = {} - EGP:ReceivePosSize( tbl ) - tbl.font = net.ReadString(8) - tbl.size = net.ReadUInt(8) - tbl.valign = net.ReadUInt(2) - tbl.halign = net.ReadUInt(2) - tbl.parent = net.ReadInt(16) - EGP:ReceiveColor( tbl, self ) - tbl.angle = net.ReadInt(16)/20 - return tbl + EGP.ReceiveSize(tbl) + return table.Merge(tbl, base.Receive(self)) end Obj.DataStreamInfo = function( self ) - return { x = self.x, y = self.y, w = self.w, h = self.h, valign = self.valign, halign = self.halign, size = self.size, r = self.r, g = self.g, b = self.b, a = self.a, text = self.text, font = self.font, parent = self.parent, angle = self.angle } + return table.Merge({ w = self.w, h = self.h}, base.DataStreamInfo(self)) end diff --git a/lua/entities/gmod_wire_egp/lib/objects/wedge.lua b/lua/entities/gmod_wire_egp/lib/objects/wedge.lua index d6057435cd..85f86c82f8 100644 --- a/lua/entities/gmod_wire_egp/lib/objects/wedge.lua +++ b/lua/entities/gmod_wire_egp/lib/objects/wedge.lua @@ -54,8 +54,8 @@ Obj.DataStreamInfo = function( self ) table.Merge( tbl, { angle = self.angle, size = self.size, fidelity = self.fidelity } ) return tbl end -function Obj:Contains(egp, x, y) - x, y = EGP.WorldToLocal(egp, self, x, y) +function Obj:Contains(x, y) + x, y = EGP.WorldToLocal(self, x, y) x, y = x / self.w, y / self.h if x * x + y * y > 1 then return false end diff --git a/lua/entities/gmod_wire_egp_emitter.lua b/lua/entities/gmod_wire_egp_emitter.lua index a6e803f509..f0257a0196 100644 --- a/lua/entities/gmod_wire_egp_emitter.lua +++ b/lua/entities/gmod_wire_egp_emitter.lua @@ -93,9 +93,9 @@ if CLIENT then for _, obj in ipairs(rt) do if obj.parent == -1 or obj.NeedsConstantUpdate then self.NeedsUpdate = true end if obj.parent ~= 0 then - if not obj.IsParented then EGP:SetParent(self, obj.index, obj.parent) end - local _, data = EGP:GetGlobalPos(self, obj.index) - EGP:EditObject(obj, data) + if not obj.IsParented then EGP:SetParent(self, obj, obj.parent) end + local _, data = EGP.GetGlobalPos(self, obj) + obj:SetPos(data.x, data.y, data.angle) elseif obj.IsParented then EGP:UnParent(self, obj) end diff --git a/lua/entities/gmod_wire_egp_hud/huddraw.lua b/lua/entities/gmod_wire_egp_hud/huddraw.lua index 00abae75db..7c30c7b2b5 100644 --- a/lua/entities/gmod_wire_egp_hud/huddraw.lua +++ b/lua/entities/gmod_wire_egp_hud/huddraw.lua @@ -39,8 +39,8 @@ if CLIENT then r[i+1] = (r[i+1]- yMin) * yMul end local settings = {} - if isstring(v.verticesindex) then settings = { [v.verticesindex] = makeTable( v, r ) } else settings = makeTable( v, r ) end - EGP:EditObject(v, settings) + if isstring(v.verticesindex) then settings = { [v.verticesindex] = makeTable( v, r ) } else v.vertices = makeTable(v, r) end + v:EditObject(settings) else if v.x then v.x = (v.x - xMin) * xMul diff --git a/lua/entities/gmod_wire_expression2/core/egpfunctions.lua b/lua/entities/gmod_wire_expression2/core/egpfunctions.lua index bdb38bd885..fb20d11951 100644 --- a/lua/entities/gmod_wire_expression2/core/egpfunctions.lua +++ b/lua/entities/gmod_wire_expression2/core/egpfunctions.lua @@ -1,9 +1,10 @@ + +local NULL_EGPOBJECT = EGP.NULL_EGPOBJECT + local function Update(self,this) self.data.EGP.UpdatesNeeded[this] = true end -local getCenterFromPos = EGP.ParentingFuncs.getCenterFromPos - -------------------------------------------------------- -- Frames -------------------------------------------------------- @@ -82,7 +83,7 @@ e2function void wirelink:egpOrder( number index, number order ) end e2function number wirelink:egpOrder( number index ) - if (!EGP:IsAllowed( self, this )) then return end + if (!EGP:IsAllowed( self, this )) then return -1 end local bool, k, v = EGP:HasObject( this, index ) if (bool) then return k @@ -125,32 +126,35 @@ __e2setcost(15) -------------------------------------------------------- -- Box -------------------------------------------------------- -e2function void wirelink:egpBox( number index, vector2 pos, vector2 size ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpBox( number index, vector2 pos, vector2 size ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["Box"], { index = index, w = size[1], h = size[2], x = pos[1], y = pos[2] }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -------------------------------------------------------- -- BoxOutline -------------------------------------------------------- -e2function void wirelink:egpBoxOutline( number index, vector2 pos, vector2 size ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpBoxOutline( number index, vector2 pos, vector2 size ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["BoxOutline"], { index = index, w = size[1], h = size[2], x = pos[1], y = pos[2] }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -------------------------------------------------------- -- RoundedBox -------------------------------------------------------- -e2function void wirelink:egpRoundedBox( number index, vector2 pos, vector2 size ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpRoundedBox( number index, vector2 pos, vector2 size ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["RoundedBox"], { index = index, w = size[1], h = size[2], x = pos[1], y = pos[2] }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end e2function void wirelink:egpRadius( number index, number radius ) - if (!EGP:IsAllowed( self, this )) then return end + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, k, v = EGP:HasObject( this, index ) if (bool) then if (EGP:EditObject( v, { radius = radius } )) then EGP:DoAction( this, self, "SendObject", v ) Update(self,this) end @@ -160,25 +164,28 @@ end -------------------------------------------------------- -- RoundedBoxOutline -------------------------------------------------------- -e2function void wirelink:egpRoundedBoxOutline( number index, vector2 pos, vector2 size ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpRoundedBoxOutline( number index, vector2 pos, vector2 size ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["RoundedBoxOutline"], { index = index, w = size[1], h = size[2], x = pos[1], y = pos[2] }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -------------------------------------------------------- -- Text -------------------------------------------------------- -e2function void wirelink:egpText( number index, string text, vector2 pos ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpText( number index, string text, vector2 pos ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["Text"], { index = index, text = text, x = pos[1], y = pos[2] }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -e2function void wirelink:egpTextLayout( number index, string text, vector2 pos, vector2 size ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpTextLayout( number index, string text, vector2 pos, vector2 size ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["TextLayout"], { index = index, text = text, x = pos[1], y = pos[2], w = size[1], h = size[2] }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end __e2setcost(10) @@ -270,10 +277,10 @@ __e2setcost(20) local function maxvertices() return EGP.ConVars.MaxVertices:GetInt() end -e2function void wirelink:egpPoly( number index, ...args ) - if (!EGP:IsAllowed( self, this )) then return end - if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", nil) end - if #args < 3 then return end -- No less than 3 +e2function egpobject wirelink:egpPoly( number index, ...args ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end + if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", NULL_EGPOBJECT) end + if #args < 3 then return NULL_EGPOBJECT end -- No less than 3 local max = maxvertices() @@ -293,12 +300,13 @@ e2function void wirelink:egpPoly( number index, ...args ) local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["Poly"], { index = index, vertices = vertices }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -e2function void wirelink:egpPoly( number index, array args ) - if (!EGP:IsAllowed( self, this )) then return end - if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", nil) end - if (#args<3) then return end -- No less than 3 +e2function egpobject wirelink:egpPoly( number index, array args ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end + if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", NULL_EGPOBJECT) end + if (#args<3) then return NULL_EGPOBJECT end -- No less than 3 local max = maxvertices() @@ -318,16 +326,17 @@ e2function void wirelink:egpPoly( number index, array args ) local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["Poly"], { index = index, vertices = vertices }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -------------------------------------------------------- -- PolyOutline -------------------------------------------------------- -e2function void wirelink:egpPolyOutline( number index, ...args ) - if (!EGP:IsAllowed( self, this )) then return end - if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", nil) end - if #args < 3 then return end -- No less than 3 +e2function egpobject wirelink:egpPolyOutline( number index, ...args ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end + if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", NULL_EGPOBJECT) end + if #args < 3 then return NULL_EGPOBJECT end -- No less than 3 local max = maxvertices() @@ -347,12 +356,13 @@ e2function void wirelink:egpPolyOutline( number index, ...args ) local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["PolyOutline"], { index = index, vertices = vertices }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -e2function void wirelink:egpPolyOutline( number index, array args ) - if (!EGP:IsAllowed( self, this )) then return end - if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", nil) end - if (#args<3) then return end -- No less than 3 +e2function egpobject wirelink:egpPolyOutline( number index, array args ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end + if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", NULL_EGPOBJECT) end + if (#args<3) then return NULL_EGPOBJECT end -- No less than 3 local max = maxvertices() @@ -372,6 +382,7 @@ e2function void wirelink:egpPolyOutline( number index, array args ) local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["PolyOutline"], { index = index, vertices = vertices }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end e2function void wirelink:egpAddVertices( number index, array args ) @@ -398,7 +409,7 @@ e2function void wirelink:egpAddVertices( number index, array args ) end end - if (EGP:EditObject( v, { vertices = vertices } )) then + if v:EditObject({ vertices = vertices }) then EGP:InsertQueue( this, self.player, EGP._SetVertex, "SetVertex", index, vertices, true ) Update(self,this) end @@ -409,10 +420,10 @@ end -- egpLineStrip (PolyOutline without the final connecting line) -------------------------------------------------------- -e2function void wirelink:egpLineStrip( number index, ...args ) - if (!EGP:IsAllowed( self, this )) then return end - if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", nil) end - if #args < 2 then return end -- No less than 2 +e2function egpobject wirelink:egpLineStrip( number index, ...args ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end + if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", NULL_EGPOBJECT) end + if #args < 2 then return NULL_EGPOBJECT end -- No less than 2 local max = maxvertices() @@ -432,12 +443,13 @@ e2function void wirelink:egpLineStrip( number index, ...args ) local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["LineStrip"], { index = index, vertices = vertices }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -e2function void wirelink:egpLineStrip( number index, array args ) - if (!EGP:IsAllowed( self, this )) then return end - if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", nil) end - if (#args<2) then return end -- No less than 2 +e2function egpobject wirelink:egpLineStrip( number index, array args ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end + if (!EGP:ValidEGP( this )) then return self:throw("Invalid wirelink!", NULL_EGPOBJECT) end + if (#args<2) then return NULL_EGPOBJECT end -- No less than 2 local max = maxvertices() @@ -457,6 +469,7 @@ e2function void wirelink:egpLineStrip( number index, array args ) local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["LineStrip"], { index = index, vertices = vertices }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end __e2setcost(15) @@ -464,62 +477,68 @@ __e2setcost(15) -------------------------------------------------------- -- Line -------------------------------------------------------- -e2function void wirelink:egpLine( number index, vector2 pos1, vector2 pos2 ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpLine( number index, vector2 pos1, vector2 pos2 ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["Line"], { index = index, x = pos1[1], y = pos1[2], x2 = pos2[1], y2 = pos2[2] }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -------------------------------------------------------- -- Circle -------------------------------------------------------- -e2function void wirelink:egpCircle( number index, vector2 pos, vector2 size ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpCircle( number index, vector2 pos, vector2 size ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["Circle"], { index = index, x = pos[1], y = pos[2], w = size[1], h = size[2] }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -------------------------------------------------------- -- Circle Outline -------------------------------------------------------- -e2function void wirelink:egpCircleOutline( number index, vector2 pos, vector2 size ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpCircleOutline( number index, vector2 pos, vector2 size ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["CircleOutline"], { index = index, x = pos[1], y = pos[2], w = size[1], h = size[2] }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -------------------------------------------------------- -- Triangle -------------------------------------------------------- -e2function void wirelink:egpTriangle( number index, vector2 v1, vector2 v2, vector2 v3 ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpTriangle( number index, vector2 v1, vector2 v2, vector2 v3 ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local vertices = { { x = v1[1], y = v1[2] }, { x = v2[1], y = v2[2] }, { x = v3[1], y = v3[2] } } local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["Poly"], { index = index, vertices = vertices }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -------------------------------------------------------- -- Triangle Outline -------------------------------------------------------- -e2function void wirelink:egpTriangleOutline( number index, vector2 v1, vector2 v2, vector2 v3 ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpTriangleOutline( number index, vector2 v1, vector2 v2, vector2 v3 ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local vertices = { { x = v1[1], y = v1[2] }, { x = v2[1], y = v2[2] }, { x = v3[1], y = v3[2] } } local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["PolyOutline"], { index = index, vertices = vertices }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -------------------------------------------------------- -- Wedge -------------------------------------------------------- -e2function void wirelink:egpWedge( number index, vector2 pos, vector2 size ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpWedge( number index, vector2 pos, vector2 size ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["Wedge"], { index = index, x = pos[1], y = pos[2], w = size[1], h = size[2] }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end --[[ I'm sticking to my policy of not spamming pointless functions. e2function void wirelink:egpWedge( number index, vector2 pos, vector2 size, number angle, number mouthsize ) - if (!EGP:IsAllowed( self, this )) then return end + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["Wedge"], { index = index, x = pos[1], y = pos[2], w = size[1], h = size[2], size = mouthsize, angle = angle }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end end @@ -528,15 +547,16 @@ end -------------------------------------------------------- -- Wedge Outline -------------------------------------------------------- -e2function void wirelink:egpWedgeOutline( number index, vector2 pos, vector2 size ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpWedgeOutline( number index, vector2 pos, vector2 size ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["WedgeOutline"], { index = index, x = pos[1], y = pos[2], w = size[1], h = size[2] }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end --[[ I'm sticking to my policy of not spamming pointless functions. e2function void wirelink:egpWedgeOutline( number index, vector2 pos, vector2 size, number angle, number mouthsize ) - if (!EGP:IsAllowed( self, this )) then return end + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["WedgeOutline"], { index = index, x = pos[1], y = pos[2], w = size[1], h = size[2], size = mouthsize, angle = angle }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end end @@ -545,14 +565,15 @@ end -------------------------------------------------------- -- 3DTracker -------------------------------------------------------- -e2function void wirelink:egp3DTracker( number index, vector pos ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egp3DTracker( number index, vector pos ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["3DTracker"], { index = index, target_x = pos[1], target_y = pos[2], target_z = pos[3], directionality = 0 }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end -e2function void wirelink:egp3DTracker( number index, vector pos, number directionality ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egp3DTracker( number index, vector pos, number directionality ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end if directionality > 0 then directionality = 1 @@ -562,6 +583,7 @@ e2function void wirelink:egp3DTracker( number index, vector pos, number directio local bool, obj = EGP:CreateObject( this, EGP.Objects.Names["3DTracker"], { index = index, target_x = pos[1], target_y = pos[2], target_z = pos[3], directionality = directionality }, self.player ) if (bool) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end __e2setcost(10) @@ -570,7 +592,7 @@ e2function void wirelink:egpPos( number index, vector pos ) if (!EGP:IsAllowed( self, this )) then return end local bool, k, v = EGP:HasObject( this, index ) if (bool) then - if (EGP:EditObject( v, { target_x = pos[1], target_y = pos[2], target_z = pos[3] } )) then EGP:DoAction( this, self, "SendObject", v ) Update(self,this) end + if (v:EditObject({ target_x = pos[1], target_y = pos[2], target_z = pos[3] })) then EGP:DoAction( this, self, "SendObject", v ) Update(self,this) end end end @@ -587,7 +609,7 @@ e2function void wirelink:egpSize( number index, vector2 size ) if (!EGP:IsAllowed( self, this )) then return end local bool, k, v = EGP:HasObject( this, index ) if (bool) then - if (EGP:EditObject( v, { w = size[1], h = size[2] } )) then EGP:DoAction( this, self, "SendObject", v ) Update(self,this) end + if v:EditObject({ w = size[1], h = size[2] }) then EGP:DoAction( this, self, "SendObject", v ) Update(self,this) end end end @@ -604,11 +626,8 @@ end ---------------------------- e2function void wirelink:egpPos( number index, vector2 pos ) if (!EGP:IsAllowed( self, this )) then return end - local bool, k, v = EGP:HasObject( this, index ) - if (bool) then - local x, y = pos[1], pos[2] - if (EGP:EditObject( v, { x = x, y = y, _x = x, _y = y } )) then EGP:DoAction( this, self, "SendObject", v ) Update(self,this) end - end + local bool, _, v = EGP:HasObject(this, index) + if bool and v:SetPos(pos[1], pos[2]) then EGP:DoAction( this, self, "SendObject", v ) Update(self,this) end end ---------------------------- @@ -619,7 +638,7 @@ e2function void wirelink:egpAngle( number index, number angle ) if (!EGP:IsAllowed( self, this )) then return end local bool, k, v = EGP:HasObject( this, index ) if (bool) then - if (EGP:EditObject( v, { angle = angle, _angle = angle } )) then EGP:DoAction( this, self, "SendObject", v ) Update(self,this) end + if v:SetPos(nil, nil, angle) then EGP:DoAction( this, self, "SendObject", v ) Update(self,this) end end end @@ -643,7 +662,7 @@ e2function void wirelink:egpAngle( number index, vector2 worldpos, vector2 axisp local t = { x = x, _x = x, y = y, _y = y } if (v.angle) then t.angle, t._angle = angle, angle end - if (EGP:EditObject( v, t )) then EGP:DoAction( this, self, "SendObject", v ) Update(self,this) end + if v:EditObject(t) then EGP:DoAction( this, self, "SendObject", v ) Update(self,this) end end end end @@ -818,18 +837,15 @@ end __e2setcost(20) e2function vector wirelink:egpGlobalPos( number index ) - local hasvertices, posang = EGP:GetGlobalPos( this, index ) - if hasvertices then - local x, y = getCenterFromPos(posang) - return Vector(x , y, 0) - end + local _, posang = EGP:GetGlobalPos( this, index ) return Vector(posang.x, posang.y, posang.angle) end e2function array wirelink:egpGlobalVertices( number index ) - local hasvertices, data = EGP:GetGlobalPos( this, index ) - if (hasvertices) then - if (data.vertices) then + local hasobject, _, object = EGP:HasObject(this, index) + if hasobject and object.verticesindex then + local data = EGP:GetGlobalVertices(object) + if data.vertices then local ret = {} for i=1,#data.vertices do local v = data.vertices[i] @@ -984,21 +1000,28 @@ e2function string wirelink:egpObjectType(number index) return "" end +e2function egpobject wirelink:egpObject(number index) + local bool, _, obj = EGP:HasObject(this, index) + return bool and obj or nil +end + -------------------------------------------------------- -- Additional Functions -------------------------------------------------------- __e2setcost(15) -e2function void wirelink:egpCopy( index, fromindex ) - if (!EGP:IsAllowed( self, this )) then return end +e2function egpobject wirelink:egpCopy( index, fromindex ) + if (!EGP:IsAllowed( self, this )) then return NULL_EGPOBJECT end local bool, k, v = EGP:HasObject( this, fromindex ) if (bool) then local copy = table.Copy( v ) copy.index = index local bool2, obj = EGP:CreateObject( this, v.ID, copy, self.player ) if (bool2) then EGP:DoAction( this, self, "SendObject", obj ) Update(self,this) end + return obj end + return NULL_EGPOBJECT end __e2setcost(20) @@ -1036,7 +1059,7 @@ __e2setcost(20) --- Returns 1 if the object with specified index contains the specified point. e2function number wirelink:egpObjectContainsPoint(number index, vector2 point) local _, _, object = EGP:HasObject(this, index) - return object and object:Contains(this, point[1], point[2]) and 1 or 0 + return object and object:Contains(point[1], point[2]) and 1 or 0 end __e2setcost(10) @@ -1155,7 +1178,7 @@ e2function void wirelink:egpHudEnable(enable) end e2function array wirelink:egpConnectedUsers() - if not EGP:ValidEGP(this) then return self:throw("Invalid wirelink!", nil) end + if not EGP:ValidEGP(this) then return self:throw("Invalid wirelink!", {}) end if not this.Users then return {} end local sanitised_array, i = {}, 0 diff --git a/lua/entities/gmod_wire_expression2/core/egpobjects.lua b/lua/entities/gmod_wire_expression2/core/egpobjects.lua new file mode 100644 index 0000000000..58560a4b78 --- /dev/null +++ b/lua/entities/gmod_wire_expression2/core/egpobjects.lua @@ -0,0 +1,866 @@ +-- +-- File for EGP Object handling in E2. +-- + +-- Dumb but simple +local NULL_EGPOBJECT = EGP.NULL_EGPOBJECT +local M_NULL_EGPOBJECT = getmetatable(NULL_EGPOBJECT) +local M_EGPObject = getmetatable(EGP.Objects.Base) + +-- Table of allowed arguments and their types +local EGP_ALLOWED_ARGS = + { + x = "n", + x2 = "n", + y = "n", + y2 = "n", + z = "n", + w = "n", + h = "n", + r = "n", + g = "n", + b = "n", + a = "n", + size = "n", + angle = "n", + fidelity = "n", + radius = "n", + valign = "n", + halign = "n", + text = "s", + font = "s", + material = "s", + } + +local function Update(self, this) + self.data.EGP.UpdatesNeeded[this] = true +end + +local function isValid(this) + if this and getmetatable(this) ~= M_NULL_EGPOBJECT then return true else return false end +end + +---- Type defintion + +registerType("egpobject", "xeo", NULL_EGPOBJECT, + nil, + nil, + nil, + function(v) + return not istable(v) or getmetatable(v) ~= M_EGPObject + end +) + +__e2setcost(2) + +registerOperator("ass", "xeo", "xeo", function(self, args) + local lhs, op2, scope = args[2], args[3], args[4] + local rhs = op2[1](self, op2) + if rhs == nil then return nil end + + self.Scopes[scope][lhs] = rhs + self.Scopes[scope].vclk[lhs] = true + return rhs +end) + +e2function number operator_is(egpobject egpo) + return (getmetatable(egpo) == M_EGPObject) and 1 or 0 +end + +e2function number operator==(egpobject lhs, egpobject rhs) + return (lhs == rhs) and 1 or 0 +end + +---- Functions + +---------------------------- +-- Table modification +---------------------------- + +__e2setcost(10) + +e2function egpobject egpobject:modify(table arguments) + local egp = this.EGP + local converted = {} + + for k, v in pairs(arguments.s) do + if EGP_ALLOWED_ARGS[k] == arguments.stypes[k] or false then converted[k] = v end + end + + if this:EditObject(converted) then EGP:DoAction(egp, self, "Update", this) Update(self, egp) end + return this +end + +-------------------------------------------------------- +-- Order +-------------------------------------------------------- + +__e2setcost(15) + +e2function void egpobject:setOrder(order) + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + local bool, k = EGP:HasObject(egp, this.index) + if (bool) then + if EGP:SetOrder(egp, k, order) then + EGP:DoAction(egp, self, "SendObject", this) + Update(self, egp) + end + end +end + +e2function number egpobject:getOrder() + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return -1 end + local bool, k = EGP:HasObject(egp, this.index) + return bool and k or -1 +end + +e2function void egpobject:setOrderAbove(egpobject abovethis) + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if not (isValid(this) or isValid(abovethis)) then self:throw("Invalid EGP Object") end + local bool, k = EGP:HasObject(egp, this.index) + if bool then + if EGP:HasObject(egp, abovethis.index) then + if EGP:SetOrder(egp, k, abovethis.index, 1) then + EGP:DoAction(egp, self, "SendObject", this) + Update(self, egp) + end + end + end +end + +e2function void egpobject:setOrderBelow(egpobject belowthis) + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if not (isValid(this) or isValid(belowthis)) then self:throw("Invalid EGP Object") end + local bool, k = EGP:HasObject(egp, this.index) + if bool then + if EGP:HasObject(egp, belowthis.index) then + if EGP:SetOrder(egp, k, belowthis.index, -1) then + EGP:DoAction(egp, self, "SendObject", this) + Update(self, egp) + end + end + end +end + +---------------------------- +-- Set Text +---------------------------- + +__e2setcost(7) + +e2function void egpobject:setText(string text) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:Set("text", text) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:setText(string text, string font, number size) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:EditObject({ text = text, font = font, size = size }) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +---------------------------- +-- Alignment +---------------------------- +e2function void egpobject:setAlign(number halign) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:Set("halign", math.Clamp(halign, 0, 2)) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:setAlign(number halign, number valign) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:EditObject({ valign = math.Clamp(valign, 0, 2), halign = math.Clamp(halign, 0, 2) }) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +---------------------------- +-- Filtering +---------------------------- +e2function void egpobject:setFiltering(number filtering) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:Set("filtering", math.Clamp(filtering, 0, 3)) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +---------------------------- +-- Font +---------------------------- +e2function void egpobject:setFont(string font) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if #font > 30 then return self:throw("Font string is too long!") end + if this:Set("font", font) then EGP:DoAction(egp, self, "SendObject", obj) Update(self, this) end +end + +e2function void egpobject:setFont(string font, number size) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if #font > 30 then return self:throw("Font string is too long!") end + if this:EditObject({ font = font, size = size }) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +-------------------------------------------------------- +-- 3DTracker +-------------------------------------------------------- +__e2setcost(10) + +e2function void egpobject:setPos(vector pos) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:EditObject({ target_x = pos[1], target_y = pos[2], target_z = pos[3] }) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +-------------------------------------------------------- +-- Set functions +-------------------------------------------------------- + +__e2setcost(7) + +---------------------------- +-- Size +---------------------------- +e2function void egpobject:setSize(vector2 size) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:EditObject({ w = size[1], h = size[2] }) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:setSize(width, height) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:EditObject({ w = width, h = height }) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:setSize(number size) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:Set("size", size) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +---------------------------- +-- Position +---------------------------- +e2function void egpobject:setPos(vector2 pos) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:SetPos(pos[1], pos[2]) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:setPos(x, y) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:SetPos(x, y) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:setPos(x, y, x2, y2) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:SetPos(x, y, nil, x2, y2) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +---------------------------- +-- Angle +---------------------------- +e2function void egpobject:setAngle(number angle) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:Set("angle", angle) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +------------- +-- Position & Angle +------------- +e2function void egpobject:setPos(x, y, angle) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:SetPos(x, y, angle) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:rotateAroundAxis(vector2 worldpos, vector2 axispos, number angle) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this.x and this.y then + local vec, ang = LocalToWorld(Vector(axispos[1], axispos[2], 0), angle_origin, Vector(worldpos[1], worldpos[2], 0), Angle(0, -angle, 0)) + + local x = vec.x + local y = vec.y + + angle = -ang.yaw + + if this:SetPos(x, y, angle) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end + end +end + +---------------------------- +-- Polys +---------------------------- + +local maxVertices = EGP.ConVars.MaxVertices + +e2function void egpobject:setVertices(array verts) + if not isValid(this) then return self:throw("Invalid EGP Object") end + if not this.vertices then return end + if #verts < 3 then return end + local max = maxVertices:GetInt() + + local vertices = {} + for _, v in ipairs(verts) do + if istable(v) then + local n = #vertices + if n > max then + break + elseif #v == 2 then + vertices[n + 1] = { x = v[1], y = v[2] } + elseif #v == 4 then + vertices[n + 1] = { x= v[1], y = v[2], u = v[3], v = v[4] } + end + end + end + + if this:Set("vertices", vertices) then + local egp = this.EGP + EGP:InsertQueue(egp, self.player, EGP._SetVertex, "SetVertex", this.index, vertices, true) -- wtf? + Update(self, egp) + end +end + +e2function void egpobject:setVertices(...args) + if not isValid(this) then return self:throw("Invalid EGP Object") end + if not this.vertices then return end + if #args < 3 then return end + local max = maxVertices:GetInt() + + local vertices = {} + for k, v in ipairs(args) do + if istable(v) then + local n = #vertices + if n > max then + break + elseif typeids[k] == "xv2" then + vertices[n + 1] = { x= v[1], y = v[2] } + elseif typeids[k] == "xv4" then + vertices[n + 1] = { x= v[1], y = v[2], u = v[3], v = v[4] } + end + end + end + + if this:Set("vertices", vertices) then + local egp = this.EGP + EGP:InsertQueue(egp, self.player, EGP._SetVertex, "SetVertex", this.index, vertices, true) + Update(self, egp) + end +end + + + +---------------------------- +-- Color +---------------------------- +e2function void egpobject:setColor(vector4 color) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:EditObject({ r = color[1], g = color[2], b = color[3], a = color[4] }) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:setColor(vector color) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:EditObject({ r = color[1], g = color[2], b = color[3] }) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:setColor(r, g, b, a) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:EditObject({ r = r, g = g, b = b, a = a }) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:setAlpha(number a) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:Set("a", a) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +---------------------------- +-- Material +---------------------------- +e2function void egpobject:setMaterial(string material) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + material = WireLib.IsValidMaterial(material) + if this:Set("material", material) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:setMaterialFromScreen(entity gpu) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if gpu and gpu:IsValid() then + if this:Set("material", gpu) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end + end +end + +---------------------------- +-- Fidelity (number of corners for circles and wedges) +---------------------------- +e2function void egpobject:setFidelity(number fidelity) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:EditObject({ fidelity = math.Clamp(fidelity, 3, 180) }) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +[nodiscard] +e2function number egpobject:getFidelity() + return this.fidelity or -1 +end + +---------------------------- +-- Parenting +---------------------------- +e2function void egpobject:parentTo(egpobject parent) + if not isValid(this) or not isValid(parent) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if egp ~= parent.EGP then return self:throw("Invalid EGP Object", nil) end + if not EGP:IsAllowed(self, egp) then return end + if EGP:SetParent(egp, this, parent) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:parentTo(number parentindex) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if EGP:SetParent(egp, this, parentindex) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void wirelink:egpParent(egpobject child, egpobject parent) + if not EGP:IsAllowed(self, this) then return end + if not EGP:ValidEGP(this) then return self:throw("Invalid wirelink!") end + if not (isValid(child) or isValid(parent) or child.EGP == this or parent.EGP == this) then return self:throw("Invalid EGP Object", nil) end + if EGP:SetParent(this, child, parent) then EGP:DoAction(this, self, "SendObject", child) Update(self, this) end +end + +-- Entity parenting (only for 3Dtracker - does nothing for any other object) +e2function void egpobject:trackerParent(entity parent) + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not parent or not parent:IsValid() then return end + if not EGP:IsAllowed(self, egp) then return end + + if this.NeedsConstantUpdate and this.parententity ~= parent then + this.parententity = parent + + EGP:DoAction(egp, self, "SendObject", this) + Update(self, egp) + end +end + +-- Returns the entity a tracker is parented to +[nodiscard] +e2function entity egpobject:trackerParent() + if not isValid(this) then return self:throw("Invalid EGP Object", NULL) end + return IsValid(this.parententity) and this.parententity or NULL +end + +e2function void egpobject:parentToCursor() + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if EGP:SetParent(egp, this, -1) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +e2function void egpobject:unparent() + if not isValid(this) then return self:throw("Invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if EGP:UnParent(egp, this) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) end +end + +[nodiscard] +e2function number egpobject:parentIndex() + if not isValid(this) then return self:throw("Invalid EGP Object", 0) end + return this.parent or 0 +end + +[nodiscard] +e2function egpobject egpobject:parent() + if not isValid(this) then return self:throw("Invalid EGP Object", NULL_EGPOBJECT) end + local _, _, v = EGP:HasObject(this.EGP, this.parent) + return v or NULL_EGPOBJECT +end + +-------------------------------------------------------- +-- Remove +-------------------------------------------------------- +e2function void wirelink:egpRemove(egpobject obj) + if not EGP:IsAllowed(self, this) then return end + if not EGP:ValidEGP(this) then return end + if isValid(obj) then + EGP:DoAction(this, self, "RemoveObject", obj.index) + table.Empty(obj) + setmetatable(obj, M_NULL_EGPOBJECT) + Update(self, this) + end +end + +e2function void egpobject:remove() + if not isValid(this) then return end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + + EGP:DoAction(egp, self, "RemoveObject", this.index) + table.Empty(this) + setmetatable(this, M_NULL_EGPOBJECT) -- In an ideal scenario we would probably want this = NULL_EGPOBJECT instead + Update(self, egp) +end + +e2function void egpobject:draw() + if not this._nodraw then return end + local egp = this.EGP + this._nodraw = nil + if not EGP:IsAllowed(self, egp) then return end + + if EGP:CreateObject(egp, this.ID, this) then + EGP:DoAction(egp, self, "SendObject", this) + Update(self, egp) + end +end + +e2function void egpobject:hide() + if not isValid(this) or this._nodraw then return end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + + EGP:DoAction(egp, self, "RemoveObject", this.index) + this._nodraw = true + Update(self, egp) +end + +[nodiscard] +e2function number egpobject:isVisible() + return isValid(this) and not this._nodraw and 1 or 0 +end + +-------------------------------------------------------- +-- Get functions +-------------------------------------------------------- +__e2setcost(20) + +[nodiscard] +e2function vector egpobject:globalPos() + if not isValid(this) then return self:throw("Invalid EGP Object", Vector(0, 0, 0)) end + local _, posang = EGP:GetGlobalPos(this.EGP, this) + return Vector(posang.x, posang.y, posang.angle) +end + +[nodiscard] +e2function array egpobject:globalVertices() + if not isValid(this) then return self:throw("Invalid EGP Object", {}) end + if this.verticesindex then + local data = EGP:GetGlobalVertices(this.EGP, this) + if data.vertices then + local ret = {} + for i = 1, #data.vertices do + local v = data.vertices[i] + ret[i] = {v.x, v.y} + self.prf = self.prf + 0.1 + end + return ret + elseif data.x and data.y and data.x2 and data.y2 and data.x3 and data.y3 then + return { { data.x, data.y }, { data.x2, data.y2 }, { data.x3, data.y3 } } + elseif data.x and data.y and data.x2 and data.y2 then + return { {data.x, data.y}, {data.x2, data.y2} } + end + end + return {} +end + +[nodiscard] +e2function number wirelink:egpHasObject(egpobject object) + return this == object.EGP and 1 or 0 +end + + +__e2setcost(3) + +[nodiscard] +e2function vector2 egpobject:getPos() + if not isValid(this) then return self:throw("Invalid EGP Object", { -1, -1 }) end + return (this.x and this.y and { this.x, this.y }) or { -1, -1 } +end + + +[nodiscard] +e2function vector egpobject:getPosAng() + if not isValid(this) then return self:throw("Invalid EGP Object", Vector(-1, -1, -1)) end + return (this.x and this.y and this.angle and Vector(this.x, this.y, this.angle)) or Vector(-1, -1, -1) +end + +[nodiscard] +e2function vector2 egpobject:getSize() + if not isValid(this) then return self:throw("Invalid EGP Object", { -1, -1 }) end + return (this.w and this.h and { this.w, this.h }) or { -1, -1 } +end + +[nodiscard] +e2function number egpobject:getSizeNum() + if not isValid(this) then return self:throw("Invalid EGP Object", -1) end + return this.size or -1 +end + +[nodiscard] +e2function vector4 egpobject:getColor4() + if not isValid(this) then return self:throw("Invalid EGP Object", { -1, -1, -1, -1 }) end + return (this.r and this.g and this.b and this.a and { this.r, this.g, this.b, this.a }) or { -1, -1, -1, -1 } +end + +[nodiscard] +e2function vector egpobject:getColor() + if not isValid(this) then return self:throw("Invalid EGP Object", Vector(-1, -1, -1)) end + return (this.r and this.g and this.b and Vector(this.r, this.g, this.b)) or Vector(-1, -1, -1) +end + +[nodiscard] +e2function number egpobject:getAlpha() + if not isValid(this) then return self:throw("Invalid EGP Object", -1) end + return this.a or -1 +end + +[nodiscard] +e2function number egpobject:getAngle() + if not isValid(this) then return self:throw("Invalid EGP Object", -1) end + return this.angle or -1 +end + +[nodiscard] +e2function string egpobject:getMaterial() + if not isValid(this) then return self:throw("Invalid EGP Object", "") end + return tostring(this.material) or "" +end + +[nodiscard] +e2function number egpobject:getRadius() + if not isValid(this) then return self:throw("Invalid EGP Object", -1) end + return this.radius or -1 +end + +__e2setcost(10) + +[nodiscard] +e2function array egpobject:getVertices() + if this.vertices then + local ret = {} + for k, v in ipairs(this.vertices) do + ret[k] = { v.x, v.y } + end + return ret + elseif v.x and v.y and v.x2 and v.y2 and v.x3 and v.y3 then + return { {v.x, v.y}, {v.x2, v.y2 }, { v.x3, v.y3 } } + elseif v.x and v.y and v.x2 and v.y2 then + return { {v.x, v.y}, { v.x2, v.y2 } } + else + return {} + end +end + +-------------------------------------------------------- +-- Object Type +-------------------------------------------------------- +__e2setcost(4) + +[nodiscard] +e2function string egpobject:getObjectType() + return this.Name or "Unknown" +end + +-------------------------------------------------------- +-- Additional Functions +-------------------------------------------------------- + +__e2setcost(15) + +[nodiscard] +e2function egpobject wirelink:egpCopy(number index, egpobject from) + if not EGP:IsAllowed(self, this) then return NULL_EGPOBJECT end + if not EGP:ValidEGP(this) then return self:throw("Invalid wirelink!", NULL_EGPOBJECT) end + if not isValid(from) then return self:throw("Invalid EGPObject", NULL_EGPOBJECT) end + if from then + local copy = table.Copy(from) + copy.index = index + local bool, obj = EGP:CreateObject(this, from.ID, copy, self.player) + if bool then EGP:DoAction(this, self, "SendObject", obj) Update(self, this) return obj end + end +end + +e2function void egpobject:copyFrom(egpobject from) + if not EGP:IsAllowed(self, this) then return end + if not isValid(from) then return self:throw("Invalid EGPObject") end + if from then + local copy = table.Copy(from) + copy.index = this.index + copy.EGP = this.EGP + local bool, obj = EGP:CreateObject(copy.EGP, from.ID, copy, self.player) + if bool then EGP:DoAction(this, self, "SendObject", obj) Update(self, this) return end + end +end + +__e2setcost(10) + +[nodiscard] +e2function number egpobject:containsPoint(vector2 point) + return isValid(this) and this:Contains(point[1], point[2]) and 1 or 0 +end + +__e2setcost(5) + +[nodiscard] +e2function egpobject wirelink:egpobject(number index) + if not EGP:IsAllowed(self, this) then return NULL_EGPOBJECT end + if not EGP:ValidEGP(this) then return self:throw("Invalid wirelink!", NULL_EGPOBJECT) end + local _, _, obj = EGP:HasObject(this, index) + return obj or NULL_EGPOBJECT +end + +__e2setcost(1) + +[nodiscard] +e2function egpobject noegpobject() + return NULL_EGPOBJECT +end + +[nodiscard] +e2function string toString(egpobject egpo) + return tostring(egpo) +end + +[nodiscard] +e2function string egpobject:toString() = e2function string toString(egpobject egpo) + +-------------------------------------------------------- +-- Array Index Operators +-------------------------------------------------------- + +registerCallback("postinit", function() + E2Lib.currentextension = "egpobjects" + local fixDefault = E2Lib.fixDefault + for _, v in pairs(wire_expression_types) do + local id = v[1] + local default = v[2] + local typecheck = v[6] + + __e2setcost(5) + + -- Getter + registerOperator("indexget", "xeos" .. id, id, function(self, this, index) + local indexType = EGP_ALLOWED_ARGS[index] + + if not indexType then return fixDefault(default) end + + local obj = this[index] + + if not obj or id ~= indexType then return fixDefault(default) end + if typecheck and typecheck(obj) then return fixDefault(default) end -- Type check + + return obj + end) + + -- Setter + registerOperator("indexset", "xeos" .. id, id, function(self, this, index, value) + if not EGP_ALLOWED_ARGS[index] then return fixDefault(default) end + + if not isValid(this) then return self:throw("Tried to acces invalid EGP Object", nil) end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return fixDefault(default) end + if this:Set(index, value) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) self.GlobalScope.vclk[this] = true end + return value + end) + + -- Implicitly typed setter + registerOperator("indexset", "xeos", id, function(self, this, index, value) + local indexType = EGP_ALLOWED_ARGS[index] + + if not indexType then return end + if indexType ~= id then self:throw(string.format("EGP Object expected '%s' type but got '%s'!", indexType, id)) end + + if not isValid(this) then return self:throw("Tried to acces invalid EGP Object") end + local egp = this.EGP + if not EGP:IsAllowed(self, egp) then return end + if this:Set(index, value) then EGP:DoAction(egp, self, "SendObject", this) Update(self, egp) self.GlobalScope.vclk[this] = true end + return + end) + end + + local egpCreate = EGP.CreateObject + local workingSet = table.Copy(EGP.Objects.Names) + for name, id in pairs(workingSet) do + -- Indexed table "constructor" + registerFunction("egp" .. name, "xwl:nt", "xeo", function(self, args) + local this, index, args = args[1], args[2], args[3] + if not EGP:IsAllowed(self, this) then return NULL_EGPOBJECT end + + local converted = {} + + for k, v in pairs(args.s) do + if EGP_ALLOWED_ARGS[k] == args.stypes[k] or false then converted[k] = v end + end + + converted.index = index + + local bool, obj = egpCreate(EGP, this, id, converted) + if bool then + EGP:DoAction(this, self, "SendObject", obj) + Update(self, this) + end + return obj + end, 10, { "index", "args" }, { legacy = false }) + + --[[ + -- Unindexed table constructor + registerFunction("egp" .. name, "xwl:t", "xeo", function(self, args) + local this, index, args = args[1], args[2], args[3] + + local converted = {} + + for k, v in pairs(args.s) do + if EGP_ALLOWED_ARGS[k] == args.stypes[k] or false then converted[k] = v end + end + + converted.index = EGP.GetNextIndex(this) + + local bool, obj = egpCreate(this, id, converted) + if bool then + EGP:DoAction(this, self, "SendObject", obj) + Update(self, this) + return obj + end + end, 10, { "this", "args" }, { nodiscard = true, legacy = false }) + ]] + end +end) diff --git a/lua/entities/gmod_wire_expression2/core/extloader.lua b/lua/entities/gmod_wire_expression2/core/extloader.lua index 64f137edd9..5cfa208c1a 100644 --- a/lua/entities/gmod_wire_expression2/core/extloader.lua +++ b/lua/entities/gmod_wire_expression2/core/extloader.lua @@ -168,6 +168,7 @@ e2_include("steamidconv.lua") e2_include("easings.lua") e2_include("damage.lua") e2_include("remote.lua") +e2_include("egpobjects.lua") -- Load serverside files here, they need additional parsing do diff --git a/lua/wire/client/e2descriptions.lua b/lua/wire/client/e2descriptions.lua index 8a967f3283..bf31e7db53 100644 --- a/lua/wire/client/e2descriptions.lua +++ b/lua/wire/client/e2descriptions.lua @@ -1410,31 +1410,33 @@ E2Helper.Descriptions["bNot(nn)"] = "Performs a binary Not. The second argument E2Helper.Descriptions["egpAlign(xwl:nn)"] = "Changes the horizontal alignment. Works on: text and text layout. Number can be 0, 1 or 2" E2Helper.Descriptions["egpAlign(xwl:nnn)"] = "Changes the horizontal and vertical alignment. Works on: text and text layout. Numbers can be 0, 1 or 2" E2Helper.Descriptions["egpAlpha(xwl:nn)"] = "Changes the alpha (transparency) of an object" -E2Helper.Descriptions["egpAlpha(xwl:n)"] = "Returns the alpha of the object" +E2Helper.Descriptions["egpAlpha"] = "Returns the alpha of the object" E2Helper.Descriptions["egpAngle(xwl:nn)"] = "Changes the angle of the object" -E2Helper.Descriptions["egpAngle(xwl:n)"] = "Returns the angle of the object" +E2Helper.Descriptions["egpAngle"] = "Returns the angle of the object" E2Helper.Descriptions["egpAngle(xwl:nxv2xv2n)"] = "Rotates the object around the first vec2 with the second vec2 as offset at angle N" -E2Helper.Descriptions["egpColor(xwl:n)"] = "Returns the color of the object as 3D vector" +E2Helper.Descriptions["egpColor"] = "Returns the color of the object as 3D vector" E2Helper.Descriptions["egpColor(xwl:nnnnn)"] = "Changes the color and alpha of the object" E2Helper.Descriptions["egpColor(xwl:nxv4)"] = "Changes the color and alpha of the object" E2Helper.Descriptions["egpColor(xwl:nv)"] = "Changes the color of the object" -E2Helper.Descriptions["egpColor4(xwl:n)"] = "Returns the color of the object as 4D vector (including alpha)" -E2Helper.Descriptions["egpFidelity(xwl:n)"] = "Returns the fidelity of the object" +E2Helper.Descriptions["egpColor4"] = "Returns the color of the object as 4D vector (including alpha)" +E2Helper.Descriptions["egpFidelity"] = "Returns the fidelity of the object" E2Helper.Descriptions["egpFidelity(xwl:nn)"] = "Changes the fidelity of the object (the number of vertices the circle will use)" E2Helper.Descriptions["egpFont(xwl:nsn)"] = "Changes the font and size of the text object" -E2Helper.Descriptions["egpFont(xwl:ns)"] = "Changes the font of the text object" -E2Helper.Descriptions["egpMaterial(xwl:n)"] = "Returns the material of the object" +E2Helper.Descriptions["egpFont"] = "Changes the font of the text object" +E2Helper.Descriptions["egpMaterial"] = "Returns the material of the object" E2Helper.Descriptions["egpMaterial(xwl:ns)"] = "Changes the material of the object" E2Helper.Descriptions["egpMaterialFromScreen(xwl:ne)"] = "Sets the material of the object to a current snapshot of the target screen. Note that this only works for players which see both the egp as well the target screen at that time" E2Helper.Descriptions["egpOrder(xwl:nn)"] = "Sets the order at which the object will be rendered" -E2Helper.Descriptions["egpOrder(xwl:n)"] = "Returns the order at which the object is rendered" -E2Helper.Descriptions["egpParent(xwl:n)"] = "Returns the index of the parent object" +E2Helper.Descriptions["egpOrderAbove(xwl:nn)"] = "Makes the object render above the object at the index" +E2Helper.Descriptions["egpOrderBelow(xwl:nn)"] = "Makes the object render below the object at the index" +E2Helper.Descriptions["egpOrder"] = "Returns the order at which the object is rendered" +E2Helper.Descriptions["egpParent"] = "Returns the index of the parent object" E2Helper.Descriptions["egpParent(xwl:ne)"] = "Parents the 3D tracker object to an entity" E2Helper.Descriptions["egpParent(xwl:nn)"] = "Parents the object to another object. Parented objects' positions are local to their parent" E2Helper.Descriptions["egpParentToCursor(xwl:n)"] = "Parents the object to player's cursor" E2Helper.Descriptions["egpUnParent(xwl:n)"] = "Un-parents the object" E2Helper.Descriptions["egpPos(xwl:n)"] = "Returns the position of the object" -E2Helper.Descriptions["egpPos(xwl:nxv2)"] = "Changes the position of the object" +E2Helper.Descriptions["egpPos"] = "Changes the position of the object" E2Helper.Descriptions["egpPos(xwl:nv)"] = "Changes the world position of the 3D tracker object" E2Helper.Descriptions["egpQueue()"] = "Returns the number of items in your queue" E2Helper.Descriptions["egpQueueClk(e)"] = "Returns 1 if the current execution was caused by the EGP queue system of specified screen" @@ -1445,8 +1447,8 @@ E2Helper.Descriptions["egpQueuePlayer()"] = "Returns the player which ordered th E2Helper.Descriptions["egpQueueScreen()"] = "Returns the screen entity which the queue finished sending items for" E2Helper.Descriptions["egpQueueScreenWirelink()"] = "Returns the screen wirelink which the queue finished sending items for" E2Helper.Descriptions["egpRadius(xwl:nn)"] = "Changes the corner radius of the rounded box object" -E2Helper.Descriptions["egpRadius(xwl:n)"] = "Returns the corcner radius of the rounded box object" -E2Helper.Descriptions["egpRemove(xwl:n)"] = "Removes the object from the screen" +E2Helper.Descriptions["egpRadius"] = "Returns the corcner radius of the rounded box object" +E2Helper.Descriptions["egpRemove"] = "Removes the object from the screen" E2Helper.Descriptions["egpResolution(xwl:xv2xv2)"] = "Sets the scale of the screen such that the top left corner is equal to the first vector and the bottom right corner is equal to the second vector" E2Helper.Descriptions["egpScale(xwl:xv2xv2)"] = "Sets the scale of the screen's X axis to the first vector and Y axis to the second vector" E2Helper.Descriptions["egpScrH(e)"] = "Returns the player's screen resolution height" @@ -1455,22 +1457,19 @@ E2Helper.Descriptions["egpScrSize(e)"] = "Returns the player's screen resolution E2Helper.Descriptions["egpSetText(xwl:ns)"] = "Changes the text of the text object" E2Helper.Descriptions["egpSize(xwl:n)"] = "Returns the size of the object" E2Helper.Descriptions["egpSize(xwl:nn)"] = "Changes the size of the text/line/outline object" -E2Helper.Descriptions["egpSize(xwl:nxv2)"] = "Changes the size of the object" -E2Helper.Descriptions["egpSizeNum(xwl:n)"] = "Returns the size of the text/line/outline object" +E2Helper.Descriptions["egpSize"] = "Changes the width and height of the object" +E2Helper.Descriptions["egpSizeNum"] = "Returns the size of the text/line/outline object" E2Helper.Descriptions["egpToWorld(xwl:xv2)"] = "Converts a 2D vector on the screen or emitter into a 3D vector in the world" -E2Helper.Descriptions["egpTrackerParent(xwl:n)"] = "Returns the parent entity of the 3D tracker object" +E2Helper.Descriptions["egpTrackerParent"] = "Returns the parent entity of the 3D tracker object" ---E2Helper.Descriptions["egpAddVertices(xwl:nr)"] = "" ---E2Helper.Descriptions["egpBytesLeft()"] = "" E2Helper.Descriptions["egpCanSendUmsg()"] = "Returns 1 if you can send an usermessage at the moment, 0 otherwise" E2Helper.Descriptions["egpClear(xwl:)"] = "Clears the EGP screen" E2Helper.Descriptions["egpClearQueue()"] = "Clears your entire queue" -E2Helper.Descriptions["egpCopy(xwl:nn)"] = "Copies the settings of the second object into the first. If the first object does not exist, it's created" -E2Helper.Descriptions["egpConnectedUsers(xwl:)"] = "Returns an array of players connected to the EGP" +E2Helper.Descriptions["egpCopy"] = "Copies the settings of the second object into the first. If the first object does not exist, it's created" E2Helper.Descriptions["egpCursor(xwl:e)"] = "Returns the specified player's aim position on the screen" E2Helper.Descriptions["egpDrawTopLeft(xwl:n)"] = "Set to 1 to make boxes, outline boxes, rounded boxes, and rounded outline boxes draw from the top left corner instead of from the center" -E2Helper.Descriptions["egpGlobalPos(xwl:n)"] = "Returns the \"global\" (= it takes the parents' positions into consideration) position as a 3D vector. X and Y being the 2D X,Y coordinates, while Z is the angle" -E2Helper.Descriptions["egpGlobalVertices(xwl:n)"] = "Returns an array of 2D vectors with the \"global\" positions of the vertices in the object" +E2Helper.Descriptions["egpGlobalPos"] = "Returns the \"global\" (= it takes the parents' positions into consideration) position as a 3D vector. X and Y being the 2D X,Y coordinates, while Z is the angle" +E2Helper.Descriptions["egpGlobalVertices"] = "Returns an array of 2D vectors with the \"global\" positions of the vertices in the object" E2Helper.Descriptions["egpGlobalFiltering(xwl:n)"] = "Changes the texture filter used to draw all EGP Objects. Works only on EGP Screens. See _TEXFILTER constants (POINT=sharp, ANISOTROPIC=blurry/default)" E2Helper.Descriptions["egpHasObject(xwl:n)"] = "Returns 1 if the object with specified index exists on the screen, 0 if not" E2Helper.Descriptions["egpObjectContainsPoint(xwl:nxv2)"] = "Returns 1 if the object with specified index contains the specified point" @@ -1485,9 +1484,9 @@ E2Helper.Descriptions["egpMaxObjects()"] = "Returns the maximum amount of object E2Helper.Descriptions["egpMaxUmsgPerSecond()"] = "Returns the maximum number of usermessages you can send per second" E2Helper.Descriptions["egpNumObjects(xwl:)"] = "Returns the number of objects on the screen" E2Helper.Descriptions["egpRunOnQueue(xwl:n)"] = "Set to 1 if you want your E2 to be triggered once the queue has finished sending all items in the queue for the screen" -E2Helper.Descriptions["egpVertices(xwl:n)"] = "Returns an array of the vertices of the object" +E2Helper.Descriptions["egpVertices"] = "Returns an array of the vertices of the object" E2Helper.Descriptions["egpObjectIndexes(xwl:)"] = "Returns an array containing all object indexes being used" -E2Helper.Descriptions["egpObjectType(xwl:n)"] = "Returns the type of the object with specified index" +E2Helper.Descriptions["egpObjectType"] = "Returns the type of the object" E2Helper.Descriptions["egpObjectTypes(xwl:)"] = "Returns an array whose keys are bound to object index, and value being the type of particular object" E2Helper.Descriptions["egp3DTracker(xwl:nv)"] = "Creates a 3D tracker object at specified world position" @@ -1512,6 +1511,93 @@ E2Helper.Descriptions["egpTriangleOutline(xwl:nxv2xv2xv2)"] = "Creates a outline E2Helper.Descriptions["egpWedge(xwl:nxv2xv2)"] = "Creates a wedge object. Wedge objects are like circles, except they have a cake-piece-like mouth which you can change using egpSize" E2Helper.Descriptions["egpWedgeOutline(xwl:nxv2xv2)"] = "Creates a outline wedge object. Wedge objects are like circles, except they have a cake-piece-like mouth which you can change using egpSize" +E2Helper.Descriptions["egp3DTracker"] = "Creates a 3D tracker with the provided arguments" +E2Helper.Descriptions["egpBox"] = "Creates a box with the provided arguments" +E2Helper.Descriptions["egpBoxOutline"] = "Creates an outline box with the provided arguments" +E2Helper.Descriptions["egpCircle"] = "Creates a circle with the provided arguments" +E2Helper.Descriptions["egpCircleOutline"] = "Creates an outline circle with the provided arguments" +E2Helper.Descriptions["egpLine"] = "Creates a line with the provided arguments" +E2Helper.Descriptions["egpLineStrip"] = "Creates a curve with with the provided arguments. Use egpSetVertices to add vertices to it" +E2Helper.Descriptions["egpPoly"] = "Creates a polygon with with the provided arguments. Use egpSetVertices to add vertices to it" +E2Helper.Descriptions["egpPolyOutline"] = "Creates a outline polygon with with the provided arguments. Use egpSetVertices to add vertices to it" +E2Helper.Descriptions["egpRoundedBox"] = "Creates a rounded box with with the provided arguments" +E2Helper.Descriptions["egpRoundedBoxOutline"] = "Creates a rounded outline box with with the provided arguments" +E2Helper.Descriptions["egpText"] = "Creates a text object with with the provided arguments" +E2Helper.Descriptions["egpTextLayout"] = "Creates a text layout object with with the provided arguments" +E2Helper.Descriptions["egpWedge"] = "Creates a wedge object. Wedge objects are like circles, except they have a cake-piece-like mouth which you can change using egpSize" +E2Helper.Descriptions["egpWedgeOutline"] = "Creates a outline wedge object. Wedge objects are like circles, except they have a cake-piece-like mouth which you can change using egpSize" + +E2Helper.Descriptions["modify(xeo:t)"] = "Modifies an object with the provided arguments." + +E2Helper.Descriptions["copyFrom(xeo:xeo)"] = "Copies the settings of the second object into the first. If the first object does not exist, it's created" +E2Helper.Descriptions["getAlpha(xeo:)"] = "Returns the alpha of the object" +E2Helper.Descriptions["getAngle(xeo:)"] = "Returns the angle of the object" +E2Helper.Descriptions["getColor(xeo:)"] = "Returns the color of the object as a vector" +E2Helper.Descriptions["getColor4(xeo:)"] = "Returns the color of the object as a vector4" +E2Helper.Descriptions["getFidelity(xeo:)"] = "Returns the fidelity of the object" +E2Helper.Descriptions["getMaterial(xeo:)"] = "Returns the material of the object. Note this does not return anything when using a GPU material" +E2Helper.Descriptions["getObjectType(xeo:)"] = "Returns the type of the object" +E2Helper.Descriptions["getOrder(xeo:)"] = "Returns the order at which the object is rendered" +E2Helper.Descriptions["getRadius(xeo:)"] = "Returns the radius of the object" +E2Helper.Descriptions["getSize(xeo:)"] = "Returns the size of the object" +E2Helper.Descriptions["getSizeNum(xeo:)"] = "Returns the size of the text/line/outline object" +E2Helper.Descriptions["getVertices(xeo:)"] = "Returns an array of the vertices of the object" +E2Helper.Descriptions["globalPos(xeo:)"] = "Returns the \"global\" (= it takes the parents' positions into consideration) position as a 3D vector. X and Y being the 2D X,Y coordinates, while Z is the angle" +E2Helper.Descriptions["globalVertices(xeo:)"] = "Returns an array of 2D vectors with the \"global\" positions of the vertices in the object" +E2Helper.Descriptions["setAlign(xeo:n)"] = "Changes the horizontal alignment. Works on: text and text layout. Number can be 0, 1 or 2" +E2Helper.Descriptions["setAlign(xeo:nn)"] = "Changes the horizontal and vertical alignment. Works on: text and text layout. Numbers can be 0, 1 or 2" +E2Helper.Descriptions["setAlpha(xeo:n)"] = "Changes the alpha (transparency) of an object" +E2Helper.Descriptions["setAngle(xeo:n)"] = "Changes the angle of the object" +E2Helper.Descriptions["rotateAroundAxis(xeo:xv2xv2n)"] = "Rotates the object around the first vec2 with the second vec2 as offset at angle N" +E2Helper.Descriptions["setColor(xeo:nnnn)"] = "Changes the color and alpha of the object" +E2Helper.Descriptions["setColor(xeo:xv4)"] = "Changes the color and alpha of the object" +E2Helper.Descriptions["setColor(xeo:v)"] = "Changes the color of the object" +E2Helper.Descriptions["setFidelity(xeo:n)"] = "Changes the fidelity of the object (the number of vertices the circle will use)" +E2Helper.Descriptions["setFont(xeo:s)"] = "Changes the font of the text object" +E2Helper.Descriptions["setFont(xeo:sn)"] = "Changes the font and size of the text object" +E2Helper.Descriptions["setMaterial(xeo:s)"] = "Changes the material of the object" +E2Helper.Descriptions["setMaterialFromScreen(xeo:e)"] = "Sets the material of the object to a current snapshot of the target screen. Note that this only works for players which see both the egp as well the target screen at that time" +E2Helper.Descriptions["setOrder(xeo:n)"] = "Sets the order at which the object will be rendered. This is different from index" +E2Helper.Descriptions["setOrderAbove(xeo:xeo)"] = "Makes the object render above the object" +E2Helper.Descriptions["setOrderBelow(xeo:xeo)"] = "Makes the object render below the object" +E2Helper.Descriptions["parent(xeo:)"] = "Returns the parent object" +E2Helper.Descriptions["parentTo(xeo:n)"] = "Parents the object to another object. Parented objects' positions are local to their parent" +E2Helper.Descriptions["parentTo(xeo:xeo)"] = "Parents the object to another object. Parented objects' positions are local to their parent" +E2Helper.Descriptions["egpParent(xwl:xeoxeo)"] = "Parents the object to another object. Parented objects' positions are local to their parent" +E2Helper.Descriptions["parentToCursor(xeo:)"] = "Parents the object to player's cursor" +E2Helper.Descriptions["parentIndex(xeo:)"] = "Returns the index of the parent object" +E2Helper.Descriptions["remove(xeo:)"] = "Removes the object from the screen" +E2Helper.Descriptions["unparent(xeo:)"] = "Un-parents the object" +E2Helper.Descriptions["getPos(xeo:)"] = "Returns the position of the object" +E2Helper.Descriptions["getPosAng(xeo:)"] = "Returns the position (x, y) and angle (z) of the object" +E2Helper.Descriptions["setPos(xeo:nnnn)"] = "Changes the position of the start and end of a line object, otherwise acts normally." +E2Helper.Descriptions["setPos(xeo:v)"] = "Changes the world position of the 3D tracker object" +E2Helper.Descriptions["setPos(xeo:xv2)"] = "Changes the position of the object" +E2Helper.Descriptions["setPos(xeo:nn)"] = "Changes the position of the object" +E2Helper.Descriptions["setPos(xeo:nnn)"] = "Changes the position and angle of the object" +E2Helper.Descriptions["setRadius(xeo:n)"] = "Changes the corner radius of the rounded box object" +E2Helper.Descriptions["setText(xeo:s)"] = "Changes the text of the text object" +E2Helper.Descriptions["setText(xeo:ssn)"] = "Changes the text, font, and text size of the text object" +E2Helper.Descriptions["setVertices"] = "Sets the vertices of the object. Can use vector2 or vector4 for vertices." +E2Helper.Descriptions["setSize(xeo:n)"] = "Changes the size of the text/line/outline object" +E2Helper.Descriptions["setSize(xeo:nn)"] = "Changes the width and height of an object" +E2Helper.Descriptions["setSize(xeo:xv2)"] = "Changes the width and height of an object" +E2Helper.Descriptions["isVisible(xeo:)"] = "Returns 1 if the object is visible." +E2Helper.Descriptions["hide(xeo:)"] = "Removes an object from the screen but keeps its data intact." +E2Helper.Descriptions["draw(xeo:)"] = "Shows a hidden EGP object." +E2Helper.Descriptions["trackerParent(xeo:)"] = "Returns the parent entity of the 3D tracker object." +E2Helper.Descriptions["trackerParent(xeo:e)"] = "Parents the 3D tracker object to an entity" + +E2Helper.Descriptions["egpConnectedUsers(xwl:)"] = "Returns an array of players connected to the EGP" +E2Helper.Descriptions["egpCursor(xwl:e)"] = "Returns the specified player's aim position on the screen" +E2Helper.Descriptions["egpHasObject(xwl:xeo)"] = "Returns 1 if the object exists on the screen, 0 if not" +E2Helper.Descriptions["containsPoint(xeo:xv2)"] = "Returns 1 if the object contains the specified point" +E2Helper.Descriptions["setFiltering(xeo:n)"] = "Changes the texture filter used to draw the object. Works on objects that draw a material. See _TEXFILTER constants (POINT=sharp, ANISOTROPIC=blurry/default)" +E2Helper.Descriptions["egpobject(xwl:n)"] = "Returns the EGPObject at the index" +E2Helper.Descriptions["noegpobject"] = "Returns a NULL egpobject." +E2Helper.Descriptions["toString(xeo:)"] = "Returns a string representation of the EGPObject" +E2Helper.Descriptions["toString(xeo)"] = "Returns a string representation of the EGPObject" + -- (de)serialization E2Helper.Descriptions["glonDecode(s)"] = "Decodes a string into an array using GLON" E2Helper.Descriptions["glonDecodeTable(s)"] = "Decodes a string into a table using GLON"