commit 154813f54a399afadd01266fb45fdd73f0c75e3f Author: Ryan Ward Date: Mon Feb 10 17:18:21 2020 -0500 First Commit diff --git a/GuiManager/Core/Colors.int b/GuiManager/Core/Colors.int new file mode 100644 index 0000000..ceded46 --- /dev/null +++ b/GuiManager/Core/Colors.int @@ -0,0 +1,1683 @@ +local function HSL(h, s, l, a) + if s<=0 then return l,l,l,a end + h, s, l = h/256*6, s/255, l/255 + local c = (1-math.abs(2*l-1))*s + local x = (1-math.abs(h%2-1))*c + local m,r,b,g = (l-.5*c), 0,0,0 + if h < 1 then r,b,g = c,x,0 + elseif h < 2 then r,b,g = x,c,0 + elseif h < 3 then r,b,g = 0,c,x + elseif h < 4 then r,b,g = 0,x,c + elseif h < 5 then r,b,g = x,0,c + else r,b,g = c,0,x + end return (r+m)*255,(g+m)*255,(b+m)*255,a +end +Color={ +new=function(r,b,g) + if type(r)=="string" then + r,b,g=tonumber(string.sub(r,1,2),16),tonumber(string.sub(r,3,4),16),tonumber(string.sub(r,5,6),16) + end + mt = { + __add = function (c1,c2) + return Color.new(c1[1]+c2[1],c1[2]+c2[2],c1[2]+c2[2]) + end, + __sub = function (c1,c2) + return Color.new(c1[1]-c2[1],c1[2]-c2[2],c1[2]-c2[2]) + end, + __mul = function (c1,c2) + return Color.new(c1[1]*c2[1],c1[2]*c2[2],c1[2]*c2[2]) + end, + __div = function (c1,c2) + return Color.new(c1[1]/c2[1],c1[2]/c2[2],c1[2]/c2[2]) + end, + __mod = function (c1,c2) + return Color.new(c1[1]%c2[1],c1[2]%c2[2],c1[2]%c2[2]) + end, + __pow = function (c1,c2) + return Color.new(c1[1]^c2[1],c1[2]^c2[2],c1[2]^c2[2]) + end, + __unm = function (c1) + return Color.new(-c1[1],-c1[2],-c1[2]) + end, + __tostring = function(c) + return "("..c[1]..","..c[2]..","..c[3]..")" + end, + __eq = Color.EQ, + __lt = Color.LT, + __le = Color.LE, + } + local temp = {r/255,b/255,g/255,1} + setmetatable(temp, mt) + return temp +end, +Random=function() + return Color.new(math.random(0,255),math.random(0,255),math.random(0,255)) +end, +EQ = function (c1,c2) + return (c1[1]==c2[1] and c1[2]==c2[2] and c1[2]==c2[2]) +end, +LT = function (c1,c2) + return (c1[1] self.x and x < self.x+self.width and y > self.y and y < self.y+self.height) and (x > _GuiPro.Frames[i].x and x < _GuiPro.Frames[i].x+_GuiPro.Frames[i].width and y > _GuiPro.Frames[i].y and y < _GuiPro.Frames[i].y+_GuiPro.Frames[i].height) and (x > self.x and x < self.x+self.width and y > self.y and y < self.y+self.height ) + -- if not pos then return true end + -- end + -- end + -- end +end +function gui:Clickable() + local x,y,w,h=love.graphics.getScissor() + local mx=love.mouse.getX() + local my=love.mouse.getY() + if _GuiPro. HasStencel then + local obj=_GuiPro.StencelHolder + if self:isDescendant(obj) then + return math.sqrt((mx-obj.x)^2+(my-obj.y)^2)<=(obj.offset.size.x or 0) + end + end + if not(x) then + return true + end + return not(mx>x+w or mxy+h or my ref.x and x < ref.x+ref.width and y > ref.y and y < ref.y+ref.height) and (x > self.x and x < self.x+self.width and y > self.y and y < self.y+self.height and self:Clickable() and (self:eventable() or self:touchable())) then + return true + else + return false + end + else + return false + end +end \ No newline at end of file diff --git a/GuiManager/Core/fromString.int b/GuiManager/Core/fromString.int new file mode 100644 index 0000000..e69de29 diff --git a/GuiManager/Core/full.int b/GuiManager/Core/full.int new file mode 100644 index 0000000..b23738e --- /dev/null +++ b/GuiManager/Core/full.int @@ -0,0 +1,3 @@ +function gui:full() + self:SetDualDim(nil,nil,nil,nil,nil,nil,1,1) +end \ No newline at end of file diff --git a/GuiManager/Core/newBase.int b/GuiManager/Core/newBase.int new file mode 100644 index 0000000..e16bcc4 --- /dev/null +++ b/GuiManager/Core/newBase.int @@ -0,0 +1,167 @@ +_GuiPro.Frames = {} +_GuiPro.Type = "Window" +_GuiPro.depth = 0 +function gui.enableAutoWindowScaling(b) + _GuiPro.DPI_ENABLED=b or true + _defaultfont=love.graphics.newFont(12*love.window.getPixelScale()) +end +function filter(name, x, y, w, h, sx ,sy ,sw ,sh) + if type(name)~="string" then + sh=sw + sw=sy + sy=sx + sx=h + h=w + w=y + y=x + x=name + end + return x,y,w,h,sx,sy,sw,sh +end +function gui:getChildren() + return self.Children +end +function gui:newBase(tp,name, x, y, w, h, sx ,sy ,sw ,sh) + _GuiPro.count=_GuiPro.count+1 + local c = {} + setmetatable(c, gui) + if self==gui then + c.Parent=_GuiPro + else + c.Parent=self + end + if tp:match("Frame") then + _GuiPro.Frames[#_GuiPro.Frames+1] = c + end + if self.Type and self.Type:match("Frame") then + c.FrameRef = self + else + c.FrameRef = self.FrameRef + end + c.segments=nil + c.ry=nil + c.rx=nil + c.DPI=1 + c.isLeaf = true + c.Parent.isLeaf = false + if _GuiPro.DPI_ENABLED then + c.DPI=love.window.getPixelScale() + x, y, w, h=c.DPI*x,c.DPI*y,c.DPI*w,c.DPI*h + end + c.centerFontY=true + c.FormFactor="rectangle" + c.Type=tp + c.Active=true + c.form="rectangle" + c.Draggable=false + c.Name=name or "Gui"..tp + c:SetName(name) + c.BorderSize=1 + c.BorderColor={0,0,0} + c.VIS=true + c.Visible=true + c.oV=true + c.Children={} + c.hovering=false + c.rclicked=false + c.lclicked=false + c.mclicked=false + c.clicked=false + c.Visibility=1 + c.TextWrap=true + c.scale={} + c.scale.size={} + c.scale.size.x=sw or 0 + c.scale.size.y=sh or 0 + c.offset={} + c.offset.size={} + c.offset.size.x=w or 0 + c.offset.size.y=h or 0 + c.scale.pos={} + c.scale.pos.x=sx or 0 + c.scale.pos.y=sy or 0 + c.offset.pos={} + c.offset.pos.x=x or 0 + c.offset.pos.y=y or 0 + c.width = 0 + c.height = 0 + c.LRE=false + c.RRE=false + c.MRE=false + c.Color = {255, 255, 255} + function c:setRoundness(rx,ry,segments) + self.segments=segments + self.ry=ry + self.rx=rx + end + function c.stfunc() + love.graphics.rectangle("fill", c.x, c.y, c.width, c.height,c.rx,c.ry,c.segments) + end + function c:hasRoundness() + return (self.ry or self.rx) + end + c.tid={} + c.touchcount=0 + c.x=(c.Parent.width*c.scale.pos.x)+c.offset.pos.x+c.Parent.x + c.y=(c.Parent.height*c.scale.pos.y)+c.offset.pos.y+c.Parent.y + c.width=(c.Parent.width*c.scale.size.x)+c.offset.size.x + c.height=(c.Parent.height*c.scale.size.y)+c.offset.size.y + function c:ImageRule() + if self.Image then + local sx=self.width/self.ImageWidth + local sy=self.height/self.ImageHeigth + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.ImageVisibility*255) + if self.width~=self.ImageWidth and self.height~=self.ImageHeigth then + love.graphics.draw(self.Image,self.x,self.y,math.rad(self.rotation),sx,sy) + else + love.graphics.draw(self.Image,self.Quad,self.x,self.y,math.rad(self.rotation),sx,sy) + end + end + end + function c:VideoRule() + if self.Video then + local sx=self.width/self.VideoWidth + local sy=self.height/self.VideoHeigth + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.VideoVisibility*255) + if self.width~=self.VideoWidth and self.height~=self.VideoHeigth then + love.graphics.draw(self.Video,self.x,self.y,math.rad(self.rotation),sx,sy) + else + love.graphics.draw(self.Video,self.Quad,self.x,self.y,math.rad(self.rotation),sx,sy) + end + end + end + function c:repeatImage(b,b2) + if b then + self.Image:setWrap(b,b2 or "repeat") + function self:ImageRule() + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.ImageVisibility*255) + love.graphics.draw(self.Image,self.Quad,self.x,self.y,math.rad(self.rotation)) + end + else + sx=self.width/self.ImageWidth + sy=self.height/self.ImageHeigth + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.ImageVisibility*255) + love.graphics.draw(self.Image,self.Quad,self.x,self.y,math.rad(self.rotation),sx,sy) + end + end + function c:Mutate(t) + for i,v in pairs(t) do + _GuiPro.self=self + if type(i)=="number" then + loadstring("_GuiPro.self:"..v)() + elseif i:match"__self__" then + local ind=i:match"__self__(.+)" + if not self[ind] then self[ind]={} end + loadstring("_GuiPro.self."..ind.."=_GuiPro.self:"..v)() + elseif i:match"__child__" then + local ind,child = i:match"__child__(%S-)_(.+)" + self[ind][child]=v + else + self[i]=v + end + end + return self + end + table.insert(c.Parent.Children,c) + return c +end \ No newline at end of file diff --git a/GuiManager/Core/patches.int b/GuiManager/Core/patches.int new file mode 100644 index 0000000..7c8f66a --- /dev/null +++ b/GuiManager/Core/patches.int @@ -0,0 +1,7 @@ +_GuiPro.mousedownfunc=love.mouse.isDown +function love.mouse.isDown(b) + if not(b) then + return false + end + return _GuiPro.mousedownfunc(({["l"]=1,["r"]=2,["m"]=3})[b] or b) +end \ No newline at end of file diff --git a/GuiManager/Core/toString.int b/GuiManager/Core/toString.int new file mode 100644 index 0000000..741685c --- /dev/null +++ b/GuiManager/Core/toString.int @@ -0,0 +1,40 @@ +function gui:toString() -- oh boy this is gonna be painful lol + multi:newThread("saving data: ",function() + local dat=bin.stream("test.dat",false) + function GetAllChildren2(Object) + local Stuff = {} + function Seek(Items) + for i=1,#Items do + --table.insert(Stuff,Items[i]) + for a,v in pairs(Items[i]) do + -- dat:tackE(a.."|"..tostring(v)) + print(a.."|"..tostring(v)) + -- dat.workingfile:flush() + end + thread.skip() + local NItems = Items[i]:getChildren() + if NItems ~= nil then + Seek(NItems) + end + end + end + local Objs = Object:getChildren() + for i=1,#Objs do + -- table.insert(Stuff,Objs[i]) + for a,v in pairs(Objs[i]) do + -- dat:tackE(a.."|"..tostring(v)) + print(Objs[i].Type..":"..a.."|"..tostring(v)) + -- dat.workingfile:flush() + end + thread.skip() + local Items = Objs[i]:getChildren() + if Items ~= nil then + Seek(Items) + end + end + -- dat:tofile("test.dat") + return Stuff + end + GetAllChildren2(self) + end) +end \ No newline at end of file diff --git a/GuiManager/Core/touchManager.int b/GuiManager/Core/touchManager.int new file mode 100644 index 0000000..06259c7 --- /dev/null +++ b/GuiManager/Core/touchManager.int @@ -0,0 +1,204 @@ +--[[WORKING ON +doubleTap - UnFinished! +touchRendering - Broken +]] +function gui:TClickable(mx,my) + local x,y,w,h=love.graphics.getScissor() + if _GuiPro.HasStencel then + local obj=_GuiPro.StencelHolder + if self:isDescendant(obj) then + return math.sqrt((mx-obj.x)^2+(my-obj.y)^2)<=(obj.offset.size.x or 0) + end + end + if not(x) then + return true + end + return not(mx>x+w or mxy+h or my self.x and x < self.x+self.width and y > self.y and y < self.y+self.height and self:TClickable(x,y) and self:eventable()) + end + end + self.id=-1 +end +--multi:newTask(function() -- A bit of post-loading haha + gui.touchpressed=multi:newConnection() + gui.touchreleased=multi:newConnection() + gui.touchmoved=multi:newConnection() + love.touchpressed=Library.convert(love.touchpressed or function() end) + love.touchreleased=Library.convert(love.touchreleased or function() end) + love.touchmoved=Library.convert(love.touchmoved or function() end) + love.touchpressed:inject(function(id, x, y, dx, dy, pressure) gui.touchpressed:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + love.touchreleased:inject(function(id, x, y, dx, dy, pressure) gui.touchreleased:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + love.touchmoved:inject(function(id, x, y, dx, dy, pressure) gui.touchmoved:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + _GuiPro.TouchReady=true + _GuiPro.TouchRegister={} + gui.touchpressed:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if #v.tid==0 then + if (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + v:addTID(id) + v.touchcount=1 + for i=1,#v.ToFuncP do + v.ToFuncP[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + elseif not(v:hasTID(id)) then + if (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + v:addTID(id) + v.touchcount=v.touchcount+1 + for i=1,#v.ToFuncP do + v.ToFuncP[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end + end) + gui.touchreleased:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if v:hasTID(id) then + v:removeTID(id) + for i=1,#v.ToFuncR do + v.ToFuncR[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end) + gui.touchmoved:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if v:hasTID(id) and (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + for i=1,#v.ToFuncM do + v.ToFuncM[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + elseif v:hasTID(id) and not((x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable())) then + v:removeTID(id) + for i=1,#v.ToFuncR do + v.ToFuncR[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end) +--end) +-- now that that is done lets set up some more post loading checks +_GuiPro.int=multi:newProcessor() +_GuiPro.int:Start() +_GuiPro.int:setJobSpeed(.001) +_GuiPro.EXACT=0 +_GuiPro.LAX=.01 +_GuiPro.LAZY=.05 +-- now lets define the reg function +function gui.Compare(a,b,v,tp) + if tp==">" then + if (a+v>b or a-v>b) then + return true + end + elseif tp=="<" then + if (a+v=" then + if (a+v>=b or a-v>=b) then + return true + end + elseif tp=="==" then -- this one is gonna be tricky + if (a>=b-v and a<=b+v) or (b>=a-v and b<=a+v) then + return true + end + end + return false +end +function gui:regesterTouch() + local obj=self + obj.ToFuncP={} + obj.ToFuncM={} + obj.ToFuncR={} + obj.To2Func={} + obj.ToDTFunc={} + obj.touchRendering =_GuiPro.EXACT -- exact(0), lax(), # + function obj:removeTID(id) + for i=1,#self.tid do + if self.tid[i]==id then + table.remove(self.tid,i) + self.touchcount=self.touchcount-1 + return + end + end + end + function obj:hasTID(id) + for i=1,#self.tid do + if self.tid[i]==id then + return true + end + end + return false + end + obj.txl1=0 + obj.tyl1=0 + obj.txl2=0 + obj.tyl2=0 + obj.LS=0 + obj:OnUpdate(function(self) + if self.touchcount==2 then + local x1,y1=love.touch.getPosition( self.tid[1] ) + local x2,y2=love.touch.getPosition( self.tid[2] ) + local CS=math.sqrt((x2-x1)^2+(y2-y1)^2) + if gui.Compare(CS,self.LS,self.touchRendering,">") then + for i=1,#self.To2Func do + self.To2Func[i](self,CS,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + elseif gui.Compare(CS,self.LS,self.touchRendering,"<") then + for i=1,#self.To2Func do + self.To2Func[i](self,-CS,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + elseif gui.Compare(CS,self.LS,self.touchRendering,"==") then + for i=1,#self.To2Func do + self.To2Func[i](self,0,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + end + -- if self.txl1~=x1 or self.txl2~=x2 or self.tyl1~=y1 or self.tyl2~=y2 then + -- for i=1,#self.To2Func do + -- self.To2Func[i](self,0,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + -- end + -- end + self.LS=CS + self.txl1=x1 + self.txl2=x2 + self.tyl1=y1 + self.tyl2=y2 + end + end) + function obj:OnDoubleTap(func) + table.insert(self.ToDTFunc,func) + end + function obj:On2TouchMoved(func) + table.insert(self.To2Func,func) + end + function obj:addTID(id) + table.insert(self.tid,id) + end + function obj:OnTouchPressed(func) + table.insert(self.ToFuncP,func) -- event for touches + end + function obj:OnTouchReleased(func) -- event for touches + table.insert(self.ToFuncR,func) + end + function obj:OnTouchMoved(func) -- event for touches + table.insert(self.ToFuncM,func) + end + if _GuiPro.TouchReady then -- my sneaky test + print("Registred: "..tostring(obj)) + table.insert(_GuiPro.TouchRegister,obj) + else + print("Attempting to register: "..tostring(obj)) + _GuiPro.int:newJob(function() table.insert(_GuiPro.TouchRegister,obj) end) -- a sneaky way to ensure that your object gets registered eventually, even if you call the method before the touch patch was activated. + end +end diff --git a/GuiManager/Drawing/AddDrawRuleB.int b/GuiManager/Drawing/AddDrawRuleB.int new file mode 100644 index 0000000..5510a3d --- /dev/null +++ b/GuiManager/Drawing/AddDrawRuleB.int @@ -0,0 +1,4 @@ +function gui:AddDrawRuleB(rule) + if not(self.DrawRulesB) then self.DrawRulesB={} end + table.insert(self.DrawRulesB,rule) +end \ No newline at end of file diff --git a/GuiManager/Drawing/AddDrawRuleE.int b/GuiManager/Drawing/AddDrawRuleE.int new file mode 100644 index 0000000..a025f89 --- /dev/null +++ b/GuiManager/Drawing/AddDrawRuleE.int @@ -0,0 +1,4 @@ +function gui:AddDrawRuleE(rule) + if not(self.DrawRulesE) then self.DrawRulesE={} end + table.insert(self.DrawRulesE,rule) +end \ No newline at end of file diff --git a/GuiManager/Drawing/canvas.int b/GuiManager/Drawing/canvas.int new file mode 100644 index 0000000..e69de29 diff --git a/GuiManager/Drawing/draw.int b/GuiManager/Drawing/draw.int new file mode 100644 index 0000000..d0b2404 --- /dev/null +++ b/GuiManager/Drawing/draw.int @@ -0,0 +1,12 @@ +function gui:draw() + if _GuiPro.rotate~=0 then + love.graphics.rotate(math.rad(_GuiPro.rotate)) + end + if self.FormFactor:lower()=="rectangle" then + self:drawR() + elseif self.FormFactor:lower()=="circle" then + self:drawC() + else + error("Unsupported FormFactor: "..self.FormFactor.."!") + end +end \ No newline at end of file diff --git a/GuiManager/Drawing/drawC.int b/GuiManager/Drawing/drawC.int new file mode 100644 index 0000000..95febad --- /dev/null +++ b/GuiManager/Drawing/drawC.int @@ -0,0 +1,89 @@ +function gui:drawC() + if love.mouse.isDown("l")==false and love.mouse.isDown("m")==false and love.mouse.isDown("r")==false then + _GuiPro.DragItem={} + _GuiPro.hasDrag=false + end + if self.Visible==true and self.VIS==true then + local b=true + for i,v in pairs(_GuiPro.Clips) do + if self:isDescendant(v)==true then + b=false + end + end + if b then + love.graphics.setStencilTest( ) + _GuiPro.HasStencel=false + _GuiPro.StencelHolder=nil + end + local x,y,r,s=(self.offset.pos.x or 0)+self.Parent.x,(self.offset.pos.y or 0)+self.Parent.y,self.offset.size.x or 0,self.offset.size.y or 360 + if self.CC then + x,y=x+r,y+r + end + self.x,self.y=x,y + _GuiPro.circleStencilFunction = function() + love.graphics.circle("fill",x,y,r,s) + end + if math.sqrt((love.mouse.getX()-x)^2+(love.mouse.getY()-y)^2)<=r and self:eventable() and self:Clickable() and self.Active==true then + self.hovering=true + if love.mouse.isDown("l") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.lclicked=true + elseif love.mouse.isDown("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.rclicked=true + elseif love.mouse.isDown("m") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.mclicked=true + else + if string.find(self.Type, "Button") and _GuiPro.hasDrag==false then + love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + self.hovering=false + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + if self.ClipDescendants==true then + _GuiPro.Clips[tostring(self)]=self + _GuiPro.HasStencel=true + _GuiPro.StencelHolder=self + love.graphics.stencil(_GuiPro.circleStencilFunction) + love.graphics.setStencilTest("notequal",0) + end + love.graphics.circle("fill",x,y,r,s) + love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],(self.BorderVisibility or 1)) + for b=0,self.BorderSize-1 do + love.graphics.circle("line",x,y,r+b,s) + end + if string.find(self.Type, "Text") then + if self.text~=nil then + if self.AutoScaleText then + self.FontSize=math.floor(self.height/1.45833) + end + love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility) + love.graphics.setFont(self.Font) + love.graphics.printf(self.text, x-(r/2)+(self.XTween), y-(r/2)+self.Tween, r, self.TextFormat) + end + end + end +end \ No newline at end of file diff --git a/GuiManager/Drawing/drawR.int b/GuiManager/Drawing/drawR.int new file mode 100644 index 0000000..b9e6273 --- /dev/null +++ b/GuiManager/Drawing/drawR.int @@ -0,0 +1,73 @@ +function gui:drawR() + if love.mouse.isDown("l")==false and love.mouse.isDown("m")==false and love.mouse.isDown("r")==false then + _GuiPro.DragItem={} + _GuiPro.hasDrag=false + end + if self.hidden then + self.x=(self.Parent.width*self.scale.pos.x)+self.offset.pos.x+self.Parent.x + self.y=(self.Parent.height*self.scale.pos.y)+self.offset.pos.y+self.Parent.y + self.width=(self.Parent.width*self.scale.size.x)+self.offset.size.x + self.height=(self.Parent.height*self.scale.size.y)+self.offset.size.y + self.VIS = false + end + if self.Visible==true and self.VIS==true then + self.x=(self.Parent.width*self.scale.pos.x)+self.offset.pos.x+self.Parent.x + self.y=(self.Parent.height*self.scale.pos.y)+self.offset.pos.y+self.Parent.y + self.width=(self.Parent.width*self.scale.size.x)+self.offset.size.x + self.height=(self.Parent.height*self.scale.size.y)+self.offset.size.y + local b=true + for i,v in pairs(_GuiPro.Clips) do + if self:isDescendant(v)==true then + b=false + end + end + if b==true then + love.graphics.setStencilTest() + love.graphics.setScissor() + end + if self.DrawRulesB then + for dr=1,#self.DrawRulesB do + self.DrawRulesB[dr](self) + end + end + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + if self.ClipDescendants==true then + _GuiPro.Clips[tostring(self)]=self + love.graphics.setScissor(self.x, self.y, self.width, self.height) + end + if self:hasRoundness() then + -- love.graphics.stencil(self.stfunc, "replace", 1) + -- love.graphics.setStencilTest("greater", 0) + end + love.graphics.rectangle("fill", self.x, self.y, self.width, self.height,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI) + if string.find(self.Type, "Image") then + self:ImageRule() + end + if self.Type=="Video" then + self:VideoRule() + end + if self:hasRoundness() then + -- love.graphics.setStencilTest() + end + love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],(self.BorderVisibility or 1)) + for b=0,self.BorderSize-1 do + love.graphics.rectangle("line", self.x-(b/2), self.y-(b/2), self.width+b, self.height+b,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI) + end + if string.find(self.Type, "Text") then + if self.text~=nil and self.TextFormat ~= "center" then + love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility) + love.graphics.setFont(self.Font) + love.graphics.printf(self.text, self.x + (self.XTween or 0), self.y + (self.YTween or 0), self.width, self.TextFormat,self.TextRotaion) + elseif self.text~=nil and self.TextFormat == "center" then + love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility) + love.graphics.setFont(self.Font) + love.graphics.printf(self.text, self.x+(self.width-self.Font:getWidth(self.text))/2, self.y+(self.height-self.Font:getHeight())/2, self.width, "left",self.TextRotaion) + end + end + if self.DrawRulesE then + for dr=1,#self.DrawRulesE do + self.DrawRulesE[dr](self) + end + end + end +end \ No newline at end of file diff --git a/GuiManager/Frame/newDropFrame.int b/GuiManager/Frame/newDropFrame.int new file mode 100644 index 0000000..97e4720 --- /dev/null +++ b/GuiManager/Frame/newDropFrame.int @@ -0,0 +1,37 @@ +function gui:newDropFrame(name,x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("DropFrame",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=false + c.funcD={} + function c:GetDroppedItems() + local t=self:getChildren() + local tab={} + for i=1,#t do + if t[i].Type=="TextImageButtonFrameDrag" then + table.insert(tab,t[i]) + end + end + return tab + end + function c:OnDropped(func) + table.insert(self.funcD,func) + end + c:OnUpdate(function(self) + if _GuiPro.DragItem then + if _GuiPro.DragItem.Type=="TextImageButtonFrameDrag" and love.mouse.isDown(_GuiPro.DragItem.dragbut or "m")==false and self:IsHovering() then + local t=_GuiPro.DragItem + _GuiPro.DragItem={} + for i=1,#t.funcD do + t.funcD[i](self,t) + end + for i=1,#self.funcD do + self.funcD[i](self,t) + end + _GuiPro.hasDrag=false + end + end + end) + return c +end \ No newline at end of file diff --git a/GuiManager/Frame/newFrame.int b/GuiManager/Frame/newFrame.int new file mode 100644 index 0000000..5e6b084 --- /dev/null +++ b/GuiManager/Frame/newFrame.int @@ -0,0 +1,8 @@ +function gui:newFrame(name,x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("Frame",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=false + return c +end \ No newline at end of file diff --git a/GuiManager/Frame/newFullFrame.int b/GuiManager/Frame/newFullFrame.int new file mode 100644 index 0000000..5cda200 --- /dev/null +++ b/GuiManager/Frame/newFullFrame.int @@ -0,0 +1,4 @@ +function gui:newFullFrame(name) + name=name or "" + return self:newFrame(name,0,0,0,0,0,0,1,1) +end \ No newline at end of file diff --git a/GuiManager/Frame/newTabFrame.int b/GuiManager/Frame/newTabFrame.int new file mode 100644 index 0000000..9f8f8fe --- /dev/null +++ b/GuiManager/Frame/newTabFrame.int @@ -0,0 +1,59 @@ +function gui:newTabFrame(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=gui:newFrame(name, x, y, w, h, sx ,sy ,sw ,sh) + c.tabheight=20 + c.Holder=c:newFrame("Holder",0,c.tabheight,0,0,0,0,1,1) + c.TabHolder=c:newFrame("TabHolder",0,0,0,c.tabheight,0,0,1) + function c:setTabHeight(n) + self.tabheight=n + self.Holder:SetDualDim(0,-self.tabheight,0,0,0,0,1,1) + end + function c:addTab(name,colorT,colorH) + if colorT and not(colorH) then + colorH=colorT + end + local tab=self.TabHolder:newTextButton(name,name,0,0,0,0,0,0,0,1) + tab.Tween=-3 + if colorT then + tab.Color=colorT + end + local holder=self.Holder:newFrame(name,0,0,0,0,0,0,1,1) + if colorH then + holder.Color=colorH + end + tab.frame=holder + tab:OnReleased(function(b,self) + if b=="l" then + local tt=self.Parent:getChildren() + local th=self.Parent.Parent.Holder:getChildren() + for i=1,#th do + th[i].Visible=false + end + for i=1,#tt do + tt[i].frame.Visible=false + tt[i].BorderSize=1 + end + self.BorderSize=0 + self.frame.Visible=true + end + end) + local tt=self.TabHolder:getChildren() + for i=1,#tt do + tt[i].frame.Visible=false + tt[i].BorderSize=1 + end + tab.frame.Visible=true + tab.BorderSize=0 + return tab,holder + end + c:OnUpdate(function(self) + local th=self.TabHolder:getChildren() + local l=self.width/#th + for i=1,#th do + th[i]:SetDualDim(l*(i-1),0,l) + end + if #th==0 then + self:Destroy() + end + end) + return c +end \ No newline at end of file diff --git a/GuiManager/Frame/newratioFrame.int b/GuiManager/Frame/newratioFrame.int new file mode 100644 index 0000000..e69de29 diff --git a/GuiManager/GuiManager.lua b/GuiManager/GuiManager.lua new file mode 100644 index 0000000..4b1ab1e --- /dev/null +++ b/GuiManager/GuiManager.lua @@ -0,0 +1,4115 @@ +utf8 = require("utf8") +gui = {} +gui.__index = gui +gui.TB={} +gui.Version="9.0.0" -- Is it really ready for release? +_GuiPro={GBoost=true,hasDrag=false,DragItem={},Children={},Visible=true,count=0,x=0,y=0,height=0,width=0,update=function(self) local things=GetAllChildren2(self) UpdateThings(things) end,draw=function(self) local things=GetAllChildren(self) DrawThings(things) end,getChildren=function(self) return self.Children end} +_GuiPro.Clips={} +_GuiPro.rotate=0 +_defaultfont = love.graphics.setNewFont(12) +setmetatable(_GuiPro, gui) +function gui:LoadInterface(file) + local add=".int" + if string.find(file,".",1,true) then add="" end + if love.filesystem.getInfo(file..add) then + a,b=pcall(love.filesystem.load(file..add)) + if a then + --print("Loaded: "..file) + else + print("Error loading file: "..file) + print(a,b) + end + else + print("File does not exist!") + return false + end +end +function gui.LoadAll(dir) + files=love.filesystem.getDirectoryItems(dir) + for i=1,#files do + if string.sub(files[i],-4)==".int" then + gui:LoadInterface(dir.."/"..files[i]) + end + end +end + +function gui:Clickable() + local x,y,w,h=love.graphics.getScissor() + local mx=love.mouse.getX() + local my=love.mouse.getY() + if _GuiPro.HasStencel then + local obj=_GuiPro.StencelHolder + if self:isDescendant(obj) then + return math.sqrt((mx-obj.x)^2+(my-obj.y)^2)<=(obj.offset.size.x or 0) + end + end + if not(x) then + return true + end + return not(mx>x+w or mxy+h or myx+w or mxy+h or my self.x and x < self.x+self.width and y > self.y and y < self.y+self.height and self:TClickable(x,y) and self:eventable()) + end + end + self.id=-1 +end +multi:newTask(function() -- A bit of post-loading haha + gui.touchpressed=multi:newConnection() + gui.touchreleased=multi:newConnection() + gui.touchmoved=multi:newConnection() + love.touchpressed=Library.convert(love.touchpressed or function() end) + love.touchreleased=Library.convert(love.touchreleased or function() end) + love.touchmoved=Library.convert(love.touchmoved or function() end) + love.touchpressed:inject(function(id, x, y, dx, dy, pressure) gui.touchpressed:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + love.touchreleased:inject(function(id, x, y, dx, dy, pressure) gui.touchreleased:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + love.touchmoved:inject(function(id, x, y, dx, dy, pressure) gui.touchmoved:Fire(id, x, y, dx, dy, pressure) return {id, x, y, dx, dy, pressure} end,1) + _GuiPro.TouchReady=true + _GuiPro.TouchRegister={} + gui.touchpressed:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if #v.tid==0 then + if (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + v:addTID(id) + v.touchcount=1 + for i=1,#v.ToFuncP do + v.ToFuncP[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + elseif not(v:hasTID(id)) then + if (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + v:addTID(id) + v.touchcount=v.touchcount+1 + for i=1,#v.ToFuncP do + v.ToFuncP[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end + end) + gui.touchreleased:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if v:hasTID(id) then + v:removeTID(id) + for i=1,#v.ToFuncR do + v.ToFuncR[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end) + gui.touchmoved:connect(function(id, x, y, dx, dy, pressure) + for i,v in pairs(_GuiPro.TouchRegister) do + if v:hasTID(id) and (x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable()) then + for i=1,#v.ToFuncM do + v.ToFuncM[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + elseif v:hasTID(id) and not((x > v.x and x < v.x+v.width and y > v.y and y < v.y+v.height and v:TClickable(x,y) and v:eventable())) then + v:removeTID(id) + for i=1,#v.ToFuncR do + v.ToFuncR[i](v,id, x-v.x, y-v.y, dx, dy or 0, pressure or 1) + end + end + end + end) +end) +-- now that that is done lets set up some more post loading checks +_GuiPro.int=multi:newProcess() +_GuiPro.int:Start() +_GuiPro.int:setJobSpeed(.001) +_GuiPro.EXACT=0 +_GuiPro.LAX=.01 +_GuiPro.LAZY=.05 +-- now lets define the reg function +function gui.Compare(a,b,v,tp) + if tp==">" then + if (a+v>b or a-v>b) then + return true + end + elseif tp=="<" then + if (a+v=" then + if (a+v>=b or a-v>=b) then + return true + end + elseif tp=="==" then -- this one is gonna be tricky + if (a>=b-v and a<=b+v) or (b>=a-v and b<=a+v) then + return true + end + end + return false +end +function gui:regesterTouch() + local obj=self + obj.ToFuncP={} + obj.ToFuncM={} + obj.ToFuncR={} + obj.To2Func={} + obj.ToDTFunc={} + obj.touchRendering =_GuiPro.EXACT -- exact(0), lax(), # + function obj:removeTID(id) + for i=1,#self.tid do + if self.tid[i]==id then + table.remove(self.tid,i) + self.touchcount=self.touchcount-1 + return + end + end + end + function obj:hasTID(id) + for i=1,#self.tid do + if self.tid[i]==id then + return true + end + end + return false + end + obj.txl1=0 + obj.tyl1=0 + obj.txl2=0 + obj.tyl2=0 + obj.LS=0 + obj:OnUpdate(function(self) + if self.touchcount==2 then + local x1,y1=love.touch.getPosition( self.tid[1] ) + local x2,y2=love.touch.getPosition( self.tid[2] ) + local CS=math.sqrt((x2-x1)^2+(y2-y1)^2) + if gui.Compare(CS,self.LS,self.touchRendering,">") then + for i=1,#self.To2Func do + self.To2Func[i](self,CS,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + elseif gui.Compare(CS,self.LS,self.touchRendering,"<") then + for i=1,#self.To2Func do + self.To2Func[i](self,-CS,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + elseif gui.Compare(CS,self.LS,self.touchRendering,"==") then + for i=1,#self.To2Func do + self.To2Func[i](self,0,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + end + end + -- if self.txl1~=x1 or self.txl2~=x2 or self.tyl1~=y1 or self.tyl2~=y2 then + -- for i=1,#self.To2Func do + -- self.To2Func[i](self,0,x1-self.x,y1-self.y,x2-self.x,y2-self.y) + -- end + -- end + self.LS=CS + self.txl1=x1 + self.txl2=x2 + self.tyl1=y1 + self.tyl2=y2 + end + end) + function obj:OnDoubleTap(func) + table.insert(self.ToDTFunc,func) + end + function obj:On2TouchMoved(func) + table.insert(self.To2Func,func) + end + function obj:addTID(id) + table.insert(self.tid,id) + end + function obj:OnTouchPressed(func) + table.insert(self.ToFuncP,func) -- event for touches + end + function obj:OnTouchReleased(func) -- event for touches + table.insert(self.ToFuncR,func) + end + function obj:OnTouchMoved(func) -- event for touches + table.insert(self.ToFuncM,func) + end + if _GuiPro.TouchReady then -- my sneaky test + print("Registred: "..tostring(obj)) + table.insert(_GuiPro.TouchRegister,obj) + else + print("Attempting to register: "..tostring(obj)) + _GuiPro.int:newJob(function() table.insert(_GuiPro.TouchRegister,obj) end) -- a sneaky way to ensure that your object gets registered eventually, even if you call the method before the touch patch was activated. + end +end + +function UpdateThings(items) + for i=#items,1,-1 do + if items[i]:LClicked() then + for g=1,#items[i].funcs do + items[i].funcs[g]("l",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif items[i]:RClicked() then + for g=1,#items[i].funcs do + items[i].funcs[g]("r",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif items[i]:MClicked() then + for g=1,#items[i].funcs do + items[i].funcs[g]("m",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + end + if not(items[i]:LClicked()) and items[i].LRE then + for g=1,#items[i].funcs2 do + items[i].funcs2[g]("l",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif not(items[i]:RClicked()) and items[i].RRE then + for g=1,#items[i].funcs2 do + items[i].funcs2[g]("r",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif not(items[i]:MClicked()) and items[i].MRE then + for g=1,#items[i].funcs2 do + items[i].funcs2[g]("m",items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + end + if items[i]:Hovering() and items[i].HE==false then + for g=1,#items[i].funcs3 do + items[i].funcs3[g](items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif not(items[i]:Hovering()) and items[i].HE==true then + for g=1,#items[i].funcs4 do + items[i].funcs4[g](items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + elseif items[i]:Hovering() then + for g=1,#items[i].func9 do + items[i].func9[g](items[i],love.mouse.getX()-items[i].x,love.mouse.getY()-items[i].y) + end + end + for g=1,#items[i].funcs5 do + items[i].funcs5[g](items[i]) + end + end +end +function GetAllChildren(Object) + local Stuff = {} + function Seek(Items) + for i=1,#Items do + if Items[i].Visible==true then + table.insert(Stuff,Items[i]) + local NItems = Items[i]:getChildren() + if NItems ~= nil then + Seek(NItems) + end + end + end + end + local Objs = Object:getChildren() + for i=1,#Objs do + if Objs[i].Visible==true then + table.insert(Stuff,Objs[i]) + local Items = Objs[i]:getChildren() + if Items ~= nil then + Seek(Items) + end + end + end + return Stuff +end +function GetAllChildren2(Object) + local Stuff = {} + function Seek(Items) + for i=1,#Items do + table.insert(Stuff,Items[i]) + local NItems = Items[i]:getChildren() + if NItems ~= nil then + Seek(NItems) + end + end + end + local Objs = Object:getChildren() + for i=1,#Objs do + table.insert(Stuff,Objs[i]) + local Items = Objs[i]:getChildren() + if Items ~= nil then + Seek(Items) + end + end + return Stuff +end +function gui:getTile(i,x,y,w,h)-- returns imagedata + if type(i)=="string" then + i=love.graphics.newImage(i) + elseif type(i)=="userdata" then + -- do nothing + elseif string.find(self.Type,"Image",1,true) then + local i,x,y,w,h=self.Image,i,x,y,w + else + error("getTile invalid args!!! Usage: ImageElement:getTile(x,y,w,h) or gui:getTile(imagedata,x,y,w,h)") + end + local iw,ih=i:getDimensions() + local id,_id=i:getData(),love.image.newImageData(w,h) + for _x=x,w+x-1 do + for _y=y,h+y-1 do + -- + _id:setPixel(_x-x,_y-y,id:getPixel(_x,_y)) + end + end + return love.graphics.newImage(_id) +end +function gui:newAnim(file,delay, x, y, w, h, sx ,sy ,sw ,sh) + local x,y,w,h,sx,sy,sw,sh=filter(file, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation",file, x, y, w, h, sx ,sy ,sw ,sh) + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files={} + c.AnimStart={} + c.AnimEnd={} + local _files=alphanumsort(love.filesystem.getDirectoryItems(file)) + for i=1,#_files do + if string.sub(_files[i],-1,-1)~="b" then + table.insert(c.files,love.graphics.newImage(file.."/".._files[i])) + end + end + c.step=multi:newTStep(1,#c.files,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(pos,step) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end +function gui:newAnimFromData(data,delay, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation","FromFile", x, y, w, h, sx ,sy ,sw ,sh) + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files=data + c.AnimStart={} + c.AnimEnd={} + c:SetImage(c.files[1]) + c.step=multi:newTStep(1,#c.files,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(pos,step) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end +function gui:newAnimFromTiles(file,xd,yd,delay, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(file, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation",file, x, y, w, h, sx ,sy ,sw ,sh) + local im=love.graphics.newImage(file) + local _x,_y=im:getDimensions() + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files={} + c.AnimStart={} + c.AnimEnd={} + for i=0,_y/yd-1 do + for j=0,_x/xd-1 do + table.insert(c.files,gui:getTile(im,j*xd,i*yd,xd,yd)) + end + end + c:SetImage(c.files[1]) + c.step=multi:newTStep(1,#c.files,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(pos,step) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end +function gui:newFullImageLabel(i,name) + return self:newImageLabel(i,name,0,0,0,0,0,0,1,1) +end +function gui:newImageButton(i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageButton",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" or type(i):find("ImageData") then + c.Image=love.graphics.newImage(i) + else + c.Image=i + end + c.Visibility=0 + c.ImageVisibility=1 + c.rotation=0 + if c.Image~=nil then + c.ImageHeigth=c.Image:getHeight() + c.ImageHeight=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + c:OnEnter(function() + love.mouse.setCursor(_GuiPro.CursorH) + end) + c:OnExit(function() + love.mouse.setCursor(_GuiPro.CursorN) + end) + return c +end +function gui:newImageLabel(i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageLabel",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" or type(i):find("ImageData") then + c.Image=love.graphics.newImage(i) + else + c.Image=i + end + c.Visibility=0 + c.ImageVisibility=1 + c.rotation=0 + if c.Image then + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + return c +end +function gui:newVideo(name,i,x,y,w,h,sx,sy,sw,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("Video",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Video=love.graphics.newVideo(i) + else + c.Video=i + end + c.Visibility=0 + c.VideoVisibility=1 + c.rotation=0 + if c.Video~=nil then + c.VideoHeigth=c.Video:getHeight() + c.VideoWidth=c.Video:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.VideoWidth,c.VideoHeigth) + end + c.funcV={} + function c:Play() + self.handStart=true + self.Video:play() + end + function c:Pause() + self.Video:pause() + end + c.Resume=c.Play + function c:Stop() + self.handStart=false + self:Pause() + self:Rewind() + for i=1,# self.funcV do + self.funcV[i](self) + end + end + function c:OnVideoStopped(func) + table.insert(self.funcV,func) + end + function c:Rewind() + self.Video:rewind() + end + function c:Restart() + self:Rewind() + self:Play() + end + function c:Seek(o) + self.Video:seek(o) + end + function c:Tell() + self.Video:tell() + end + function c:SetFilter(min, mag, anisotropy) + self.Video:setFilter(min, mag, anisotropy) + end + function c:IsPlaying() + return self.Video:isPlaying() + end + c:OnUpdate(function(self) + if self.Video:isPlaying()==false and self.handStart == true then + self:Stop() + end + end) + return c +end +function gui:SetImage(i) + if type(i)=="string" or tostring(i):find("ImageData") then + self.Image=love.graphics.newImage(i) + else + self.Image=i + end + if self.Image then + self.ImageHeigth=self.Image:getHeight() + self.ImageWidth=self.Image:getWidth() + self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth) + end + return self.ImageWidth,self.ImageHeigth +end +function gui:UpdateImage() + self.ImageHeigth=self.Image:getHeight() + self.ImageWidth=self.Image:getWidth() + self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth) +end +function gui:newDropFrame(name,x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("DropFrame",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=false + c.funcD={} + function c:GetDroppedItems() + local t=self:getChildren() + local tab={} + for i=1,#t do + if t[i].Type=="TextImageButtonFrameDrag" then + table.insert(tab,t[i]) + end + end + return tab + end + function c:OnDropped(func) + table.insert(self.funcD,func) + end + c:OnUpdate(function(self) + if _GuiPro.DragItem then + if _GuiPro.DragItem.Type=="TextImageButtonFrameDrag" and love.mouse.isDown(_GuiPro.DragItem.dragbut or "m")==false and self:IsHovering() then + local t=_GuiPro.DragItem + _GuiPro.DragItem={} + for i=1,#t.funcD do + t.funcD[i](self,t) + end + for i=1,#self.funcD do + self.funcD[i](self,t) + end + _GuiPro.hasDrag=false + end + end + end) + return c +end +function gui:newFrame(name,x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("Frame",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=false + return c +end +function gui:newFullFrame(name) + name=name or "" + return self:newFrame(name,0,0,0,0,0,0,1,1) +end + +function gui:newTabFrame(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=gui:newFrame(name, x, y, w, h, sx ,sy ,sw ,sh) + c.tabheight=20 + c.Holder=c:newFrame("Holder",0,c.tabheight,0,0,0,0,1,1) + c.TabHolder=c:newFrame("TabHolder",0,0,0,c.tabheight,0,0,1) + function c:setTabHeight(n) + self.tabheight=n + self.Holder:SetDualDim(0,-self.tabheight,0,0,0,0,1,1) + end + function c:addTab(name,colorT,colorH) + if colorT and not(colorH) then + colorH=colorT + end + local tab=self.TabHolder:newTextButton(name,name,0,0,0,0,0,0,0,1) + tab.Tween=-3 + if colorT then + tab.Color=colorT + end + local holder=self.Holder:newFrame(name,0,0,0,0,0,0,1,1) + if colorH then + holder.Color=colorH + end + tab.frame=holder + tab:OnReleased(function(b,self) + if b=="l" then + local tt=self.Parent:getChildren() + local th=self.Parent.Parent.Holder:getChildren() + for i=1,#th do + th[i].Visible=false + end + for i=1,#tt do + tt[i].frame.Visible=false + tt[i].BorderSize=1 + end + self.BorderSize=0 + self.frame.Visible=true + end + end) + local tt=self.TabHolder:getChildren() + for i=1,#tt do + tt[i].frame.Visible=false + tt[i].BorderSize=1 + end + tab.frame.Visible=true + tab.BorderSize=0 + return tab,holder + end + c:OnUpdate(function(self) + local th=self.TabHolder:getChildren() + local l=self.width/#th + for i=1,#th do + th[i]:SetDualDim(l*(i-1),0,l) + end + if #th==0 then + self:Destroy() + end + end) + return c +end +function gui:newDragItem(t,i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextImageButtonFrameDrag",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=true + c.funcD={} + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + c.ImageVisibility=1 + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + elseif type(i)=="image" then + c.Image=i + c.ImageVisibility=1 + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + c:OnDragStart(function(self,x,y) + if _GuiPro.hasDrag==false then + self:setParent(_GuiPro) + self:SetDualDim(x,y) + self:TopStack() + end + end) + c.rotation=0 + c.Tween=0 + c.XTween=0 + c.text = t + c.AutoScaleText=false + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.TextVisibility=1 + c.TextColor = {0, 0, 0} + function c:OnDropped(func) + table.insert(self.funcD,func) + end + c:OnUpdate(function(self) + if love.mouse.isDown("m" or self.dragbut)==false and self==_GuiPro.DragItem and self.hovering==false then + _GuiPro.DragItem={} + for i=1,#self.func7 do + self.func7[i](self,(love.mouse.getX())-self.width/2,(love.mouse.getY())-self.height/2) + end + end + end) + return c +end +function gui:newItem(t,i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextImageButtonFrame",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + else + c.Image=i + end + c.rotation=0 + c.ImageVisibility=1 + c.Draggable=false + if c.Image~=nil then + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + c.Tween=0 + c.XTween=0 + c.text = t + c.AutoScaleText=false + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.TextVisibility=1 -- 0=invisible,1=solid (self.TextVisibility*254+1) + c.TextColor = {0, 0, 0} + return c +end +function gui:addDominance() + _GuiPro.TopHovered=self +end +function gui:addHotKey(key) + local temp=self:newFrame(0,0,0,0) + temp.Visible=false + temp:setHotKey(key) + return temp +end +function gui:AdvTextBox(txt,x,y,w,h,sx,sy,sw,sh) + name="AdvTextBox" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("AdvTextBoxFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c.BorderSize=0 + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + --local temp = c:newTextButton("X","Close",-25,5,20,20,1) + --temp.Tween=-5 + --temp.XTween=-2 + --temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + --temp.Color=Color.Red + c.tLink=c:newTextBox("puttext","TextBox",5,h-95,-40,30,0,1,1,1) + c.tLink.Color=Color.light_gray + c.tLink.ClearOnFocus=true + c.tLink:OnFocus(function(self) self.ClearOnFocus=false end) + local temp=c:newTextButton("OK","Ok",-35,h-65,30,30,1,1) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcO do self.Parent.funcO[i](self.Parent,self.Parent.tLink.text) end end) + temp.Color=Color.Green + temp.XTween=-2 + local temp=c:newTextButton("X","Cancel",-35,h-95,30,30,1,1) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent,self.Parent.tLink.text) end end) + temp.Color=Color.Red + temp.XTween=-2 + function c:Close() + self.Visible=false + end + function c:Open() + self.Visible=true + end + function c:OnOk(func) + table.insert(self.funcO,func) + end + function c:OnX(func) + table.insert(self.funcX,func) + end + return c +end +function alphanumsort(o) + local function padnum(d) local dec, n = string.match(d, "(%.?)0*(.+)") + return #dec > 0 and ("%.12f"):format(d) or ("%s%03d%s"):format(dec, #n, n) + end + table.sort(o, function(a,b) return tostring(a):gsub("%.?%d+",padnum)..("%3d"):format(#b)< tostring(b):gsub("%.?%d+",padnum)..("%3d"):format(#a) end) + return o +end +function gui:anchorRight(n) + self:SetDualDim(-(self.width+n),nil,nil,nil,1) +end +function _GuiPro.gradient(colors) + local direction = colors.direction or "horizontal" + colors.direction=nil + trans = colors.trans or 1 + trans=math.floor(trans) + if direction == "horizontal" then + direction = true + elseif direction == "vertical" then + direction = false + else + error("Invalid direction '" .. tostring(direction) "' for gradient. Horizontal or vertical expected.") + end + local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1,"rgba32f") + for __i, color in ipairs(colors) do + local x, y + if direction then + x, y = 0, __i - 1 + else + x, y = __i - 1, 0 + end + result:setPixel(x, y, color[1], color[2], color[3], trans) + end + result = love.graphics.newImage(result) + result:setFilter('linear', 'linear') + return result +end +function _GuiPro.drawinrect(img, x, y, w, h, r, ox, oy, kx, ky) + love.graphics.draw(img, x, y, r, w / img:getWidth(), h / img:getHeight(), ox, oy, kx, ky) +end +function gui:ApplyGradient(rules) + self.Image=nil + self.Type=self.Type.."w/GradImage" + self.rotation=0 + self.ImageVisibility=rules.visibility or 1 + self:SetImage(_GuiPro.gradient(rules)) +end +function gui:BottomStack() + childs=self.Parent:getChildren() + for i=1,#childs do + if childs[i]==self then + table.remove(self.Parent.Children,i) + table.insert(self.Parent.Children,1,self) + break + end + end +end +function gui:center() + self:centerX() + self:centerY() +end +function gui:centerX() + self:SetDualDim(-(self.width/2),nil,nil,nil,.5) +end +function gui:centerY() + self:SetDualDim(nil,-(self.height/2),nil,nil,nil,.5) +end +function gui:Destroy() + check=self.Parent:getChildren() + local cc=0 + for cc=1,#check do + if check[cc]==self then + table.remove(self.Parent.Children,cc) + end + end + self.Destroyed = true +end +function gui:disrespectHierarchy() + _GuiPro.Hierarchy=false +end +function gui:GetAllChildren() + local Stuff = {} + function Seek(Items) + for i=1,#Items do + if Items[i].Visible==true then + table.insert(Stuff,Items[i]) + local NItems = Items[i]:getChildren() + if NItems ~= nil then + Seek(NItems) + end + end + end + end + local Objs = self:getChildren() + for i=1,#Objs do + if Objs[i].Visible==true then + table.insert(Stuff,Objs[i]) + local Items = Objs[i]:getChildren() + if Items ~= nil then + Seek(Items) + end + end + end + return Stuff +end +function gui:GetChild(name) + return self.Children[name] or self +end +function gui:getChildren() + return self.Children +end +function gui:getColor(cindex) + return Color[cindex] +end +function gui:getFullSize() + local maxx,maxy=-math.huge,-math.huge + local temp = self:GetAllChildren() + for i=1,#temp do + if temp[i].width+temp[i].offset.pos.x>maxx then + maxx=temp[i].width+temp[i].offset.pos.x + elseif temp[i].height+temp[i].offset.pos.y>maxy then + maxy=temp[i].height+temp[i].offset.pos.y + end + end + return maxx,maxy +end +function gui:getHighest() + if self.Children[#self.Children]~=nil then + return self.Children[#self.Children] + end +end +function gui:getLowest() + if self.Children[1]~=nil then + return self.Children[1] + end +end +function InGrid(i,x,y,s) + return math.floor((i-1)/x)*s,(i-1)*s-(math.floor((i-1)/y)*(s*x)) +end +function InGridX(i,w,h,xs,ys) + local xc,yc=math.floor(w/xs),math.floor(h/ys) + local xi,yi=(i-1)%xc,math.floor((i-1)/xc) + return xi*xs,yi*ys +end +function InGridY(i,w,h,xs,ys) + local xc,yc=math.floor(w/xs),math.floor(h/ys) + local xi,yi=math.floor((i-1)/yc),(i-1)%yc + return xi*xs,yi*ys +end +function gui:isDescendant(obj) + local things=obj:GetAllChildren() + for i=1,#things do + if things[i]==self then + return true + end + end + return false +end +function gui:isHighest() + return (self==self.Parent:getHighest()) +end +function gui:IsHovering() + return (love.mouse.getX() > self.x and love.mouse.getX() < self.x+self.width and love.mouse.getY() > self.y and love.mouse.getY() < self.y+self.height) +end +function gui:isLowest() + return (self==self.Parent:getLowest()) +end +function gui.massMutate(t,...) + local mut={...} + for i=1,#mut do + mut[i]:Mutate(t) + end +end +function gui:Move(x,y) + self.offset.pos.x=self.offset.pos.x+x + self.offset.pos.y=self.offset.pos.y+y +end +if love.filesystem.getInfo("CheckBoxes.png") then + _GuiPro.UC=gui:getTile("CheckBoxes.png",0,0,16,16) + _GuiPro.C=gui:getTile("CheckBoxes.png",16,0,16,16) + _GuiPro.UCH=gui:getTile("CheckBoxes.png",0,16,16,16) + _GuiPro.CH=gui:getTile("CheckBoxes.png",16,16,16,16) +end +function gui:newCheckBox(name,x,y) + if not(_GuiPro.UC) then error("CheckBoxes.png not found! Cannot currently use checkbox without the data") end + if type(name)~="String" then + x,y,name=name,x,"CheckBox" + end + local c=self:newImageLabel(_GuiPro.UC,name, x, y, 16,16) + c.Visibility=0 + c.check=false + c:OnEnter(function(self) + if self.check then + self:SetImage(_GuiPro.CH) + else + self:SetImage(_GuiPro.UCH) + end + end) + function c:isChecked() + return self.check + end + c:OnExit(function(self) + if self.check then + self:SetImage(_GuiPro.C) + else + self:SetImage(_GuiPro.UC) + end + end) + c:OnReleased(function(b,self) + self.check=not(self.check) + if self.check then + self:SetImage(_GuiPro.CH) + else + self:SetImage(_GuiPro.UCH) + end + end) + return c +end +function gui:newMessageBox(txt,x,y,w,h,sx,sy,sw,sh) + name="MessageBox" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("MessageBoxFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c.BorderSize=0 + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + local temp = c:newTextButton("X","Close",-25,5,20,20,1) + temp.Tween=-5 + temp.XTween=-2 + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + temp.Color=Color.Red + local temp=c:newTextButton("OK","Ok",0,h-65,0,30,.25,1,.5) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcO do self.Parent.funcO[i](self.Parent) end end) + temp.Color=Color.Green + function c:Close() + self.Visible=false + end + function c:Open() + self.Visible=true + end + function c:OnOk(func) + table.insert(self.funcO,func) + end + function c:OnX(func) + table.insert(self.funcX,func) + end + return c +end +function gui:newPart(x, y,w ,h , sx ,sy ,sw ,sh) + local c = {} + setmetatable(c, gui) + if self==gui then + c.Parent=_GuiPro + else + c.Parent=self + end + c.funcs={} + c.funcs2={} + c.funcs3={} + c.funcs4={} + c.funcs5={} + c.func6={} + c.func7={} + c.func8={} + c.func9={} + c.func10={} + c.form="rectangle" + c.Color = {255, 255, 255} + c.scale={} + c.scale.size={} + c.scale.size.x=sw or 0 + c.scale.size.y=sh or 0 + c.offset={} + c.offset.size={} + c.offset.size.x=w or 0 + c.offset.size.y=h or 0 + c.scale.pos={} + c.scale.pos.x=sx or 0 + c.scale.pos.y=sy or 0 + c.offset.pos={} + c.offset.pos.x=x or 0 + c.offset.pos.y=y or 0 + c.VIS=true + c.Visible=true + c.Visibility=1 + c.BorderColor={0,0,0} + c.BorderSize=0 + c.Type="Part" + c.Name="GuiPart" + _GuiPro.count=_GuiPro.count+1 + c.x=(c.Parent.width*c.scale.pos.x)+c.offset.pos.x+c.Parent.x + c.y=(c.Parent.height*c.scale.pos.y)+c.offset.pos.y+c.Parent.y + c.width=(c.Parent.width*c.scale.size.x)+c.offset.size.x + c.height=(c.Parent.height*c.scale.size.y)+c.offset.size.y + table.insert(c.Parent.Children,c) + return c +end +function gui:newProgressBar(txt,x,y,w,h,sx,sy,sw,sh) + name="newProgressBar" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("newProgressBarFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c.BorderSize=0 + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + local temp = c:newTextButton("X","Close",-25,5,20,20,1) + temp.Tween=-5 + temp.XTween=-2 + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + temp.Color=Color.Red + c.BarBG=c:newTextButton("",5,h-65,-10,30,0,1,1) + c.BarBG:ApplyGradient{Color.Red,Color.light_red} + c.Bar=c.BarBG:newTextLabel("",0,0,0,0,0,0,0,1) + c.Bar:ApplyGradient{Color.Green,Color.light_green} + c.BarDisp=c.BarBG:newTextLabel("0%","0%",0,0,0,0,0,0,1,1) + c.BarDisp.Visibility=0 + c.BarDisp.Link=c.Bar + c.BarDisp:OnUpdate(function(self) + self.text=self.Link.scale.size.x*100 .."%" + end) + c.Func1={} + function c:On100(func) + table.insert(self.Func1,func) + end + c:OnUpdate(function(self) + if self.Bar.scale.size.x*100>=100 then + for P=1,#self.Func1 do + self.Func1[P](self) + end + end + end) + function c:SetPercentage(n) + self.Bar:SetDualDim(0,0,0,0,0,0,n/100,1) + end + return c +end +function gui:newScrollBar(color1,color2) + local scrollbar=self:newFrame(-20,0,20,0,1,0,0,1) + scrollbar.funcS={} + scrollbar.Color=color1 or Color.saddle_brown + scrollbar:OnClicked(function(b,self,x,y) + love.mouse.setX(self.x+10) + if y>=10 and y<=self.height-10 then + self.mover:SetDualDim(0,y-10) + end + if y<10 then + love.mouse.setY(10+self.y) + end + if y>self.height-10 then + love.mouse.setY((self.height-10)+self.y) + end + for i=1,#self.funcS do + self.funcS[i](self,self:getPosition()) + end + end) + scrollbar:OnEnter(function(self) + self:addDominance() + end) + scrollbar:OnExit(function(self) + self:removeDominance() + end) + scrollbar.mover=scrollbar:newTextButton("","",0,0,20,20) + scrollbar.mover.Color=color2 or Color.light_brown + function scrollbar:getPosition() + return ((self.mover.offset.pos.y)/(self.height-20))*100 + end + function scrollbar:setPosition(n) + print((self.height-20),n) + self.mover.offset.pos.y=((self.height-20)/(100/n)) + for i=1,#self.funcS do + self.funcS[i](self,self:getPosition()) + end + end + function scrollbar:OnScroll(func) + table.insert(self.funcS,func) + end + return scrollbar +end +function gui:newScrollMenu(title,tabN,onloop,x, y, w, h, sx ,sy ,sw ,sh) + local Main = self:newFrame(x, y, w, h, sx ,sy ,sw ,sh) + local Title=Main:newTextButton(title,"Title",0,0,0,20,0,0,1) + Title.Tween=-4 + Title.FontSize=12 + Title:OnReleased(function(b,self) + self.Parent.Tick=not(self.Parent.Tick) + end) + local scroll=Main:newTextButton("","Scroll",-20,20,20,-20,1,0,0,1) + scroll:OnClicked(function(b,self,x,y) + self.Parent.Mover:SetDualDim(0,y-10,20,20) + if self.Parent.Mover.offset.pos.y<0 then + self.Parent.Mover:SetDualDim(0,0,20,20) + end + if self.Parent.Mover.offset.pos.y>self.Parent.height-40 then + self.Parent.Mover:SetDualDim(0,self.Parent.height-40,20,20) + end + local temp = #self.Parent.TList + self.Parent.pos=(math.floor((temp*self.Parent.Mover.offset.pos.y)/self.height))+1 + end) + Main:OnUpdate(function(self) + if self.Tick==false then + self.Visibility=0 + end + end) + scroll:OnUpdate(function(self) + self.Visible=self.Parent.Tick + end) + local Mover=scroll:newTextLabel("",0,0,20,20) + Main.Mover=Mover + Main.TList=tabN + Main.pos=1 + Main.Tick=true + function Main:Update(title,tabN,onloop) + ch=self:getChildren() + for i=#ch,1,-1 do + ch[i]:Destroy() + end + Title=Main:newTextButton(title,"Title",0,0,0,20,0,0,1) + Title.Tween=-4 + Title.FontSize=12 + Title:OnReleased(function(b,self) + self.Parent.Tick=not(self.Parent.Tick) + end) + scroll=Main:newTextButton("","Scroll",-20,20,20,-20,1,0,0,1) + scroll:OnClicked(function(b,self,x,y) + self.Parent.Mover:SetDualDim(0,y-10,20,20) + if self.Parent.Mover.offset.pos.y<0 then + self.Parent.Mover:SetDualDim(0,0,20,20) + end + if self.Parent.Mover.offset.pos.y>self.Parent.height-40 then + self.Parent.Mover:SetDualDim(0,self.Parent.height-40,20,20) + end + local temp = #self.Parent.TList + self.Parent.pos=(math.floor((temp*self.Parent.Mover.offset.pos.y)/self.height))+1 + end) + local Mover=scroll:newTextLabel("",0,0,20,20) + Main.Mover=Mover + Main.TList=tabN + Main.pos=1 + Main.Tick=true + scroll:OnUpdate(function(self) + self.Visible=self.Parent.Tick + end) + for i=1,math.floor(Main.height/20)-1 do + local temp=Main:newTextButton("","Item"..i,0,i*20,-20,20,0,0,1) + temp.FontSize=10 + temp.Tween=-4 + temp.pos=i + temp:OnUpdate(function(self) + self.text=self.Parent.TList[(self.Parent.pos+self.pos)-1] + self.Visible=self.Parent.Tick + end) + if onloop then + onloop(temp,i) + end + end + end + io.write(tostring(Main.height).."\n") + for i=1,math.floor(Main.height/20)-1 do + local temp=Main:newTextButton("Item"..i,0,i*20,-20,20,0,0,1) + temp.FontSize=10 + temp.Tween=-4 + temp.pos=i + temp:OnUpdate(function(self) + if self.Parent.TList[(self.Parent.pos+self.pos)-1]~=nil then + self.text=self.Parent.TList[(self.Parent.pos+self.pos)-1] + else + self.text="" + end + self.Visible=self.Parent.Tick + end) + if onloop then + onloop(temp,i) + end + end + return Main +end +function gui:destroyAllChildren() + local c=self.Children + for i=1,#c do + c[i]:Destroy() + end +end +function gui:removeDominance() + _GuiPro.TopHovered=nil +end +function gui:respectHierarchy() + _GuiPro.Hierarchy=true +end +function gui.round(num, idp) + local mult = 10^(idp or 0) + return math.floor(num * mult + 0.5) / mult +end +function gui.setBG(i) + gui.ff:SetImage(i) +end +function gui:setColor(a,b,c) + if type(a)=="string" then + self.Color=Color[a] + elseif type(a)=="number" then + self.Color=Color.new(a,b,c) + end +end +function gui:setTextColor(a,b,c) + if type(a)=="string" then + self.TextColor=Color[a] + elseif type(a)=="number" then + self.TextColor=Color.new(a,b,c) + end +end +function gui:setDefualtFont(font) + _defaultfont = font +end +function gui:SetDualDim(x, y, w, h, sx ,sy ,sw ,sh) + if _GuiPro.DPI_ENABLED then + if x then + x=self.DPI*x + end + if y then + y=self.DPI*y + end + if w then + w=self.DPI*w + end + if h then + h=self.DPI*h + end + end + if sx then + self.scale.pos.x=sx + end + if sy then + self.scale.pos.y=sy + end + if x then + self.offset.pos.x=x + end + if y then + self.offset.pos.y=y + end + if sw then + self.scale.size.x=sw + end + if sh then + self.scale.size.y=sh + end + if w then + self.offset.size.x=w + end + if h then + self.offset.size.y=h + end + if self.Image then + self:SetImage(self.Image) + end +end +function gui:setDualDim(...) + self:SetDualDim(...) +end +function gui:setText(txt) + self.text=txt +end +function gui:getText(txt) + return self.text +end +_GuiPro.CursorN=love.mouse.getSystemCursor("arrow") +_GuiPro.CursorH=love.mouse.getSystemCursor("hand") +function gui:SetHand(img,x,y) + _GuiPro.CursorN=love.mouse.newCursor(img,x,y) +end +function gui:setHotKey(key) + local tab=key:split("+") + self.hotkeys=tab + self.cooldown=false + self.Alarm=multi:newAlarm(1) + self.Alarm.parent=self + self.args={} + self.funcHK=multi:newConnection() + self.Alarm:OnRing(function(alarm) alarm.parent.cooldown=false end) + function self:OnHotKey(func) + self.funcHK:connect(func) + end + self:OnUpdate(function(self) + if self.cooldown then return end + for i=1,#self.hotkeys do + if not(love.keyboard.isDown(self.hotkeys[i])) then + return + end + end + self.cooldown=true + self.funcHK:Fire(self) + self.Alarm:Reset() + end) +end +function gui:SetHover(img,x,y) + _GuiPro.CursorH=love.mouse.newCursor(img,x,y) +end +function gui:SetName(name) + self.Parent.Children[name]=self + self.Name=name +end +function gui:setNewFont(FontSize,filename) + if filename then + self.Font = love.graphics.newFont(filename, tonumber(FontSize)) + else + self.Font=love.graphics.setNewFont(tonumber(FontSize)) + end +end +function gui:setParent(parent,name)-- Needs fixing!!! + local temp=self.Parent:getChildren() + for i=1,#temp do + if temp[i]==self then + table.remove(self.Parent.Children,i) + break + end + end + table.insert(parent.Children,self) + self.Parent=parent + if name then + self:SetName(name) + end +end +function gui:setVisiblity(val) + self.Visible=val + self.oV=val + doto=self:GetAllChildren() + if val==false then + for i=1,#doto do + doto[i].Visible=val + end + else + for i=1,#doto do + doto[i].Visible=doto[i].oV + end + end +end +function gui:TopStack() + childs=self.Parent:getChildren() + for i=1,#childs do + if childs[i]==self then + table.remove(self.Parent.Children,i) + table.insert(self.Parent.Children,self) + break + end + end +end +function string:insert(p,s) + return ("%s%s%s"):format(self:sub(1,p), s, self:sub(p+1)) +end +function string:remove(p,l) + l=l or 1 + return ("%s%s"):format(self:sub(1,p-1), self:sub(p+l)) +end +function gui:newTextBox(t,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextBox",name, x, y, w, h, sx ,sy ,sw ,sh) + c.ClearOnFocus=false + c.LoseFocusOnEnter=true + c.Tween=0 + c.XTween=0 + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.text = t + c.ttext= t + c.AutoScaleText=false + c.TextVisibility=1 + c.Color = {220, 220, 220} + c.TextColor = {0, 0, 0} + c.Active=false + c.hidden=false + c.cursor={0,1} + c.mark=nil + c.arrowkeys=false + c.funcF={function() + love.keyboard.setTextInput(true,0,200,400,200) + end} + c.cooldown=false + c.cooldown2=false + c.funcE={function() + love.keyboard.setTextInput(false) + end} + function c:triggerEnter() + for cc=1,#self.funcE do + self.funcE[cc](self,self.ttext) + end + self.text="" + self.ttext="" + end + c.Enter=true + c.Alarm=multi:newAlarm(.1) + c.Alarm.parent=c + c.Alarm:OnRing(function(alarm) alarm.parent.cooldown=false end) + c.Alarm2=multi:newAlarm(.5) + c.Alarm2.parent=c + c.Alarm2:OnRing(function(alarm) alarm.parent.cooldown2=false end) + c.ArrowAlarm=multi:newAlarm(.1) + c.ArrowAlarm.parent=c + c.ArrowAlarm:OnRing(function(alarm) alarm.parent.arrowkeys=false end) + function c:OnFocus(func) + table.insert(self.funcF,func) + end + function c:OnEnter(func) + table.insert(self.funcE,func) + end + c:OnClicked(function(b,self) + self:focus() + end) + function c:focus() + for cc=1,#self.funcF do + self.funcF[cc](self) + end + if self.Active==false then + if self.ClearOnFocus==true then + self.text="" + self.ttext="" + end + for tb=1,#gui.TB do + if gui.TB[tb]~=nil then + gui.TB[tb].Active=false + end + end + self.Active=true + end + end + c:OnClicked(function(b,self,x,y) + local dwidth, wrappedtext = _defaultfont:getWrap(self.text:sub(1,self.cursor[1]), self.width) + local height = _defaultfont:getHeight() + if #wrappedtext>=1 then + width= _defaultfont:getWidth(wrappedtext[#wrappedtext]) + self.cursor[2]=#wrappedtext + else + self.cursor[2]=1 + width=0 + end + yc=math.ceil(((y/self.DPI)-(self.FontHeight/2)+self.Tween-self.y)/height) + xc=math.floor(x) + end) + c:AddDrawRuleE(function(self) + if self.Active then + local dwidth, wrappedtext = _defaultfont:getWrap(self.text:sub(1,self.cursor[1]), self.width) + local height = _defaultfont:getHeight() + if #wrappedtext>=1 then + width= _defaultfont:getWidth(wrappedtext[#wrappedtext]) + self.cursor[2]=#wrappedtext + else + self.cursor[2]=1 + width=0 + end + x1=width+2+self.x+self.XTween + y1=(self.y+(height*(self.cursor[2]-1))+(self.FontHeight/2)+self.Tween)*self.DPI + x2=width+2+self.x+self.XTween + y2=(self.y+(self.FontHeight/2)+self.Tween*self.DPI)+height*self.cursor[2] + love.graphics.line(x1,y1,x2,y2) + end + end) + c:OnUpdate(function(self) + if love.keyboard.isDown("backspace") and self.Active and self.cooldown==false then + if #self.text>0 then + self.text = self.text:remove(self.cursor[1]) + self.ttext = self.ttext:remove(self.cursor[1]) + self.cursor[1]=self.cursor[1]-1 + end + self.cooldown=true + self.Alarm:Reset() + elseif love.keyboard.isDown("backspace")==false then + self.cooldown=false + end + if love.keyboard.isDown("left") and self.arrowkeys==false and self.Active then + self.arrowkeys=true + self.cursor[1]=self.cursor[1]-1 + if self.cursor[1]<0 then + self.cursor[1]=0 + end + self.ArrowAlarm:Reset() + elseif love.keyboard.isDown("right") and self.arrowkeys==false and self.Active then + self.arrowkeys=true + self.cursor[1]=self.cursor[1]+1 + if self.cursor[1]>#self.text then + self.cursor[1]=#self.text + end + self.ArrowAlarm:Reset() + end + if love.keyboard.isDown("delete") and self.Active then + if #self.text>0 then + self.text = "" + self.ttext = "" + self.cursor[1]=1 + end + elseif (love.keyboard.isDown("lshift") or love.keyboard.isDown("rshift")) and love.keyboard.isDown("return") and self.cooldown2==false then + self.text=self.text.."\n" + self.ttext=self.ttext.."\n" + self.cooldown2=true + c.Alarm2:Reset() + elseif (love.keyboard.isDown("return") or love.keyboard.isDown("kpenter")) and self.Active and self.Enter and not(love.keyboard.isDown("lshift") or love.keyboard.isDown("rshift")) then + if self.LoseFocusOnEnter then + self.Active=false + else + self.Active=true + end + for cc=1,#self.funcE do + self.funcE[cc](self,self.ttext) + end + end + end) + table.insert(gui.TB,c) + return c +end +--TEXT BOX HELPER FUNCTION +function love.textinput(t) + for tb=1,#gui.TB do + if gui.TB[tb]~=nil then + if gui.TB[tb].Active then + if gui.TB[tb].hidden then + --gui.TB[tb].text=gui.TB[tb].text.."*" + gui.TB[tb].text=gui.TB[tb].text:insert(gui.TB[tb].cursor[1],"*") + else + --gui.TB[tb].text=gui.TB[tb].text..t + gui.TB[tb].text=gui.TB[tb].text:insert(gui.TB[tb].cursor[1],t) + end + gui.TB[tb].ttext=gui.TB[tb].ttext:insert(gui.TB[tb].cursor[1],t) + gui.TB[tb].cursor[1]=gui.TB[tb].cursor[1]+1 + end + end + end +end +function gui:newTextButton(t,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextButton",name, x, y, w, h, sx ,sy ,sw ,sh) + c.Tween=0 + c.XTween=0 + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.text = t + c.AutoScaleText=false + c.TextVisibility=1 -- 0=invisible,1=solid (self.TextVisibility*254+1) + c.Color = {220, 220, 220} + c.TextColor = {0, 0, 0} + c:OnEnter(function() + love.mouse.setCursor(_GuiPro.CursorH) + end) + c:OnExit(function() + love.mouse.setCursor(_GuiPro.CursorN) + end) + return c +end +function gui:newTextLabel(t,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextLabel",name, x, y, w, h, sx ,sy ,sw ,sh) + c.Tween=0 + c.XTween=0 + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.text = t + c.AutoScaleText=false + c.TextVisibility=1 -- 0=invisible,1=solid (self.TextVisibility*254+1) + c.Color = {220, 220, 220} + c.TextColor = {0, 0, 0} + return c +end +function gui:widthToTextSize(n) + if self.Font then + self:setDualDim(nil,nil,self.Font:getWidth(self.text)+(n or 4),nil,nil,nil,0) + end +end +function gui:AddDrawRuleB(rule) + if not(self.DrawRulesB) then self.DrawRulesB={} end + table.insert(self.DrawRulesB,rule) +end +function gui:AddDrawRuleE(rule) + if not(self.DrawRulesE) then self.DrawRulesE={} end + table.insert(self.DrawRulesE,rule) +end +function gui:draw() + if _GuiPro.rotate~=0 then + love.graphics.rotate(math.rad(_GuiPro.rotate)) + end + if self.FormFactor:lower()=="rectangle" then + self:drawR() + elseif self.FormFactor:lower()=="circle" then + self:drawC() + else + error("Unsupported FormFactor: "..self.FormFactor.."!") + end +end +function gui:drawC() + if love.mouse.isDown("l")==false and love.mouse.isDown("m")==false and love.mouse.isDown("r")==false then + _GuiPro.DragItem={} + _GuiPro.hasDrag=false + end + if self.Visible==true and self.VIS==true then + local b=true + for i,v in pairs(_GuiPro.Clips) do + if self:isDescendant(v)==true then + b=false + end + end + if b then + love.graphics.setStencilTest( ) + _GuiPro.HasStencel=false + _GuiPro.StencelHolder=nil + end + local x,y,r,s=(self.offset.pos.x or 0)+self.Parent.x,(self.offset.pos.y or 0)+self.Parent.y,self.offset.size.x or 0,self.offset.size.y or 360 + if self.CC then + x,y=x+r,y+r + end + self.x,self.y=x,y + _GuiPro.circleStencilFunction = function() + love.graphics.circle("fill",x,y,r,s) + end + if math.sqrt((love.mouse.getX()-x)^2+(love.mouse.getY()-y)^2)<=r and self:eventable() and self:Clickable() and self.Active==true then + self.hovering=true + if love.mouse.isDown("l") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.lclicked=true + elseif love.mouse.isDown("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.rclicked=true + elseif love.mouse.isDown("m") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.mclicked=true + else + if string.find(self.Type, "Button") and _GuiPro.hasDrag==false then + love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + self.hovering=false + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + if self.ClipDescendants==true then + _GuiPro.Clips[tostring(self)]=self + _GuiPro.HasStencel=true + _GuiPro.StencelHolder=self + love.graphics.stencil(_GuiPro.circleStencilFunction) + love.graphics.setStencilTest("notequal",0) + end + love.graphics.circle("fill",x,y,r,s) + love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.Visibility) + for b=0,self.BorderSize-1 do + love.graphics.circle("line",x,y,r+b,s) + end + if string.find(self.Type, "Text") then + if self.text~=nil then + if self.AutoScaleText then + self.FontSize=math.floor(self.height/1.45833) + end + love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility) + love.graphics.setFont(self.Font) + love.graphics.printf(self.text, x-(r/2)+(self.XTween), y-(r/2)+self.Tween, r, self.TextFormat) + end + end + end +end +function gui:drawR() + if love.mouse.isDown("l")==false and love.mouse.isDown("m")==false and love.mouse.isDown("r")==false then + _GuiPro.DragItem={} + _GuiPro.hasDrag=false + end + if self.Visible==true and self.VIS==true then + local b=true + for i,v in pairs(_GuiPro.Clips) do + if self:isDescendant(v)==true then + b=false + end + end + if b==true then + love.graphics.setStencilTest() + love.graphics.setScissor() + end + self.x=(self.Parent.width*self.scale.pos.x)+self.offset.pos.x+self.Parent.x + self.y=(self.Parent.height*self.scale.pos.y)+self.offset.pos.y+self.Parent.y + self.width=(self.Parent.width*self.scale.size.x)+self.offset.size.x + self.height=(self.Parent.height*self.scale.size.y)+self.offset.size.y + if self.DrawRulesB then + for dr=1,#self.DrawRulesB do + self.DrawRulesB[dr](self) + end + end + if (love.mouse.getX() > self.x and love.mouse.getX() < self.x+self.width and love.mouse.getY() > self.y and love.mouse.getY() < self.y+self.height and self:Clickable() and self:eventable()) or self:touchable("r") and self.Active==true then + self.hovering=true + if love.mouse.isDown("l") or self:touchable("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.lclicked=true + elseif love.mouse.isDown("r") or self:touchable("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.rclicked=true + elseif love.mouse.isDown("m") or self:touchable("r") and _GuiPro.hasDrag==false then + if string.find(self.Type, "Button") then + love.graphics.setColor(self.Color[1]-10, self.Color[2]-10, self.Color[3]-10,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.mclicked=true + else + if string.find(self.Type, "Button") or self:touchable("r") and _GuiPro.hasDrag==false then + love.graphics.setColor(self.Color[1]-5, self.Color[2]-5, self.Color[3]-5,self.Visibility) + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + end + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + else + love.graphics.setColor(self.Color[1],self.Color[2],self.Color[3],self.Visibility) + self.hovering=false + self.rclicked=false + self.lclicked=false + self.mclicked=false + end + if self.ClipDescendants==true then + _GuiPro.Clips[tostring(self)]=self + love.graphics.setScissor(self.x, self.y, self.width, self.height) + end + if self:hasRoundness() then + love.graphics.stencil(self.stfunc, "replace", 1) + love.graphics.setStencilTest("greater", 0) + end + + love.graphics.rectangle("fill", self.x, self.y, self.width, self.height,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI) + if string.find(self.Type, "Image") then + self:ImageRule() + end + if self.Type=="Video" then + self:VideoRule() + end + if self:hasRoundness() then + love.graphics.setStencilTest() + end + love.graphics.setColor(self.BorderColor[1], self.BorderColor[2], self.BorderColor[3],self.Visibility) + for b=0,self.BorderSize-1 do + love.graphics.rectangle("line", self.x-(b/2), self.y-(b/2), self.width+b, self.height+b,(self.rx or 1)*self.DPI,(self.ry or 1)*self.DPI,(self.segments or 1)*self.DPI) + end + if string.find(self.Type, "Text") then + if self.text~=nil then + if self.AutoScaleText then + self.FontSize=math.floor(self.height/1.45833) + end + love.graphics.setColor(self.TextColor[1],self.TextColor[2],self.TextColor[3],self.TextVisibility) + if self.Font==_defaultfont then + love.graphics.setFont(self.Font) + love.graphics.printf( + self.text, + (self.x+2+(self.marginL or 0) or self.XTween)*self.DPI, + (self.y+math.floor((self.FontHeight-self.FontSize)/2)+self.Tween)*self.DPI, + (self.width+(0 or (self.marginR or 0)))*self.DPI, + self.TextFormat, + self.TextRotation) + else + if type(self.Font)=="string" then + self.Font=love.graphics.newFont(self.Font,self.FontSize) + self.FontHeight=self.Font:getHeight() + else + love.graphics.setFont(self.Font) + end + if type(self.FontSize)=="string" then + self.FontSize=tonumber(self.FontSize) + love.graphics.setNewFont(self.FontSize) + end + love.graphics.printf( + self.text, + (self.x+2+(self.marginL or 0) or self.XTween)*self.DPI, + (self.y+math.floor((self.FontHeight-self.FontSize)/2)+self.Tween)*self.DPI, + (self.width+(0 or (self.marginR or 0)))*self.DPI, + self.TextFormat, + self.TextRotation) + end + end + end + if self.DrawRulesE then + for dr=1,#self.DrawRulesE do + self.DrawRulesE[dr](self) + end + end + end +end + +gui:respectHierarchy() +_GuiPro.width,_GuiPro.height=love.graphics.getDimensions() +multi:newLoop():OnLoop(function() _GuiPro.width,_GuiPro.height=love.graphics.getDimensions() _GuiPro:update() end) +multi:onDraw(function() _GuiPro:draw() end) +gui.ff=gui:newFrame("",0,0,0,0,0,0,1,1) +gui.ff.Color={255,255,255} +gui.ff:OnUpdate(function(self) + self:BottomStack() +end) + + diff --git a/GuiManager/Image-Animation/SetImage.int b/GuiManager/Image-Animation/SetImage.int new file mode 100644 index 0000000..70539c1 --- /dev/null +++ b/GuiManager/Image-Animation/SetImage.int @@ -0,0 +1,60 @@ +local multi,thread = require("multi"):init() +local GLOBAL,THREAD = require("multi.integration.loveManager"):init() +local func = THREAD:newFunction(function(path) + require("love.image") + return love.image.newImageData(path) +end) +local load = THREAD:newFunction(function(path) + require("love.image") + require("love.filesystem") + local http = require("socket.http") + local request = require("luajit-request") + function download(path) + if path:find("https") then + return request.send(path).body + elseif path:find("http") then + return http.request(path) + end + end + return love.image.newImageData(love.filesystem.newFileData((download(path)),"temp"..path:sub(-4,-1))) +end) +local cache = {} +function gui:SetImage(i,inthread) + if not i then return end + if type(i) == "userdata" and i:type() == "Image" then + self.Image=i + self.ImageHeigth=self.Image:getHeight() + self.ImageWidth=self.Image:getWidth() + self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth) + elseif type(i)=="string" then + if cache[i] then + self:SetImage(cache[i]) + else + if i:match([[https?://]]) then + load(i).connect(function(img) + self.Image = love.graphics.newImage(img) + cache[i]=self.Image + self.ImageHeigth=self.Image:getHeight() + self.ImageWidth=self.Image:getWidth() + self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth) + end) + else + if inthread or self.threadable then + func(i).connect(function(img) + self.Image = love.graphics.newImage(img) + cache[i]=self.Image + self.ImageHeigth=self.Image:getHeight() + self.ImageWidth=self.Image:getWidth() + self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth) + end) + else + self.Image = love.graphics.newImage(i) + cache[i]=self.Image + self.ImageHeigth=self.Image:getHeight() + self.ImageWidth=self.Image:getWidth() + self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth) + end + end + end + end +end \ No newline at end of file diff --git a/GuiManager/Image-Animation/newAnim.int b/GuiManager/Image-Animation/newAnim.int new file mode 100644 index 0000000..64bcda9 --- /dev/null +++ b/GuiManager/Image-Animation/newAnim.int @@ -0,0 +1,67 @@ +function gui:newAnim(file,delay, x, y, w, h, sx ,sy ,sw ,sh) + local _files=alphanumsort(love.filesystem.getDirectoryItems(file)) + local x,y,w,h,sx,sy,sw,sh=filter(file, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation",file, x, y, w, h, sx ,sy ,sw ,sh) + if not w and not h then + local w,h = love.graphics.newImage(file.."/".._files[1]):getDimensions() + c:setDualDim(nil,nil,w,h) + end + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files={} + c.AnimStart={} + c.AnimEnd={} + local count = 0 + local max + for i=1,#_files do + if string.sub(_files[i],-1,-1)~="b" then + count = count + 1 + gui.loadImageData(file.."/".._files[i],count,function(imagedata,id) + c.files[id] = love.graphics.newImage(imagedata) + end) + end + end + c.step=multi:newTStep(1,count,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(step,pos) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + self.step:Reset() + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end \ No newline at end of file diff --git a/GuiManager/Image-Animation/newAnimFromData.int b/GuiManager/Image-Animation/newAnimFromData.int new file mode 100644 index 0000000..02c85c7 --- /dev/null +++ b/GuiManager/Image-Animation/newAnimFromData.int @@ -0,0 +1,52 @@ +function gui:newAnimFromData(data,delay, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation","FromFile", x, y, w, h, sx ,sy ,sw ,sh) + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files=data + c.AnimStart={} + c.AnimEnd={} + c:SetImage(c.files[1]) + c.step=multi:newTStep(1,#c.files,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(pos,step) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end \ No newline at end of file diff --git a/GuiManager/Image-Animation/newAnimFromTiles.int b/GuiManager/Image-Animation/newAnimFromTiles.int new file mode 100644 index 0000000..56fd0d8 --- /dev/null +++ b/GuiManager/Image-Animation/newAnimFromTiles.int @@ -0,0 +1,59 @@ +function gui:newAnimFromTiles(file,xd,yd,delay, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(file, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageAnimation",file, x, y, w, h, sx ,sy ,sw ,sh) + local im=love.image.newImageData(file) + local _x,_y=im:getDimensions() + c.Visibility=0 + c.ImageVisibility=1 + c.delay=delay or .05 + c.files={} + c.AnimStart={} + c.AnimEnd={} + for i=0,_y/yd-1 do + for j=0,_x/xd-1 do + table.insert(c.files,gui:getTile(im,j*xd,i*yd,xd,yd)) + end + end + c:SetImage(c.files[1]) + c.step=multi:newTStep(1,#c.files,1,c.delay) + c.step.parent=c + c.rotation=0 + c.step:OnStart(function(step) + for i=1,#step.parent.AnimStart do + step.parent.AnimStart[i](step.parent) + end + end) + c.step:OnStep(function(step,pos) + step.parent:SetImage(step.parent.files[pos]) + end) + c.step:OnEnd(function(step) + for i=1,#step.parent.AnimEnd do + step.parent.AnimEnd[i](step.parent) + end + end) + function c:OnAnimStart(func) + table.insert(self.AnimStart,func) + end + function c:OnAnimEnd(func) + table.insert(self.AnimEnd,func) + end + function c:Pause() + self.step:Pause() + end + function c:Resume() + self.step:Resume() + end + function c:Reset() + self.step.pos=1 + end + function c:getFrames() + return #self.files + end + function c:getFrame() + return self.step.pos + end + function c:setFrame(n) + return self:SetImage(self.files[n]) + end + return c +end \ No newline at end of file diff --git a/GuiManager/Image-Animation/newFullImageLabel.int b/GuiManager/Image-Animation/newFullImageLabel.int new file mode 100644 index 0000000..953f480 --- /dev/null +++ b/GuiManager/Image-Animation/newFullImageLabel.int @@ -0,0 +1,3 @@ +function gui:newFullImageLabel(i,name) + return self:newImageLabel(i,name,0,0,0,0,0,0,1,1) +end \ No newline at end of file diff --git a/GuiManager/Image-Animation/newImageButton.int b/GuiManager/Image-Animation/newImageButton.int new file mode 100644 index 0000000..7e2794f --- /dev/null +++ b/GuiManager/Image-Animation/newImageButton.int @@ -0,0 +1,15 @@ +function gui:newImageButton(i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageButton",name, x, y, w, h, sx ,sy ,sw ,sh) + c:SetImage(i) + c.Visibility=0 + c.ImageVisibility=1 + c.rotation=0 + c:OnMouseEnter(function() + love.mouse.setCursor(_GuiPro.CursorH) + end) + c:OnMouseExit(function() + love.mouse.setCursor(_GuiPro.CursorN) + end) + return c +end \ No newline at end of file diff --git a/GuiManager/Image-Animation/newImageLabel.int b/GuiManager/Image-Animation/newImageLabel.int new file mode 100644 index 0000000..db7d0f3 --- /dev/null +++ b/GuiManager/Image-Animation/newImageLabel.int @@ -0,0 +1,10 @@ +function gui:newImageLabel(i,name, x, y, w, h, sx ,sy ,sw ,sh) + if not name then name = "Imagelabel" end + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("ImageLabel",name, x, y, w, h, sx ,sy ,sw ,sh) + c:SetImage(i) + c.Visibility=0 + c.ImageVisibility=1 + c.rotation=0 + return c +end \ No newline at end of file diff --git a/GuiManager/Image-Animation/newVideo.int b/GuiManager/Image-Animation/newVideo.int new file mode 100644 index 0000000..de2c379 --- /dev/null +++ b/GuiManager/Image-Animation/newVideo.int @@ -0,0 +1,62 @@ +function gui:newVideo(name,i,x,y,w,h,sx,sy,sw,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("Video",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Video=love.graphics.newVideo(i) + else + c.Video=i + end + c.Visibility=0 + c.VideoVisibility=1 + c.rotation=0 + if c.Video~=nil then + c.VideoHeigth=c.Video:getHeight() + c.VideoWidth=c.Video:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.VideoWidth,c.VideoHeigth) + end + c.funcV={} + function c:Play() + self.handStart=true + self.Video:play() + end + function c:Pause() + self.Video:pause() + end + c.Resume=c.Play + function c:Stop() + self.handStart=false + self:Pause() + self:Rewind() + for i=1,# self.funcV do + self.funcV[i](self) + end + end + function c:OnVideoStopped(func) + table.insert(self.funcV,func) + end + function c:Rewind() + self.Video:rewind() + end + function c:Restart() + self:Rewind() + self:Play() + end + function c:Seek(o) + self.Video:seek(o) + end + function c:Tell() + self.Video:tell() + end + function c:SetFilter(min, mag, anisotropy) + self.Video:setFilter(min, mag, anisotropy) + end + function c:IsPlaying() + return self.Video:isPlaying() + end + c:OnUpdate(function(self) + if self.Video:isPlaying()==false and self.handStart == true then + self:Stop() + end + end) + return c +end \ No newline at end of file diff --git a/GuiManager/Item/newDragItem.int b/GuiManager/Item/newDragItem.int new file mode 100644 index 0000000..162341c --- /dev/null +++ b/GuiManager/Item/newDragItem.int @@ -0,0 +1,51 @@ +function gui:newDragItem(t,i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextImageButtonFrameDrag",name, x, y, w, h, sx ,sy ,sw ,sh) + c.WasBeingDragged=false + c.IsBeingDragged=false + c.Draggable=true + c.funcD={} + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + c.ImageVisibility=1 + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + elseif type(i)=="image" then + c.Image=i + c.ImageVisibility=1 + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + c:OnDragStart(function(self,x,y) + if _GuiPro.hasDrag==false then + self:setParent(_GuiPro) + self:SetDualDim(x,y) + self:TopStack() + end + end) + c.rotation=0 + c.Tween=0 + c.XTween=0 + c.text = t + c.AutoScaleText=false + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.TextVisibility=1 + c.TextColor = {0, 0, 0} + function c:OnDropped(func) + table.insert(self.funcD,func) + end + c:OnUpdate(function(self) + if love.mouse.isDown("m" or self.dragbut)==false and self==_GuiPro.DragItem and self.hovering==false then + _GuiPro.DragItem={} + for i=1,#self.func7 do + self.func7[i](self,(love.mouse.getX())-self.width/2,(love.mouse.getY())-self.height/2) + end + end + end) + return c +end \ No newline at end of file diff --git a/GuiManager/Item/newItem.int b/GuiManager/Item/newItem.int new file mode 100644 index 0000000..57a68d5 --- /dev/null +++ b/GuiManager/Item/newItem.int @@ -0,0 +1,28 @@ +function gui:newItem(t,i,name, x, y, w, h, sx ,sy ,sw ,sh) + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("TextImageButtonFrame",name, x, y, w, h, sx ,sy ,sw ,sh) + if type(i)=="string" then + c.Image=love.graphics.newImage(i) + else + c.Image=i + end + c.rotation=0 + c.ImageVisibility=1 + c.Draggable=false + if c.Image~=nil then + c.ImageHeigth=c.Image:getHeight() + c.ImageWidth=c.Image:getWidth() + c.Quad=love.graphics.newQuad(0,0,w,h,c.ImageWidth,c.ImageHeigth) + end + c.Tween=0 + c.XTween=0 + c.text = t + c.AutoScaleText=false + c.FontHeight=_defaultfont:getHeight() + c.Font=_defaultfont + c.FontSize=15 + c.TextFormat="center" + c.TextVisibility=1 -- 0=invisible,1=solid (self.TextVisibility*254+1) + c.TextColor = {0, 0, 0} + return c +end \ No newline at end of file diff --git a/GuiManager/Misc/AdvTextBox.int b/GuiManager/Misc/AdvTextBox.int new file mode 100644 index 0000000..08a3499 --- /dev/null +++ b/GuiManager/Misc/AdvTextBox.int @@ -0,0 +1,45 @@ +function gui:AdvTextBox(txt,x,y,w,h,sx,sy,sw,sh) + name="AdvTextBox" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("AdvTextBoxFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c.BorderSize=0 + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + --local temp = c:newTextButton("X","Close",-25,5,20,20,1) + --temp.Tween=-5 + --temp.XTween=-2 + --temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + --temp.Color=Color.Red + c.tLink=c:newTextBox("puttext","TextBox",5,h-95,-40,30,0,1,1,1) + c.tLink.Color=Color.light_gray + c.tLink.ClearOnFocus=true + c.tLink:OnFocus(function(self) self.ClearOnFocus=false end) + local temp=c:newTextButton("OK","Ok",-35,h-65,30,30,1,1) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcO do self.Parent.funcO[i](self.Parent,self.Parent.tLink.text) end end) + temp.Color=Color.Green + temp.XTween=-2 + local temp=c:newTextButton("X","Cancel",-35,h-95,30,30,1,1) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent,self.Parent.tLink.text) end end) + temp.Color=Color.Red + temp.XTween=-2 + function c:Close() + self.Visible=false + end + function c:Open() + self.Visible=true + end + function c:OnOk(func) + table.insert(self.funcO,func) + end + function c:OnX(func) + table.insert(self.funcX,func) + end + return c +end \ No newline at end of file diff --git a/GuiManager/Misc/ApplyGradient.int b/GuiManager/Misc/ApplyGradient.int new file mode 100644 index 0000000..87cb97d --- /dev/null +++ b/GuiManager/Misc/ApplyGradient.int @@ -0,0 +1,36 @@ +function _GuiPro.gradient(colors) + local direction = colors.direction or "horizontal" + colors.direction=nil + trans = colors.trans or 1 + trans=math.floor(trans) + if direction == "horizontal" then + direction = true + elseif direction == "vertical" then + direction = false + else + error("Invalid direction '" .. tostring(direction) "' for gradient. Horizontal or vertical expected.") + end + local result = love.image.newImageData(direction and 1 or #colors, direction and #colors or 1,"rgba32f") + for __i, color in ipairs(colors) do + local x, y + if direction then + x, y = 0, __i - 1 + else + x, y = __i - 1, 0 + end + result:setPixel(x, y, color[1], color[2], color[3], trans) + end + result = love.graphics.newImage(result) + result:setFilter('linear', 'linear') + return result +end +function _GuiPro.drawinrect(img, x, y, w, h, r, ox, oy, kx, ky) + love.graphics.draw(img, x, y, r, w / img:getWidth(), h / img:getHeight(), ox, oy, kx, ky) +end +function gui:ApplyGradient(rules) + self.Image=nil + self.Type=self.Type.."w/GradImage" + self.rotation=0 + self.ImageVisibility=rules.visibility or 1 + self:SetImage(_GuiPro.gradient(rules)) +end \ No newline at end of file diff --git a/GuiManager/Misc/BottomStack.int b/GuiManager/Misc/BottomStack.int new file mode 100644 index 0000000..b339ec4 --- /dev/null +++ b/GuiManager/Misc/BottomStack.int @@ -0,0 +1,10 @@ +function gui:BottomStack() + childs=self.Parent:getChildren() + for i=1,#childs do + if childs[i]==self then + table.remove(self.Parent.Children,i) + table.insert(self.Parent.Children,1,self) + break + end + end +end \ No newline at end of file diff --git a/GuiManager/Misc/ClipDescendants.int b/GuiManager/Misc/ClipDescendants.int new file mode 100644 index 0000000..c57d96d --- /dev/null +++ b/GuiManager/Misc/ClipDescendants.int @@ -0,0 +1,18 @@ +function gui:ClipDescendants(bool) + local c = self:GetAllChildren() + if not c[#c] then return end + if bool then + self.clipParent = self.Parent + self.Clipping = true + c[#c].resetClip = true + for i = 1,#c do + c[i].ClipReference = self + end + else + self.Clipping = nil + c[#c].resetClip = nil + for i = 1,#c do + c[i].ClipReference = nil + end + end +end \ No newline at end of file diff --git a/GuiManager/Misc/Destroy.int b/GuiManager/Misc/Destroy.int new file mode 100644 index 0000000..dd8f5de --- /dev/null +++ b/GuiManager/Misc/Destroy.int @@ -0,0 +1,13 @@ +function gui:Destroy() + check=self.Parent:getChildren() + local cc=0 + for cc=1,#check do + if check[cc]==self then + table.remove(self.Parent.Children,cc) + end + end + self.Destroyed = true + if #self.Parent.Children==0 then + self.Parent.isLeaf = true + end +end \ No newline at end of file diff --git a/GuiManager/Misc/GetAllChildren.int b/GuiManager/Misc/GetAllChildren.int new file mode 100644 index 0000000..b3a0ae4 --- /dev/null +++ b/GuiManager/Misc/GetAllChildren.int @@ -0,0 +1,25 @@ +function gui:GetAllChildren() + local Stuff = {} + function Seek(Items) + for i=1,#Items do + if Items[i].Visible==true then + table.insert(Stuff,Items[i]) + local NItems = Items[i]:getChildren() + if NItems ~= nil then + Seek(NItems) + end + end + end + end + local Objs = self:getChildren() + for i=1,#Objs do + if Objs[i].Visible==true then + table.insert(Stuff,Objs[i]) + local Items = Objs[i]:getChildren() + if Items ~= nil then + Seek(Items) + end + end + end + return Stuff +end \ No newline at end of file diff --git a/GuiManager/Misc/GetChild.int b/GuiManager/Misc/GetChild.int new file mode 100644 index 0000000..d434f40 --- /dev/null +++ b/GuiManager/Misc/GetChild.int @@ -0,0 +1,3 @@ +function gui:GetChild(name) + return self.Children[name] or self +end \ No newline at end of file diff --git a/GuiManager/Misc/InGrid.int b/GuiManager/Misc/InGrid.int new file mode 100644 index 0000000..4e097a7 --- /dev/null +++ b/GuiManager/Misc/InGrid.int @@ -0,0 +1,3 @@ +function InGrid(i,x,y,s) + return math.floor((i-1)/x)*s,(i-1)*s-(math.floor((i-1)/y)*(s*x)) +end \ No newline at end of file diff --git a/GuiManager/Misc/InGridX.int b/GuiManager/Misc/InGridX.int new file mode 100644 index 0000000..c4aadc2 --- /dev/null +++ b/GuiManager/Misc/InGridX.int @@ -0,0 +1,5 @@ +function InGridX(i,w,h,xs,ys) + local xc,yc=math.floor(w/xs),math.floor(h/ys) + local xi,yi=(i-1)%xc,math.floor((i-1)/xc) + return xi*xs,yi*ys +end \ No newline at end of file diff --git a/GuiManager/Misc/InGridY.int b/GuiManager/Misc/InGridY.int new file mode 100644 index 0000000..555c72a --- /dev/null +++ b/GuiManager/Misc/InGridY.int @@ -0,0 +1,5 @@ +function InGridY(i,w,h,xs,ys) + local xc,yc=math.floor(w/xs),math.floor(h/ys) + local xi,yi=math.floor((i-1)/yc),(i-1)%yc + return xi*xs,yi*ys +end \ No newline at end of file diff --git a/GuiManager/Misc/IsHovering.int b/GuiManager/Misc/IsHovering.int new file mode 100644 index 0000000..072bb54 --- /dev/null +++ b/GuiManager/Misc/IsHovering.int @@ -0,0 +1,3 @@ +function gui:IsHovering() + return (love.mouse.getX() > self.x and love.mouse.getX() < self.x+self.width and love.mouse.getY() > self.y and love.mouse.getY() < self.y+self.height) +end \ No newline at end of file diff --git a/GuiManager/Misc/Move.int b/GuiManager/Misc/Move.int new file mode 100644 index 0000000..6f32db9 --- /dev/null +++ b/GuiManager/Misc/Move.int @@ -0,0 +1,4 @@ +function gui:Move(x,y) + self.offset.pos.x=self.offset.pos.x+x + self.offset.pos.y=self.offset.pos.y+y +end \ No newline at end of file diff --git a/GuiManager/Misc/SetDualDim.int b/GuiManager/Misc/SetDualDim.int new file mode 100644 index 0000000..0774965 --- /dev/null +++ b/GuiManager/Misc/SetDualDim.int @@ -0,0 +1,46 @@ +function gui:SetDualDim(x, y, w, h, sx ,sy ,sw ,sh) + if _GuiPro.DPI_ENABLED then + if x then + x=self.DPI*x + end + if y then + y=self.DPI*y + end + if w then + w=self.DPI*w + end + if h then + h=self.DPI*h + end + end + if sx then + self.scale.pos.x=sx + end + if sy then + self.scale.pos.y=sy + end + if x then + self.offset.pos.x=x + end + if y then + self.offset.pos.y=y + end + if sw then + self.scale.size.x=sw + end + if sh then + self.scale.size.y=sh + end + if w then + self.offset.size.x=w + end + if h then + self.offset.size.y=h + end + if self.Image then + self:SetImage(self.Image) + end +end +function gui:setDualDim(...) + self:SetDualDim(...) +end \ No newline at end of file diff --git a/GuiManager/Misc/SetHand.int b/GuiManager/Misc/SetHand.int new file mode 100644 index 0000000..8171f2c --- /dev/null +++ b/GuiManager/Misc/SetHand.int @@ -0,0 +1,5 @@ +_GuiPro.CursorN=love.mouse.getSystemCursor("arrow") +_GuiPro.CursorH=love.mouse.getSystemCursor("hand") +function gui:SetHand(img,x,y) + _GuiPro.CursorN=love.mouse.newCursor(img,x,y) +end \ No newline at end of file diff --git a/GuiManager/Misc/SetHover.int b/GuiManager/Misc/SetHover.int new file mode 100644 index 0000000..956e593 --- /dev/null +++ b/GuiManager/Misc/SetHover.int @@ -0,0 +1,3 @@ +function gui:SetHover(img,x,y) + _GuiPro.CursorH=love.mouse.newCursor(img,x,y) +end \ No newline at end of file diff --git a/GuiManager/Misc/SetName.int b/GuiManager/Misc/SetName.int new file mode 100644 index 0000000..1e69edd --- /dev/null +++ b/GuiManager/Misc/SetName.int @@ -0,0 +1,4 @@ +function gui:SetName(name) + self.Parent.Children[name]=self + self.Name=name +end \ No newline at end of file diff --git a/GuiManager/Misc/SquareX.int b/GuiManager/Misc/SquareX.int new file mode 100644 index 0000000..c846e39 --- /dev/null +++ b/GuiManager/Misc/SquareX.int @@ -0,0 +1,9 @@ +function gui:SquareX(n) + local n = n or 1 + local w = self.Parent.width + local rw = w*n + local s = (w-rw)/2 + self:setDualDim(self.x+s,self.y+s,rw,rw,sx,sy) + self:Move(s,s) + return self.Parent.width,rw +end \ No newline at end of file diff --git a/GuiManager/Misc/SquareY.int b/GuiManager/Misc/SquareY.int new file mode 100644 index 0000000..c90020b --- /dev/null +++ b/GuiManager/Misc/SquareY.int @@ -0,0 +1,9 @@ +function gui:SquareY(n) + local n = n or 1 + local w = self.Parent.height + local rw = w*n + local s = (w-rw)/2 + self:setDualDim(nil,nil,rw,rw) + self:Move(s,s) + return self.Parent.height,rw +end \ No newline at end of file diff --git a/GuiManager/Misc/TopStack.int b/GuiManager/Misc/TopStack.int new file mode 100644 index 0000000..a1db016 --- /dev/null +++ b/GuiManager/Misc/TopStack.int @@ -0,0 +1,10 @@ +function gui:TopStack() + childs=self.Parent:getChildren() + for i=1,#childs do + if childs[i]==self then + table.remove(self.Parent.Children,i) + table.insert(self.Parent.Children,self) + break + end + end +end \ No newline at end of file diff --git a/GuiManager/Misc/UpdateImage.int b/GuiManager/Misc/UpdateImage.int new file mode 100644 index 0000000..be4cfd7 --- /dev/null +++ b/GuiManager/Misc/UpdateImage.int @@ -0,0 +1,5 @@ +function gui:UpdateImage() + self.ImageHeigth=self.Image:getHeight() + self.ImageWidth=self.Image:getWidth() + self.Quad=love.graphics.newQuad(0,0,self.width,self.height,self.ImageWidth,self.ImageHeigth) +end \ No newline at end of file diff --git a/GuiManager/Misc/Utils.int b/GuiManager/Misc/Utils.int new file mode 100644 index 0000000..c80b4bc --- /dev/null +++ b/GuiManager/Misc/Utils.int @@ -0,0 +1,797 @@ +-- os Additions +function os.getSystemBit() + if (os.getenv('PROCESSOR_ARCHITEW6432')=='AMD64' or os.getenv('PROCESSOR_ARCHITECTURE')=='AMD64') then + return 64 + else + return 32 + end +end +function os.sleep(n) + if not n then n=0 end + local t0 = os.clock() + while os.clock() - t0 <= n do end +end +function os.pause(msg) + if msg ~= nil then + print(msg) + end + io.read() +end +function os.batCmd(cmd) + io.mkFile('temp.bat',cmd) + local temp = os.execute([[temp.bat]]) + io.delFile('temp.bat') + return temp +end +function os._getOS() + if package.config:sub(1,1)=='\\' then + return 'windows' + else + return 'unix' + end +end +function os.getOS(t) + if not t then + return os._getOS() + end + if os._getOS()=='unix' then + fh,err = io.popen('uname -o 2>/dev/null','r') + if fh then + osname = fh:read() + end + if osname then return osname end + end + local winver='Unknown Version' + local a,b,c=os.capture('ver'):match('(%d+).(%d+).(%d+)') + local win=a..'.'..b..'.'..c + if type(t)=='string' then + win=t + end + if win=='4.00.950' then + winver='95' + elseif win=='4.00.1111' then + winver='95 OSR2' + elseif win=='4.00.1381' then + winver='NT 4.0' + elseif win=='4.10.1998' then + winver='98' + elseif win=='4.10.2222' then + winver='98 SE' + elseif win=='4.90.3000' then + winver='ME' + elseif win=='5.00.2195' then + winver='2000' + elseif win=='5.1.2600' then + winver='XP' + elseif win=='5.2.3790' then + winver='Server 2003' + elseif win=='6.0.6000' then + winver='Vista/Windows Server 2008' + elseif win=='6.0.6002' then + winver='Vista SP2' + elseif win=='6.1.7600' then + winver='7/Windows Server 2008 R2' + elseif win=='6.1.7601' then + winver='7 SP1/Windows Server 2008 R2 SP1' + elseif win=='6.2.9200' then + winver='8/Windows Server 2012' + elseif win=='6.3.9600' then + winver='8.1/Windows Server 2012' + elseif win=='6.4.9841' then + winver='10 Technical Preview 1' + elseif win=='6.4.9860' then + winver='10 Technical Preview 2' + elseif win=='6.4.9879' then + winver='10 Technical Preview 3' + elseif win=='10.0.9926' then + winver='10 Technical Preview 4' + end + return 'Windows '..winver +end +function os.getLuaArch() + return (#tostring({})-7)*4 +end +if os.getOS()=='windows' then + function os.sleep(n) + if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end + end +else + function os.sleep(n) + os.execute('sleep ' .. tonumber(n)) + end +end +function os.capture(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end +function os.getCurrentUser() + return os.getenv('$USER') or os.getenv('USERNAME') +end +-- string Additions +function string.trim(s) + local from = s:match"^%s*()" + return from > #s and "" or s:match(".*%S", from) +end +function string.random(n) + local str = '' + strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'} + for i=1,n do + h = math.random(1,#strings) + str = str..''..strings[h] + end + return str +end +function string.linesToTable(s) + local t = {} + local i = 0 + while true do + i = string.find(s, '\n', i+1) + if i == nil then return t end + table.insert(t, i) + end +end +function string.lines(str) + local t = {} + local function helper(line) table.insert(t, line) return '' end + helper((str:gsub('(.-)\r?\n', helper))) + return t +end +function string.split(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = '(.-)' .. pat + local last_end = 1 + local s, e, cap = str:find(fpat, 1) + while s do + if s ~= 1 or cap ~= '' then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + return t +end +function string.shuffle(inputStr) + math.randomseed(os.time()); + local outputStr = ''; + local strLength = string.len(inputStr); + while (strLength ~=0) do + local pos = math.random(strLength); + outputStr = outputStr..string.sub(inputStr,pos,pos); + inputStr = inputStr:sub(1, pos-1) .. inputStr:sub(pos+1); + strLength = string.len(inputStr); + end + return outputStr; +end +function string.genKeys(chars,a,f,s,GG) + if GG then + chars=string.rep(chars,a) + end + if s then + chars=string.shuffle(chars) + end + b=#chars + if a==0 then return end + local taken = {} local slots = {} + for i=1,a do slots[i]=0 end + for i=1,b do taken[i]=false end + local index = 1 + local tab={} + for i=1,#chars do + table.insert(tab,chars:sub(i,i)) + end + while index > 0 do repeat + repeat slots[index] = slots[index] + 1 + until slots[index] > b or not taken[slots[index]] + if slots[index] > b then + slots[index] = 0 + index = index - 1 + if index > 0 then + taken[slots[index]] = false + end + break + else + taken[slots[index]] = true + end + if index == a then + local tt={} + for i=1,a do + table.insert(tt,tab[slots[i]]) + end + f(table.concat(tt)) + taken[slots[index]] = false + break + end + index = index + 1 + until true end +end +-- io Additions +function io.getInput(msg) + if msg ~= nil then + io.write(msg) + end + return io.read() +end +function io.scanDir(directory) + directory=directory or io.getDir() + local i, t, popen = 0, {}, io.popen + if os.getOS()=='unix' then + for filename in popen('ls -a \''..directory..'\''):lines() do + i = i + 1 + t[i] = filename + end + else + for filename in popen('dir \''..directory..'\' /b'):lines() do + i = i + 1 + t[i] = filename + end + end + return t +end +function io.buildFromTree(tbl, indent,folder) + if not indent then indent = 0 end + if not folder then folder = '' end + for k, v in pairs(tbl) do + formatting = string.rep(' ', indent) .. k .. ':' + if type(v) == 'table' then + if not(io.dirExists(folder..string.sub(formatting,1,-2))) then + io.mkDir(folder..string.sub(formatting,1,-2)) + end + io.buildFromTree(v,0,folder..string.sub(formatting,1,-2)..'\\') + else + a=string.find(tostring(v),':',1,true) + if a then + file=string.sub(tostring(v),1,a-1) + data=string.sub(tostring(v),a+1) + io.mkFile(folder..file,data,'wb') + else + io.mkFile(folder..v,'','wb') + end + end + end +end +function io.cpFile(path,topath) + if os.getOS()=='unix' then + os.execute('cp '..file1..' '..file2) + else + os.execute('Copy '..path..' '..topath) + end +end +function io.delDir(directoryname) + if os.getOS()=='unix' then + os.execute('rm -rf '..directoryname) + else + os.execute('rmdir '..directoryname..' /s /q') + end +end +function io.delFile(path) + os.remove(path) +end +function io.mkDir(dirname) + os.execute('mkdir "' .. dirname..'"') +end +function io.mkFile(filename,data,tp) + if not(tp) then tp='wb' end + if not(data) then data='' end + file = io.open(filename, tp) + if file==nil then return end + file:write(data) + file:close() +end +function io.movFile(path,topath) + io.cpFile(path,topath) + io.delFile(path) +end +function io.listFiles(dir) + if not(dir) then dir='' end + local f = io.popen('dir \''..dir..'\'') + if f then + return f:read('*a') + else + print('failed to read') + end +end +function io.getDir(dir) + if not dir then return io.getWorkingDir() end + if os.getOS()=='unix' then + return os.capture('cd '..dir..' ; cd') + else + return os.capture('cd '..dir..' & cd') + end +end +function io.getWorkingDir() + return io.popen'cd':read'*l' +end +function io.fileExists(path) + g=io.open(path or '','r') + if path =='' then + p='empty path' + return nil + end + if g~=nil and true or false then + p=(g~=nil and true or false) + end + if g~=nil then + io.close(g) + else + return false + end + return p +end +function io.fileCheck(file_name) + if not file_name then print('No path inputed') return false end + local file_found=io.open(file_name, 'r') + if file_found==nil then + file_found=false + else + file_found=true + end + return file_found +end +function io.dirExists(strFolderName) + strFolderName = strFolderName or io.getDir() + local fileHandle, strError = io.open(strFolderName..'\\*.*','r') + if fileHandle ~= nil then + io.close(fileHandle) + return true + else + if string.match(strError,'No such file or directory') then + return false + else + return true + end + end +end +function io.getAllItems(dir) + local t=os.capture("cd \""..dir.."\" & dir /a-d | find",true):lines() + return t +end +function io.listItems(dir) + if io.dirExists(dir) then + temp=io.listFiles(dir) -- current directory if blank + if io.getDir(dir)=='C:\\\n' then + a,b=string.find(temp,'C:\\',1,true) + a=a+2 + else + a,b=string.find(temp,'..',1,true) + end + temp=string.sub(temp,a+2) + list=string.linesToTable(temp) + temp=string.sub(temp,1,list[#list-2]) + slist=string.lines(temp) + table.remove(slist,1) + table.remove(slist,#slist) + temp={} + temp2={} + for i=1,#slist do + table.insert(temp,string.sub(slist[i],40,-1)) + end + return temp + else + return nil + end +end +function io.getDirectories(dir,l) + if dir then + dir=dir..'\\' + else + dir='' + end + local temp2=io.scanDir(dir) + for i=#temp2,1,-1 do + if io.fileExists(dir..temp2[i]) then + table.remove(temp2,i) + elseif l then + temp2[i]=dir..temp2[i] + end + end + return temp2 +end +function io.getFiles(dir,l) + if dir then + dir=dir..'\\' + else + dir='' + end + local temp2=io.scanDir(dir) + for i=#temp2,1,-1 do + if io.dirExists(dir..temp2[i]) then + table.remove(temp2,i) + elseif l then + temp2[i]=dir..temp2[i] + end + end + return temp2 +end +function io.getFullName(name) + local temp=name or arg[0] + if string.find(temp,'\\',1,true) or string.find(temp,'/',1,true) then + temp=string.reverse(temp) + a,b=string.find(temp,'\\',1,true) + if not(a) or not(b) then + a,b=string.find(temp,'/',1,true) + end + return string.reverse(string.sub(temp,1,b-1)) + end + return temp +end +function io.getName(file) + local name=io.getFullName(file) + name=string.reverse(name) + a,b=string.find(name,'.',1,true) + name=string.sub(name,a+1,-1) + return string.reverse(name) +end +function io.readFile(file) + local f = io.open(file, 'rb') + local content = f:read('*all') + f:close() + return content +end +function io.getExtension(file) + local file=io.getFullName(file) + file=string.reverse(file) + local a,b=string.find(file,'.',0,true) + local temp=string.sub(file,1,b) + return string.reverse(temp) +end +function io.pathToTable(path) + local p=io.splitPath(path) + local temp={} + temp[p[1]]={} + local last=temp[p[1]] + for i=2,#p do + snd=last + last[p[i]]={} + last=last[p[i]] + end + return temp,last,snd +end +function io.splitPath(str) + return string.split(str,'[\\/]+') +end + +function io.parseDir(dir,t) + io.tempFiles={} + function _p(dir) + local dirs=io.getDirectories(dir,true) + local files=io.getFiles(dir,true) + for i=1,#files do + p,l,s=io.pathToTable(files[i]) + if t then + s[io.getFullName(files[i])]=io.readFile(files[i]) + else + s[io.getFullName(files[i])]=io.open(files[i],'r+') + end + table.merge(io.tempFiles,p) + end + for i=1,#dirs do + table.merge(io.tempFiles,io.pathToTable(dirs[i])) + _p(dirs[i],t) + end + end + _p(dir) + return io.tempFiles +end +function io.parsedir(dir,f) + io.tempFiles={} + function _p(dir,f) + local dirs=io.getDirectories(dir,true) + local files=io.getFiles(dir,true) + for i=1,#files do + if not f then + table.insert(io.tempFiles,files[i]) + else + f(files[i]) + end + end + for i=1,#dirs do + _p(dirs[i],f) + end + end + _p(dir,f) + return io.tempFiles +end +function io.driveReady(drive) + drive=drive:upper() + if not(drive:find(':',1,true)) then + drive=drive..':' + end + drives=io.getDrives() + for i=1,#drives do + if drives[i]==drive then + return true + end + end + return false +end +function io.getDrives() + if os.getOS()=='windows' then + local temp={} + local t1=os.capture('wmic logicaldisk where drivetype=2 get deviceid, volumename',true) + local t2=os.capture('wmic logicaldisk where drivetype=3 get deviceid, volumename',true) + for drive,d2 in t1:gmatch('(.:)%s-(%w+)') do + if #d2>1 then + table.insert(temp,drive) + end + end + for drive in t2:gmatch('(.:)') do + table.insert(temp,drive) + end + return temp + end + error('Command is windows only!') +end +-- table Additions +function table.dump(t,indent) + local names = {} + if not indent then indent = '' end + for n,g in pairs(t) do + table.insert(names,n) + end + table.sort(names) + for i,n in pairs(names) do + local v = t[n] + if type(v) == 'table' then + if(v==t) then + print(indent..tostring(n)..': <-') + else + print(indent..tostring(n)..':') + table.dump(v,indent..' ') + end + else + if type(v) == 'function' then + print(indent..tostring(n)..'()') + else + print(indent..tostring(n)..': '..tostring(v)) + end + end + end +end +function table.alphanumsort(o) + local function padnum(d) local dec, n = string.match(d, '(%.?)0*(.+)') + return #dec > 0 and ('%.12f'):format(d) or ('%s%03d%s'):format(dec, #n, n) + end + table.sort(o, function(a,b) return tostring(a):gsub('%.?%d+',padnum)..('%3d'):format(#b)< tostring(b):gsub('%.?%d+',padnum)..('%3d'):format(#a) end) + return o +end +function table.foreach(t,f) + for i,v in pairs(t) do + f(v) + end +end +function table.merge(t1, t2) + for k,v in pairs(t2) do + if type(v) == 'table' then + if type(t1[k] or false) == 'table' then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +function table.print(tbl, indent) + if not indent then indent = 0 end + for k, v in pairs(tbl) do + formatting = string.rep(' ', indent) .. k .. ': ' + if type(v) == 'table' then + print(formatting) + table.print(v, indent+1) + else + print(formatting .. tostring(v)) + end + end +end +function table.merge(t1, t2) + for k,v in pairs(t2) do + if type(v) == 'table' then + if type(t1[k] or false) == 'table' then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +function table.clear(t) + for k in pairs (t) do + t[k] = nil + end +end +function table.copy(t) + function deepcopy(orig) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[deepcopy(orig_key)] = deepcopy(orig_value) + end + setmetatable(copy, deepcopy(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy + end + return deepcopy(t) +end +function table.swap(tab,i1,i2) + tab[i1],tab[i2]=tab[i2],tab[i1] +end +function table.append(t1, ...) + t1,t2= t1 or {},{...} + for k,v in pairs(t2) do + t1[#t1+1]=t2[k] + end + return t1 +end +function table.compare(t1, t2,d) + if d then + return table.deepCompare(t1,t2) + end + --if #t1 ~= #t2 then return false end + if #t2>#t1 then + for i=1,#t2 do + if t1[i] ~= t2[i] then + return false,t2[i] + end + end + else + for i=1,#t1 do + if t1[i] ~= t2[i] then + return false,t2[i] + end + end + end + return true +end +function table.deepCompare(t1,t2) + if t1==t2 then return true end + if (type(t1)~='table') then return false end + local mt1 = getmetatable(t1) + local mt2 = getmetatable(t2) + if( not table.deepCompare(mt1,mt2) ) then return false end + for k1,v1 in pairs(t1) do + local v2 = t2[k1] + if( not table.deepCompare(v1,v2) ) then return false end + end + for k2,v2 in pairs(t2) do + local v1 = t1[k2] + if( not table.deepCompare(v1,v2) ) then return false end + end + return true +end +function table.has(t,_v) + for i,v in pairs(t) do + if v==_v then + return true + end + end + return false +end +function table.reverse(tab) + local size = #tab + local newTable = {} + for i,v in ipairs (tab) do + newTable[size-i] = v + end + for i=1,#newTable do + tab[i]=newTable[i] + end +end +-- Math Additions +local Y = function(g) local a = function(f) return f(f) end return a(function(f) return g(function(x) local c=f(f) return c(x) end) end) end +local F = function(f) return function(n)if n == 0 then return 1 else return n*f(n-1) end end end +math.factorial = Y(F) +math.fib={} +math.fib.fibL={} +setmetatable(math.fib,{__call=function(self,n) + if n<=2 then + return 1 + else + if self.fibL[n] then + return self.fibL[n] + else + local t=math.fib(n-1)+math.fib(n-2) + self.fibL[n]=t + return t + end + end +end}) +local floor,insert = math.floor, table.insert +function math.basen(n,b) + n = floor(n) + if not b or b == 10 then return tostring(n) end + local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' + local t = {} + local sign = '' + if n < 0 then + sign = '-' + n = -n + end + repeat + local d = (n % b) + 1 + n = floor(n / b) + insert(t, 1, digits:sub(d,d)) + until n == 0 + return sign .. table.concat(t,'') +end +function math.convbase(n,b,tb) + return math.basen(tonumber(tostring(n),b),tb) +end +if BigNum then + function BigNum.mod(a,b) + return a-((a/b)*b) + end + local floor,insert = math.floor, table.insert + function math.basen(n,b) + n = BigNum.new(n) + if not b or b == 10 then return tostring(n) end + local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' + local t = {} + local sign = '' + if n < BigNum.new(0) then + sign = '-' + n = -n + end + repeat + local d = BigNum.mod(n , b) + 1 + n = n/b + d=tonumber(tostring(d)) + insert(t, 1, digits:sub(d,d)) + until tonumber(tostring(n)) == 0 + return sign .. table.concat(t,'') + end + function math.to10(n,b) + local num=tostring(n) + local sum=BigNum.new() + local digits = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ' + for i=1,#num do + local v=digits:find(num:sub(i,i),1,true) + sum=sum+BigNum.new(tonumber(v)-1)*BigNum.pow(BigNum.new(b),BigNum.new(#num-i)) + end + return sum + end + function math.convbase(n,b,tb) + return math.basen(math.to10(n,b),tb) + end +end +function math.numfix(n,x) + local str=tostring(n) + if #str 0 and ("%.12f"):format(d) or ("%s%03d%s"):format(dec, #n, n) + end + table.sort(o, function(a,b) return tostring(a):gsub("%.?%d+",padnum)..("%3d"):format(#b)< tostring(b):gsub("%.?%d+",padnum)..("%3d"):format(#a) end) + return o +end \ No newline at end of file diff --git a/GuiManager/Misc/anchorRight.int b/GuiManager/Misc/anchorRight.int new file mode 100644 index 0000000..91251ad --- /dev/null +++ b/GuiManager/Misc/anchorRight.int @@ -0,0 +1,3 @@ +function gui:anchorRight(n) + self:SetDualDim(-(self.width+n),nil,nil,nil,1) +end \ No newline at end of file diff --git a/GuiManager/Misc/center.int b/GuiManager/Misc/center.int new file mode 100644 index 0000000..fb22fea --- /dev/null +++ b/GuiManager/Misc/center.int @@ -0,0 +1,4 @@ +function gui:center() + self:centerX() + self:centerY() +end \ No newline at end of file diff --git a/GuiManager/Misc/centerX.int b/GuiManager/Misc/centerX.int new file mode 100644 index 0000000..ea1f599 --- /dev/null +++ b/GuiManager/Misc/centerX.int @@ -0,0 +1,3 @@ +function gui:centerX() + self:SetDualDim(-(self.width/2),nil,nil,nil,.5) +end \ No newline at end of file diff --git a/GuiManager/Misc/centerY.int b/GuiManager/Misc/centerY.int new file mode 100644 index 0000000..c998589 --- /dev/null +++ b/GuiManager/Misc/centerY.int @@ -0,0 +1,3 @@ +function gui:centerY() + self:SetDualDim(nil,-(self.height/2),nil,nil,nil,.5) +end \ No newline at end of file diff --git a/GuiManager/Misc/disrespectHierarchy.int b/GuiManager/Misc/disrespectHierarchy.int new file mode 100644 index 0000000..d25162d --- /dev/null +++ b/GuiManager/Misc/disrespectHierarchy.int @@ -0,0 +1,3 @@ +function gui:disrespectHierarchy() + _GuiPro.Hierarchy=false +end \ No newline at end of file diff --git a/GuiManager/Misc/getChildren.int b/GuiManager/Misc/getChildren.int new file mode 100644 index 0000000..295c5fc --- /dev/null +++ b/GuiManager/Misc/getChildren.int @@ -0,0 +1,3 @@ +function gui:getChildren() + return self.Children +end \ No newline at end of file diff --git a/GuiManager/Misc/getColor.int b/GuiManager/Misc/getColor.int new file mode 100644 index 0000000..bef482e --- /dev/null +++ b/GuiManager/Misc/getColor.int @@ -0,0 +1,3 @@ +function gui:getColor(cindex) + return Color[cindex] +end \ No newline at end of file diff --git a/GuiManager/Misc/getFullSize.int b/GuiManager/Misc/getFullSize.int new file mode 100644 index 0000000..62c6221 --- /dev/null +++ b/GuiManager/Misc/getFullSize.int @@ -0,0 +1,14 @@ +function gui:getFullSize() + local maxx,maxy=self.width,self.height + local px,py=self.x,self.y + local temp = self:GetAllChildren() + for i=1,#temp do + if temp[i].width+temp[i].x>maxx then + maxx=temp[i].width+temp[i].x + end + if temp[i].height+temp[i].y>maxy then + maxy=temp[i].height+temp[i].y + end + end + return maxx,maxy,px,py +end \ No newline at end of file diff --git a/GuiManager/Misc/getHighest.int b/GuiManager/Misc/getHighest.int new file mode 100644 index 0000000..df7121a --- /dev/null +++ b/GuiManager/Misc/getHighest.int @@ -0,0 +1,5 @@ +function gui:getHighest() + if self.Children[#self.Children]~=nil then + return self.Children[#self.Children] + end +end \ No newline at end of file diff --git a/GuiManager/Misc/getLowest.int b/GuiManager/Misc/getLowest.int new file mode 100644 index 0000000..5319544 --- /dev/null +++ b/GuiManager/Misc/getLowest.int @@ -0,0 +1,5 @@ +function gui:getLowest() + if self.Children[1]~=nil then + return self.Children[1] + end +end \ No newline at end of file diff --git a/GuiManager/Misc/getTile.int b/GuiManager/Misc/getTile.int new file mode 100644 index 0000000..6b6fcae --- /dev/null +++ b/GuiManager/Misc/getTile.int @@ -0,0 +1,20 @@ +function gui:getTile(i,x,y,w,h)-- returns imagedata + if type(i)=="string" then + i=love.graphics.newImage(i) + elseif type(i)=="userdata" then + -- do nothing + elseif string.find(self.Type,"Image",1,true) then + local i,x,y,w,h=self.Image,i,x,y,w + else + error("getTile invalid args!!! Usage: ImageElement:getTile(x,y,w,h) or gui:getTile(imagedata,x,y,w,h)") + end + local iw,ih=i:getDimensions() + local id,_id=i:getData(),love.image.newImageData(w,h) + for _x=x,w+x-1 do + for _y=y,h+y-1 do + -- + _id:setPixel(_x-x,_y-y,id:getPixel(_x,_y)) + end + end + return love.graphics.newImage(_id) +end \ No newline at end of file diff --git a/GuiManager/Misc/isDescendant.int b/GuiManager/Misc/isDescendant.int new file mode 100644 index 0000000..f004182 --- /dev/null +++ b/GuiManager/Misc/isDescendant.int @@ -0,0 +1,9 @@ +function gui:isDescendant(obj) + local things = obj:GetAllChildren() + for i=1,#things do + if things[i] == self then + return true + end + end + return false +end \ No newline at end of file diff --git a/GuiManager/Misc/isHighest.int b/GuiManager/Misc/isHighest.int new file mode 100644 index 0000000..0453c16 --- /dev/null +++ b/GuiManager/Misc/isHighest.int @@ -0,0 +1,3 @@ +function gui:isHighest() + return (self==self.Parent:getHighest()) +end \ No newline at end of file diff --git a/GuiManager/Misc/isLowest.int b/GuiManager/Misc/isLowest.int new file mode 100644 index 0000000..a210883 --- /dev/null +++ b/GuiManager/Misc/isLowest.int @@ -0,0 +1,3 @@ +function gui:isLowest() + return (self==self.Parent:getLowest()) +end \ No newline at end of file diff --git a/GuiManager/Misc/massMutate.int b/GuiManager/Misc/massMutate.int new file mode 100644 index 0000000..1c75aee --- /dev/null +++ b/GuiManager/Misc/massMutate.int @@ -0,0 +1,6 @@ +function gui.massMutate(t,...) + local mut={...} + for i=1,#mut do + mut[i]:Mutate(t) + end +end \ No newline at end of file diff --git a/GuiManager/Misc/newCheckBox.int b/GuiManager/Misc/newCheckBox.int new file mode 100644 index 0000000..3437754 --- /dev/null +++ b/GuiManager/Misc/newCheckBox.int @@ -0,0 +1,21 @@ +function gui:newCheckBox(x,y,sx,sy) + local check = self:newFrame(x or 0,y or 0,30,30,sx or 0,sy or 0) + check.isChecked = false + check.Visibility = 0 + check.BorderSize = 0 + local checkbox = check:newFrame(4,4,22,22) + checkbox.BorderSize = 4 + checkbox:setRoundness(5,5,30) + local highlighter = checkbox:newFrame(4,4,14,14) + highlighter.BorderSize = 0 + highlighter.Color = Color.gray50 + highlighter:setRoundness(2,2,30) + highlighter.Visible = false + check:OnReleased(function(b,self) + self.isChecked = not highlighter.Visible + highlighter.Visible = not highlighter.Visible + end) + check.box = checkbox + check.highlighter = highlighter + return check +end \ No newline at end of file diff --git a/GuiManager/Misc/newMessageBox.int b/GuiManager/Misc/newMessageBox.int new file mode 100644 index 0000000..6b11a5a --- /dev/null +++ b/GuiManager/Misc/newMessageBox.int @@ -0,0 +1,36 @@ +function gui:newMessageBox(txt,x,y,w,h,sx,sy,sw,sh) + name="MessageBox" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("MessageBoxFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c.BorderSize=0 + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + local temp = c:newTextButton("X","Close",-25,5,20,20,1) + temp.Tween=-5 + temp.XTween=-2 + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + temp.Color=Color.Red + local temp=c:newTextButton("OK","Ok",0,h-65,0,30,.25,1,.5) + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcO do self.Parent.funcO[i](self.Parent) end end) + temp.Color=Color.Green + function c:Close() + self.Visible=false + end + function c:Open() + self.Visible=true + end + function c:OnOk(func) + table.insert(self.funcO,func) + end + function c:OnX(func) + table.insert(self.funcX,func) + end + return c +end \ No newline at end of file diff --git a/GuiManager/Misc/newPart.int b/GuiManager/Misc/newPart.int new file mode 100644 index 0000000..79bd3e5 --- /dev/null +++ b/GuiManager/Misc/newPart.int @@ -0,0 +1,49 @@ +function gui:newPart(x, y,w ,h , sx ,sy ,sw ,sh) + local c = {} + setmetatable(c, gui) + if self==gui then + c.Parent=_GuiPro + else + c.Parent=self + end + c.funcs={} + c.funcs2={} + c.funcs3={} + c.funcs4={} + c.funcs5={} + c.func6={} + c.func7={} + c.func8={} + c.func9={} + c.func10={} + c.form="rectangle" + c.Color = {255, 255, 255} + c.scale={} + c.scale.size={} + c.scale.size.x=sw or 0 + c.scale.size.y=sh or 0 + c.offset={} + c.offset.size={} + c.offset.size.x=w or 0 + c.offset.size.y=h or 0 + c.scale.pos={} + c.scale.pos.x=sx or 0 + c.scale.pos.y=sy or 0 + c.offset.pos={} + c.offset.pos.x=x or 0 + c.offset.pos.y=y or 0 + c.VIS=true + c.Visible=true + c.Visibility=1 + c.BorderColor={0,0,0} + c.BorderSize=0 + c.Type="Part" + c.Name="GuiPart" + _GuiPro.count=_GuiPro.count+1 + c.x=(c.Parent.width*c.scale.pos.x)+c.offset.pos.x+c.Parent.x + c.y=(c.Parent.height*c.scale.pos.y)+c.offset.pos.y+c.Parent.y + c.width=(c.Parent.width*c.scale.size.x)+c.offset.size.x + c.height=(c.Parent.height*c.scale.size.y)+c.offset.size.y + table.insert(c.Parent.Children,c) + return c +end \ No newline at end of file diff --git a/GuiManager/Misc/newProgressBar.int b/GuiManager/Misc/newProgressBar.int new file mode 100644 index 0000000..2f82f9f --- /dev/null +++ b/GuiManager/Misc/newProgressBar.int @@ -0,0 +1,45 @@ +function gui:newProgressBar(txt,x,y,w,h,sx,sy,sw,sh) + name="newProgressBar" + x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newBase("newProgressBarFrame",name, x, y, w, 30, sx ,sy ,sw ,sh) + c.Draggable=true + c.dragbut="r" + c.BorderSize=0 + c:ApplyGradient{Color.Blue,Color.sexy_purple} + c:newTextLabel(txt,"Holder",0,0,0,h-30,0,1,1,0).Color=Color.sexy_purple + c.funcO={} + c.funcX={} + c:OnDragStart(function(self) + self:TopStack() + end) + local temp = c:newTextButton("X","Close",-25,5,20,20,1) + temp.Tween=-5 + temp.XTween=-2 + temp:OnReleased(function(b,self) for i=1,#self.Parent.funcX do self.Parent.funcX[i](self.Parent) end end) + temp.Color=Color.Red + c.BarBG=c:newTextButton("",5,h-65,-10,30,0,1,1) + c.BarBG:ApplyGradient{Color.Red,Color.light_red} + c.Bar=c.BarBG:newTextLabel("",0,0,0,0,0,0,0,1) + c.Bar:ApplyGradient{Color.Green,Color.light_green} + c.BarDisp=c.BarBG:newTextLabel("0%","0%",0,0,0,0,0,0,1,1) + c.BarDisp.Visibility=0 + c.BarDisp.Link=c.Bar + c.BarDisp:OnUpdate(function(self) + self.text=self.Link.scale.size.x*100 .."%" + end) + c.Func1={} + function c:On100(func) + table.insert(self.Func1,func) + end + c:OnUpdate(function(self) + if self.Bar.scale.size.x*100>=100 then + for P=1,#self.Func1 do + self.Func1[P](self) + end + end + end) + function c:SetPercentage(n) + self.Bar:SetDualDim(0,0,0,0,0,0,n/100,1) + end + return c +end \ No newline at end of file diff --git a/GuiManager/Misc/newScrollBar.int b/GuiManager/Misc/newScrollBar.int new file mode 100644 index 0000000..6fa810a --- /dev/null +++ b/GuiManager/Misc/newScrollBar.int @@ -0,0 +1,42 @@ +function gui:newScrollBar(color1,color2) + local scrollbar=self:newFrame(-20,0,20,0,1,0,0,1) + scrollbar.funcS={} + scrollbar.Color=color1 or Color.saddle_brown + scrollbar:OnClicked(function(b,self,x,y) + love.mouse.setX(self.x+10) + if y>=10 and y<=self.height-10 then + self.mover:SetDualDim(0,y-10) + end + if y<10 then + love.mouse.setY(10+self.y) + end + if y>self.height-10 then + love.mouse.setY((self.height-10)+self.y) + end + for i=1,#self.funcS do + self.funcS[i](self,self:getPosition()) + end + end) + scrollbar:OnEnter(function(self) + self:addDominance() + end) + scrollbar:OnExit(function(self) + self:removeDominance() + end) + scrollbar.mover=scrollbar:newTextButton("","",0,0,20,20) + scrollbar.mover.Color=color2 or Color.light_brown + function scrollbar:getPosition() + return ((self.mover.offset.pos.y)/(self.height-20))*100 + end + function scrollbar:setPosition(n) + print((self.height-20),n) + self.mover.offset.pos.y=((self.height-20)/(100/n)) + for i=1,#self.funcS do + self.funcS[i](self,self:getPosition()) + end + end + function scrollbar:OnScroll(func) + table.insert(self.funcS,func) + end + return scrollbar +end \ No newline at end of file diff --git a/GuiManager/Misc/newScrollMenu.int b/GuiManager/Misc/newScrollMenu.int new file mode 100644 index 0000000..f7ee5ac --- /dev/null +++ b/GuiManager/Misc/newScrollMenu.int @@ -0,0 +1,81 @@ +function gui:newScrollMenu(name) + local temp = self:newFullFrame(name) + temp.ref = { + [[setNewFont(16)]], + [[setRoundness(10,10,180)]], + Tween = 6 + } + temp.allowOverlapping = true + temp.Visibility = 0 + local ScrollY = temp:newFrame(name.."ScrollY",-20,0,20,0,1,0,0,1) + temp.scroll = ScrollY + ScrollY.Color=Color.new(80,80,80) + ScrollY.allowOverlapping = true + ScrollY.Mover = ScrollY:newFrame(name.."MoverY",5,5,10,80) + ScrollY.Mover.Color = Color.new(60,60,60) + local func = function(b,self,x,y,nn) + temp.symbolicY = y + if y>45 and yScrollY.height-40 then + temp.symbolicY = ScrollY.height-40 + end + func("l",ScrollY,x,temp.symbolicY,true) + end) + temp.ClipDescendants=true + temp.first = temp:newTextLabel("","",15,10,-50,40,0,0,1) + local nice = temp:newTextLabel(name,name,15,10,-50,40,0,0,1) + temp.header = nice + temp.last = temp.first + temp.last.BorderSize = 0 + temp.last.Visibility = 0 + nice:setNewFont(26) + nice.Tween = 6 + temp.list = {} + local alarm + multi:newLoop(function() + for i=1,#temp.list do + local val = (temp.first.y+(temp.list[i].staticpos)+10) + if val>temp.y and val self.x+width then + curpos = #hiddenText+1 + elseif x < self.x then + curpos = 1 + else + for i = 1,#hiddenText do + width = self.Font:getWidth(self.text:sub(1,i)) + if x-self.x < width then + curpos = i + break + end + end + end + end) + c:OnPressedOuter(function(b,self) + if Focused then + self:unfocus() + end + end) + c:OnUpdate(function(self) + if #hiddenText==0 then self.text = "" return end + if self.hideText then + self.text = table.concat(hiddenText) + else + self.text = table.concat(realText) + end + self.TextFormat = "left" + end) + multi.OnTextInput(function(t) + table.insert(hiddenText,curpos,"*") + table.insert(realText,curpos,t) + curpos = curpos + 1 + if autoScaleFont then + c:fitFont() + end + end) + multi.OnKeyPressed(function(key, scancode, isrepeat ) + if key == "backspace" then + table.remove(hiddenText,curpos-1) + table.remove(realText,curpos-1) + curpos = curpos - 1 + if curpos < 1 then + curpos = 1 + end + if autoScaleFont then + c:fitFont() + end + elseif key == "enter" then + + elseif key == "delete" then + realText = {} + hiddenText = {} + curpos = 1 + elseif key == "left" then + curpos = curpos - 1 + if curpos < 1 then + curpos = 1 + end + moved = true + alarm:Reset() + elseif key == "right" then + curpos = curpos + 1 + if curpos > #realText+1 then + curpos = #realText+1 + end + moved = true + alarm:Reset() + end + end) + local blink = false + multi:newThread("TextCursonBlinker",function() + while true do + thread.sleep(1.5) + blink = not blink + end + end) + self.DrawRulesE = {function() + if --[[blink or moved]] true then + local width = c.Font:getWidth(c.text:sub(1,curpos-1)) + local height = c.Font:getHeight() + if c.TextFormat == "center" then + -- print(c.x+(c.width/2+width),c.height,c.x+(c.width/2+width),c.height+height) + -- love.graphics.line(c.x+(c.width/2+width),c.height,c.x+(c.width/2+width),c.height+height) + elseif c.TextFormat == "right" then + --love.graphics.line(c.x+width,c.y,c.x+width,c.y+c.Font:getHeight()) + elseif c.TextFormat == "left" then + love.graphics.line(c.x+width,c.y,c.x+width,c.y+height) + end + end + end} + return c +end \ No newline at end of file diff --git a/GuiManager/Text/newTextButton.int b/GuiManager/Text/newTextButton.int new file mode 100644 index 0000000..be43ef0 --- /dev/null +++ b/GuiManager/Text/newTextButton.int @@ -0,0 +1,11 @@ +function gui:newTextButton(t,name, x, y, w, h, sx ,sy ,sw ,sh) + local x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + local c=self:newTextBase("TextButton",t,name, x, y, w, h, sx ,sy ,sw ,sh) + c:OnMouseEnter(function() + love.mouse.setCursor(_GuiPro.CursorH) + end) + c:OnMouseExit(function() + love.mouse.setCursor(_GuiPro.CursorN) + end) + return c +end \ No newline at end of file diff --git a/GuiManager/Text/newTextLabel.int b/GuiManager/Text/newTextLabel.int new file mode 100644 index 0000000..679224d --- /dev/null +++ b/GuiManager/Text/newTextLabel.int @@ -0,0 +1,4 @@ +function gui:newTextLabel(t,name, x, y, w, h, sx ,sy ,sw ,sh) + local x,y,w,h,sx,sy,sw,sh=filter(name, x, y, w, h, sx ,sy ,sw ,sh) + return self:newTextBase("TextLabel",t,name, x, y, w, h, sx ,sy ,sw ,sh) +end \ No newline at end of file diff --git a/GuiManager/Text/setDefualtFont.int b/GuiManager/Text/setDefualtFont.int new file mode 100644 index 0000000..001b9f7 --- /dev/null +++ b/GuiManager/Text/setDefualtFont.int @@ -0,0 +1,3 @@ +function gui:setDefualtFont(font) + _defaultfont = font +end \ No newline at end of file diff --git a/GuiManager/Text/setNewFont.int b/GuiManager/Text/setNewFont.int new file mode 100644 index 0000000..9b0c840 --- /dev/null +++ b/GuiManager/Text/setNewFont.int @@ -0,0 +1,9 @@ +function gui:setNewFont(filename,FontSize) + if type(filename)=="string" then + self.FontFile = filename + self.Font = love.graphics.newFont(filename, tonumber(FontSize)) + else + self.Font=love.graphics.newFont(tonumber(filename)) + end + self.Font:setFilter("linear","nearest",4) +end \ No newline at end of file diff --git a/GuiManager/Text/setgetText.int b/GuiManager/Text/setgetText.int new file mode 100644 index 0000000..bb4afc6 --- /dev/null +++ b/GuiManager/Text/setgetText.int @@ -0,0 +1,6 @@ +function gui:setText(txt) + self.text=txt +end +function gui:getText(txt) + return self.text +end \ No newline at end of file diff --git a/GuiManager/Text/widthToTextSize.int b/GuiManager/Text/widthToTextSize.int new file mode 100644 index 0000000..a36b6dc --- /dev/null +++ b/GuiManager/Text/widthToTextSize.int @@ -0,0 +1,5 @@ +function gui:widthToTextSize(n) + if self.Font then + self:setDualDim(nil,nil,self.Font:getWidth(self.text)+(n or 4),nil,nil,nil,0) + end +end \ No newline at end of file diff --git a/GuiManager/Utils.lua b/GuiManager/Utils.lua new file mode 100644 index 0000000..5f97d52 --- /dev/null +++ b/GuiManager/Utils.lua @@ -0,0 +1,770 @@ +-- os Additions +function os.getSystemBit() + if (os.getenv("PROCESSOR_ARCHITEW6432")=="AMD64" or os.getenv("PROCESSOR_ARCHITECTURE")=="AMD64") then + return 64 + else + return 32 + end +end +function os.sleep(n) + if not n then n=0 end + local t0 = os.clock() + while os.clock() - t0 <= n do end +end +function os.pause(msg) + if msg ~= nil then + print(msg) + end + io.read() +end +function os.batCmd(cmd) + io.mkFile("temp.bat",cmd) + local temp = os.execute([[temp.bat]]) + io.delFile("temp.bat") + return temp +end +function os._getOS() + if package.config:sub(1,1)=="\\" then + return "windows" + else + return "unix" + end +end +function os.getOS(t) + if not t then + return os._getOS() + end + if os._getOS()=="unix" then + fh,err = io.popen("uname -o 2>/dev/null","r") + if fh then + osname = fh:read() + end + if osname then return osname end + end + local winver="'Unknown Version'" + local a,b,c=os.capture("ver"):match("(%d+).(%d+).(%d+)") + local win=a.."."..b.."."..c + if type(t)=="string" then + win=t + end + if win=="4.00.950" then + winver="95" + elseif win=="4.00.1111" then + winver="95 OSR2" + elseif win=="4.00.1381" then + winver="NT 4.0" + elseif win=="4.10.1998" then + winver="98" + elseif win=="4.10.2222" then + winver="98 SE" + elseif win=="4.90.3000" then + winver="ME" + elseif win=="5.00.2195" then + winver="2000" + elseif win=="5.1.2600" then + winver="XP" + elseif win=="5.2.3790" then + winver="Server 2003" + elseif win=="6.0.6000" then + winver="Vista/Windows Server 2008" + elseif win=="6.0.6002" then + winver="Vista SP2" + elseif win=="6.1.7600" then + winver="7/Windows Server 2008 R2" + elseif win=="6.1.7601" then + winver="7 SP1/Windows Server 2008 R2 SP1" + elseif win=="6.2.9200" then + winver="8/Windows Server 2012" + elseif win=="6.3.9600" then + winver="8.1/Windows Server 2012" + elseif win=="6.4.9841" then + winver="10 Technical Preview 1" + elseif win=="6.4.9860" then + winver="10 Technical Preview 2" + elseif win=="6.4.9879" then + winver="10 Technical Preview 3" + elseif win=="10.0.9926" then + winver="10 Technical Preview 4" + end + return "Windows "..winver +end +function os.getLuaArch() + return (#tostring({})-7)*4 +end +if os.getOS()=="windows" then + function os.sleep(n) + if n > 0 then os.execute("ping -n " .. tonumber(n+1) .. " localhost > NUL") end + end +else + function os.sleep(n) + os.execute("sleep " .. tonumber(n)) + end +end +function os.capture(cmd, raw) + local f = assert(io.popen(cmd, 'r')) + local s = assert(f:read('*a')) + f:close() + if raw then return s end + s = string.gsub(s, '^%s+', '') + s = string.gsub(s, '%s+$', '') + s = string.gsub(s, '[\n\r]+', ' ') + return s +end +function os.getCurrentUser() + return os.getenv("$USER") or os.getenv("USERNAME") +end +-- string Additions +function string.random(n) + local str = "" + strings = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","1","2","3","4","5","6","7","8","9","0","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"} + for i=1,n do + h = math.random(1,#strings) + str = str..""..strings[h] + end + return str +end +function string.linesToTable(s) + local t = {} + local i = 0 + while true do + i = string.find(s, "\n", i+1) + if i == nil then return t end + table.insert(t, i) + end +end +function string.lines(str) + local t = {} + local function helper(line) table.insert(t, line) return "" end + helper((str:gsub("(.-)\r?\n", helper))) + return t +end +function string.split(str, pat) + local t = {} -- NOTE: use {n = 0} in Lua-5.0 + local fpat = "(.-)" .. pat + local last_end = 1 + local s, e, cap = str:find(fpat, 1) + while s do + if s ~= 1 or cap ~= "" then + table.insert(t,cap) + end + last_end = e+1 + s, e, cap = str:find(fpat, last_end) + end + if last_end <= #str then + cap = str:sub(last_end) + table.insert(t, cap) + end + return t +end +function string.shuffle(inputStr) + math.randomseed(os.time()); + local outputStr = ""; + local strLength = string.len(inputStr); + while (strLength ~=0) do + local pos = math.random(strLength); + outputStr = outputStr..string.sub(inputStr,pos,pos); + inputStr = inputStr:sub(1, pos-1) .. inputStr:sub(pos+1); + strLength = string.len(inputStr); + end + return outputStr; +end +function string.genKeys(chars,a,f,s,GG) + if GG then + chars=string.rep(chars,a) + end + if s then + chars=string.shuffle(chars) + end + b=#chars + if a==0 then return end + local taken = {} local slots = {} + for i=1,a do slots[i]=0 end + for i=1,b do taken[i]=false end + local index = 1 + local tab={} + for i=1,#chars do + table.insert(tab,chars:sub(i,i)) + end + while index > 0 do repeat + repeat slots[index] = slots[index] + 1 + until slots[index] > b or not taken[slots[index]] + if slots[index] > b then + slots[index] = 0 + index = index - 1 + if index > 0 then + taken[slots[index]] = false + end + break + else + taken[slots[index]] = true + end + if index == a then + local tt={} + for i=1,a do + table.insert(tt,tab[slots[i]]) + end + f(table.concat(tt)) + taken[slots[index]] = false + break + end + index = index + 1 + until true end +end +-- io Additions +function io.getInput(msg) + if msg ~= nil then + io.write(msg) + end + return io.read() +end +function io.scanDir(directory) + directory=directory or io.getDir() + local i, t, popen = 0, {}, io.popen + if os.getOS()=="unix" then + for filename in popen('ls -a "'..directory..'"'):lines() do + i = i + 1 + t[i] = filename + end + else + for filename in popen('dir "'..directory..'" /b'):lines() do + i = i + 1 + t[i] = filename + end + end + return t +end +function io.buildFromTree(tbl, indent,folder) + if not indent then indent = 0 end + if not folder then folder = "" end + for k, v in pairs(tbl) do + formatting = string.rep(" ", indent) .. k .. ":" + if type(v) == "table" then + if not(io.dirExists(folder..string.sub(formatting,1,-2))) then + io.mkDir(folder..string.sub(formatting,1,-2)) + end + io.buildFromTree(v,0,folder..string.sub(formatting,1,-2).."\\") + else + a=string.find(tostring(v),":",1,true) + if a then + file=string.sub(tostring(v),1,a-1) + data=string.sub(tostring(v),a+1) + io.mkFile(folder..file,data,"wb") + else + io.mkFile(folder..v,"","wb") + end + end + end +end +function io.cpFile(path,topath) + if os.getOS()=="unix" then + os.execute("cp "..file1.." "..file2) + else + os.execute("Copy "..path.." "..topath) + end +end +function io.delDir(directoryname) + if os.getOS()=="unix" then + os.execute("rm -rf "..directoryname) + else + os.execute("rmdir "..directoryname.." /s /q") + end +end +function io.delFile(path) + os.remove(path) +end +function io.mkDir(dirname) + os.execute("mkdir \"" .. dirname.."\"") +end +function io.mkFile(filename,data,tp) + if not(tp) then tp="wb" end + if not(data) then data="" end + file = io.open(filename, tp) + if file==nil then return end + file:write(data) + file:close() +end +function io.movFile(path,topath) + io.cpFile(path,topath) + io.delFile(path) +end +function io.listFiles(dir) + if not(dir) then dir="" end + local f = io.popen("dir \""..dir.."\"") + if f then + return f:read("*a") + else + print("failed to read") + end +end +function io.getDir(dir) + if not dir then return io.getWorkingDir() end + if os.getOS()=="unix" then + return os.capture("cd "..dir.." ; cd") + else + return os.capture("cd "..dir.." & cd") + end +end +function io.getWorkingDir() + return io.popen"cd":read'*l' +end +function io.fileExists(path) + g=io.open(path or '','r') + if path =="" then + p="empty path" + return nil + end + if g~=nil and true or false then + p=(g~=nil and true or false) + end + if g~=nil then + io.close(g) + else + return false + end + return p +end +function io.fileCheck(file_name) + if not file_name then print("No path inputed") return false end + local file_found=io.open(file_name, "r") + if file_found==nil then + file_found=false + else + file_found=true + end + return file_found +end +function io.dirExists(strFolderName) + strFolderName = strFolderName or io.getDir() + local fileHandle, strError = io.open(strFolderName.."\\*.*","r") + if fileHandle ~= nil then + io.close(fileHandle) + return true + else + if string.match(strError,"No such file or directory") then + return false + else + return true + end + end +end +function io.listItems(dir) + if io.dirExists(dir) then + temp=io.listFiles(dir) -- current directory if blank + if io.getDir(dir)=="C:\\\n" then + a,b=string.find(temp,"C:\\",1,true) + a=a+2 + else + a,b=string.find(temp,"..",1,true) + end + temp=string.sub(temp,a+2) + list=string.linesToTable(temp) + temp=string.sub(temp,1,list[#list-2]) + slist=string.lines(temp) + table.remove(slist,1) + table.remove(slist,#slist) + temp={} + temp2={} + for i=1,#slist do + table.insert(temp,string.sub(slist[i],40,-1)) + end + return temp + else + return nil + end +end +function io.getDirectories(dir,l) + if dir then + dir=dir.."\\" + else + dir="" + end + local temp2=io.scanDir(dir) + for i=#temp2,1,-1 do + if io.fileExists(dir..temp2[i]) then + table.remove(temp2,i) + elseif l then + temp2[i]=dir..temp2[i] + end + end + return temp2 +end +function io.getFiles(dir,l) + if dir then + dir=dir.."\\" + else + dir="" + end + local temp2=io.scanDir(dir) + for i=#temp2,1,-1 do + if io.dirExists(dir..temp2[i]) then + table.remove(temp2,i) + elseif l then + temp2[i]=dir..temp2[i] + end + end + return temp2 +end +function io.getFullName(name) + local temp=name or arg[0] + if string.find(temp,"\\",1,true) or string.find(temp,"/",1,true) then + temp=string.reverse(temp) + a,b=string.find(temp,"\\",1,true) + if not(a) or not(b) then + a,b=string.find(temp,"/",1,true) + end + return string.reverse(string.sub(temp,1,b-1)) + end + return temp +end +function io.getName(file) + local name=io.getFullName(file) + name=string.reverse(name) + a,b=string.find(name,".",1,true) + name=string.sub(name,a+1,-1) + return string.reverse(name) +end +function io.readFile(file) + local f = io.open(file, "rb") + local content = f:read("*all") + f:close() + return content +end +function io.getExtension(file) + local file=io.getFullName(file) + file=string.reverse(file) + local a,b=string.find(file,".",0,true) + local temp=string.sub(file,1,b) + return string.reverse(temp) +end +function io.pathToTable(path) + local p=io.splitPath(path) + local temp={} + temp[p[1]]={} + local last=temp[p[1]] + for i=2,#p do + snd=last + last[p[i]]={} + last=last[p[i]] + end + return temp,last,snd +end +function io.splitPath(str) + return string.split(str,'[\\/]+') +end + +function io.parseDir(dir,t) + io.tempFiles={} + function _p(dir) + local dirs=io.getDirectories(dir,true) + local files=io.getFiles(dir,true) + for i=1,#files do + p,l,s=io.pathToTable(files[i]) + if t then + s[io.getFullName(files[i])]=io.readFile(files[i]) + else + s[io.getFullName(files[i])]=io.open(files[i],"r+") + end + table.merge(io.tempFiles,p) + end + for i=1,#dirs do + table.merge(io.tempFiles,io.pathToTable(dirs[i])) + _p(dirs[i],t) + end + end + _p(dir) + return io.tempFiles +end +function io.parsedir(dir,f) + io.tempFiles={} + function _p(dir,f) + local dirs=io.getDirectories(dir,true) + local files=io.getFiles(dir,true) + for i=1,#files do + if not f then + table.insert(io.tempFiles,files[i]) + else + f(files[i]) + end + end + for i=1,#dirs do + _p(dirs[i],f) + end + end + _p(dir,f) + return io.tempFiles +end +function io.driveReady(drive) + drive=drive:upper() + if not(drive:find(":",1,true)) then + drive=drive..":" + end + drives=io.getDrives() + for i=1,#drives do + if drives[i]==drive then + return true + end + end + return false +end +function io.getDrives() + if os.getOS()=="windows" then + local temp={} + local t1=os.capture("wmic logicaldisk where drivetype=2 get deviceid, volumename",true) + local t2=os.capture("wmic logicaldisk where drivetype=3 get deviceid, volumename",true) + for drive,d2 in t1:gmatch("(.:)%s-(%w+)") do + if #d2>1 then + table.insert(temp,drive) + end + end + for drive in t2:gmatch("(.:)") do + table.insert(temp,drive) + end + return temp + end + error("Command is windows only!") +end +-- table Additions +function table.dump(t,indent) + local names = {} + if not indent then indent = "" end + for n,g in pairs(t) do + table.insert(names,n) + end + table.sort(names) + for i,n in pairs(names) do + local v = t[n] + if type(v) == "table" then + if(v==t) then + print(indent..tostring(n)..": <-") + else + print(indent..tostring(n)..":") + table.dump(v,indent.." ") + end + else + if type(v) == "function" then + print(indent..tostring(n).."()") + else + print(indent..tostring(n)..": "..tostring(v)) + end + end + end +end +function table.alphanumsort(o) + local function padnum(d) local dec, n = string.match(d, "(%.?)0*(.+)") + return #dec > 0 and ("%.12f"):format(d) or ("%s%03d%s"):format(dec, #n, n) + end + table.sort(o, function(a,b) return tostring(a):gsub("%.?%d+",padnum)..("%3d"):format(#b)< tostring(b):gsub("%.?%d+",padnum)..("%3d"):format(#a) end) + return o +end +function table.foreach(t,f) + for i,v in pairs(t) do + f(v) + end +end +function table.merge(t1, t2) + for k,v in pairs(t2) do + if type(v) == "table" then + if type(t1[k] or false) == "table" then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +function table.print(tbl, indent) + if not indent then indent = 0 end + for k, v in pairs(tbl) do + formatting = string.rep(" ", indent) .. k .. ": " + if type(v) == "table" then + print(formatting) + table.print(v, indent+1) + else + print(formatting .. tostring(v)) + end + end +end +function table.merge(t1, t2) + for k,v in pairs(t2) do + if type(v) == "table" then + if type(t1[k] or false) == "table" then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +function table.clear(t) + for k in pairs (t) do + t[k] = nil + end +end +function table.copy(t) + function deepcopy(orig) + local orig_type = type(orig) + local copy + if orig_type == 'table' then + copy = {} + for orig_key, orig_value in next, orig, nil do + copy[deepcopy(orig_key)] = deepcopy(orig_value) + end + setmetatable(copy, deepcopy(getmetatable(orig))) + else -- number, string, boolean, etc + copy = orig + end + return copy + end + return deepcopy(t) +end +function table.swap(tab,i1,i2) + tab[i1],tab[i2]=tab[i2],tab[i1] +end +function table.append(t1, ...) + t1,t2= t1 or {},{...} + for k,v in pairs(t2) do + t1[#t1+1]=t2[k] + end + return t1 +end +function table.compare(t1, t2,d) + if d then + return table.deepCompare(t1,t2) + end + --if #t1 ~= #t2 then return false end + if #t2>#t1 then + for i=1,#t2 do + if t1[i] ~= t2[i] then + return false,t2[i] + end + end + else + for i=1,#t1 do + if t1[i] ~= t2[i] then + return false,t2[i] + end + end + end + return true +end +function table.deepCompare(t1,t2) + if t1==t2 then return true end + if (type(t1)~="table") then return false end + local mt1 = getmetatable(t1) + local mt2 = getmetatable(t2) + if( not table.deepCompare(mt1,mt2) ) then return false end + for k1,v1 in pairs(t1) do + local v2 = t2[k1] + if( not table.deepCompare(v1,v2) ) then return false end + end + for k2,v2 in pairs(t2) do + local v1 = t1[k2] + if( not table.deepCompare(v1,v2) ) then return false end + end + return true +end +-- Math Additions +local Y = function(g) local a = function(f) return f(f) end return a(function(f) return g(function(x) local c=f(f) return c(x) end) end) end +local F = function(f) return function(n)if n == 0 then return 1 else return n*f(n-1) end end end +math.factorial = Y(F) +math.fib={} +math.fib.fibL={} +setmetatable(math.fib,{__call=function(self,n) + if n<=2 then + return 1 + else + if self.fibL[n] then + return self.fibL[n] + else + local t=math.fib(n-1)+math.fib(n-2) + self.fibL[n]=t + return t + end + end +end}) +local floor,insert = math.floor, table.insert +function math.basen(n,b) + n = floor(n) + if not b or b == 10 then return tostring(n) end + local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + local t = {} + local sign = "" + if n < 0 then + sign = "-" + n = -n + end + repeat + local d = (n % b) + 1 + n = floor(n / b) + insert(t, 1, digits:sub(d,d)) + until n == 0 + return sign .. table.concat(t,"") +end +function math.convbase(n,b,tb) + return math.basen(tonumber(tostring(n),b),tb) +end +if BigNum then + function BigNum.mod(a,b) + return a-((a/b)*b) + end + local floor,insert = math.floor, table.insert + function math.basen(n,b) + n = BigNum.new(n) + if not b or b == 10 then return tostring(n) end + local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + local t = {} + local sign = "" + if n < BigNum.new(0) then + sign = "-" + n = -n + end + repeat + local d = BigNum.mod(n , b) + 1 + n = n/b + d=tonumber(tostring(d)) + insert(t, 1, digits:sub(d,d)) + until tonumber(tostring(n)) == 0 + return sign .. table.concat(t,"") + end + function math.to10(n,b) + local num=tostring(n) + local sum=BigNum.new() + local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + for i=1,#num do + local v=digits:find(num:sub(i,i),1,true) + sum=sum+BigNum.new(tonumber(v)-1)*BigNum.pow(BigNum.new(b),BigNum.new(#num-i)) + end + return sum + end + function math.convbase(n,b,tb) + return math.basen(math.to10(n,b),tb) + end +end +function math.numfix(n,x) + local str=tostring(n) + if #str olleh +nil = binobj:flipbits() -- flips the binary bits +nil** = binobj:segment(a,b) -- gets a segment of the binobj data works just like string.sub(a,b) without str +nil* = binobj:insert(a,i) -- inserts i (string or number(converts into string)) in position a +nil* = binobj:parseN(n) -- removes ever (nth) byte of data +nil = binobj:getlength() -- gets length or size of binary data +nil* = binobj:shift(n) -- shift the binary data by n positive --> negitive <-- +nil* = binobj:delete(a,b) -- deletes part of a binobj data Usage: binobj:delete(#) deletes at pos # binobj:delete(#1,#2) deletes from #1 to #2 binobj:delete("string") deletes all instances of "byte" as a string Use string.char(#) or "\#" to get byte as a string +nil* = binobj:encrypt(seed) -- encrypts data using a seed, seed may be left blank +nil* = binobj:decrypt(seed) -- decrypts data encrypted with encrypt(seed) +nil* = binobj:shuffle() -- Shuffles the data randomly Note: there is no way to get it back!!! If original is needed clone beforehand +nil** = binobj:mutate(a,i) -- changes position a's value to i +nil = binobj:merge(o,t) -- o is the binobj you are merging if t is true it merges the new data to the left of the binobj EX: b:merge(o,true) b="yo" o="data" output: b="datayo" b:merge(o) b="yo" o="data" output: b="yodata" +nil* = binobj:parseA(n,a,t) -- n is every byte where you add, a is the data you are adding, t is true or false true before false after +nil = binobj:getHEX(a,b) -- returns the HEX of the bytes between a,b inclusive +nil = binobj:cryptM() -- a mirrorable encryptor/decryptor +nil = binobj:addBlock(d,n) -- adds a block of data to a binobj s is size d is data e is a bool if true then encrypts string values. if data is larger than 'n' then data is lost. n is the size of bytes the data is Note: n is no longer needed but you must use getBlock(type) to get it back +nil = binobj:getBlock(t,n) -- gets block of code by type +nil = binobj:seek(n) -- used with getBlock EX below with all 3 +nil* = binobj:morph(a,b,d) -- changes data between point a and b inclusive to d +nil = binobj:fill(n,d) -- fills binobj with data "d" for n +nil = binobj:fillrandom(n) -- fills binobj with random data for n +nil = binobj:shiftbits(n) -- shifts all bits by n amount +nil = binobj:shiftbit(n,i) -- shifts a bit ai index i by n +nil# = binobj:streamwrite(d,n) -- writes to the streamable binobj d data n position +nil# = binobj:open() -- opens the streamable binobj +nil# = binobj:close() -- closes the streamable binobj +nil# = binobj:wipe() -- erases all data in the file +nil* = binobj:tackB(d) -- adds data to the beginning of a file +nil = binobj:tackE(d) -- adds data to the end of a file +nil = binobj:parse(n,f) -- loops through each byte calling function 'f' with the args(i,binobj,data at i) +nil = binobj:flipbit(i) -- flips the binary bit at position i +nil* = binobj:gsub() -- just like string:gsub(), but mutates self + +numbers are written in Little-endian use bin.endianflop(d) to filp to Big-endian + +Note: binobj:tonumber() returns little,big so if printing do: l,b=binobj:tonumber() print(l) print(b) + +nil = bitobj:add(i) -- adds i to the bitobj i can be a number (base 10) or a bitobj +nil = bitobj:sub(i) -- subs i to the bitobj i can be a number (base 10) or a bitobj +nil = bitobj:multi(i) -- multiplys i to the bitobj i can be a number (base 10) or a bitobj +nil = bitobj:div(i) -- divides i to the bitobj i can be a number (base 10) or a bitobj +nil = bitobj:flipbits() -- filps the bits 1 --> 0, 0 --> 1 +string = bitobj:getBin() -- returns 1's & 0's of the bitobj + +# stream objects only +* not compatible with stream files +** works but do not use with large files or it works to some degree +*** all changes are made directly to the file no need to do tofile() +]] +bin.Changelog=[[ +Version.Major.Minor +------------------------- +1.0.0 : initial release load/new/tofile/clone/closeto/compare/sub/reverse/flip/segment/insert/insert/parseN/getlength/shift +1.0.1 : update Delete/tonumber/getbyte/ +1.0.2 : update Changed how delete works. Added encrypt/decrypt/shuffle +1.0.3 : update Added bits class, Added in bin: tobit/mutate/parseA Added in bits: add/sub/multi/div/isover/tobyte/tonumber/flip +1.0.4 : update Changed tobyte() to tobytes()/flipbit() to flipbits() and it now returns a binobj not str Added bin:merge +1.0.5 : update Changed bin.new() now hex data can be inserted EX: bin.new("0xFFC353D") Added in bin: getHEX/cryptM/addBlock/getBlock/seek +1.0.6 : update Added bin.NumtoHEX/bin:getHEX/bin.HEXtoBin/bin.HEXtoStr/bin.tohex/bin.fromhex +1.0.7 : update Added bin:morph/bin.endianflop/bin:scan/bin.ToStr +1.0.8 : update Added bin:fill/bin:fillrandom +1.1.0 : update Added bin.packLLIB/bin.unpackLLIB +1.2.0 : update Updated llib files +1.3.0 : Update Changed bin.unpackLLIB and bin.load() Added: bin.fileExist +1.4.0 : Update Changed bin.unpackLLIB bin.packLLIB Added: bin:shiftbits(n) bin:shiftbit(n,i) + +Woot!!! Version 2 +2.0.0 HUGE UPDATE Added Streamable files!!! lua 5.1, 5.2 and 5.3 compatable!!! +#binobj is the same as binobj:getlength() but only works in 5.2 in 5.1 just use getlength() for compatibility +Now you can work with gigabyte sized data without memory crashes(streamable files[WIP]). + +Stream Compatible methods: + sub(a,b) + getlength() + tofile(filename) + flipbits() + tonumber(a,b) + getbyte(n) + segment(a,b) + parse(n,f) + tobits(i) + reverse() + flipbit(i) + cryptM() + getBlock(t,n) + addBlock(d,n) + shiftbits(n) + shiftbit(n,i) + getHEX(a,b) + +Added functions in this version: + binobj:streamwrite(d,n) + binobj:open() + binobj:close() + binobj:tackB(d) + binobj:tackE(d) + binobj:parse(n,f) + binobj:flipbit(i) + bin.stream(file) + binobj:streamData(a,b) + bin.getVersion() + bin.escapeStr(str) + binobj:streamread(a,b) + binobj:canStreamWrite() + binobj:wipe() + +Woot!!! Version 3 +3.0.0 HUGE UPDATE!!! + Added: bin.newVFS() bin.loadVFS() bin.textToBinary(txt) bin.decodeBits(bindata) bitobj:getBin() + Updated: bin.addBlock() <-- Fixed error with added features to the bits.new() function that allow for new functions to work + Notice: The bin library now requires the utils library!!! Put utils.lua in the lua/ directory + +3.1.0 + Added: bin.newTempFile(data) binobj:setEndOfFile(n) bin.randomName(n,ext) + Updated: bin:tackE() bin:fill() bin:fillrandom() are now stream compatible! + Notic: bin:setEndOfFile() only works on streamable files! +3.1.1 + Added: bin.trimNul(s) bin:gsub() +3.1.2 + Added: log(data,name,fmt) + + In secret something is brewing... +]] +bin.data="" +bin.t="bin" +bin.__index = bin +bin.__tostring=function(self) return self.data end +bin.__len=function(self) return self:getlength() end +bits={} +bits.data="" +bits.t="bits" +bits.__index = bits +bits.__tostring=function(self) return self.data end +bits.__len=function(self) return (#self.data)/8 end +--[[---------------------------------------- +MISC +------------------------------------------]] +function log(data,name,fmt) + if not bin.logger then + bin.logger = bin.stream(name or "lua.log",false) + elseif bin.logger and name then + bin.logger:close() + bin.logger = bin.stream(name or "lua.log",false) + end + local d=os.date("*t",os.time()) + bin.logger:tackE((fmt or "["..math.numfix(d.month,2).."-"..math.numfix(d.day,2).."-"..d.year.."|"..math.numfix(d.hour,2)..":"..math.numfix(d.min,2)..":"..math.numfix(d.sec,2).."]\t")..data.."\n") +end +--[[---------------------------------------- +BIN +------------------------------------------]] +function bin.getVersion() + return bin.Version[1].."."..bin.Version[2].."."..bin.Version[3] +end +--[[function bin:gsub(...) + return self.data:gsub(...) +end +function bin:find(...) + return self.data:find(...) +end]] +function bin:gsub(...) + self.data=self.data:gsub(...) +end +function bin:find(...) + self.data=self.data:find(...) +end +function bin.fromhex(str) + return (str:gsub('..', function (cc) + return string.char(tonumber(cc, 16)) + end)) +end +if table.unpack==nil then + table.unpack=unpack +end +function bin.tohex(str) + return (str:gsub('.', function (c) + return string.format('%02X', string.byte(c)) + end)) +end +function bin:streamData(a,b) + if type(a)=="table" then + a,b,t=table.unpack(a) + end + if type(a)=="number" and type(b)=="string" then + return bin.load(self.file,a,b),bin.load(self.file,a,b).data + else + error("Invalid args!!! Is do you have a valid stream handle or is this a streamable object?") + end +end +function bin.new(data) + data=tostring(data) + local c = {} + setmetatable(c, bin) + data=data or "" + if string.sub(data,1,2)=="0x" then + data=string.sub(data,3) + data=bin.fromhex(data) + end + c.data=data + c.t="bin" + c.Stream=false + return c +end +function bin.stream(file,l) + local c=bin.new() + if bin.fileExist(file) then + c.file=file + c.lock = l + c.workingfile=io.open(file,"r+") + else + c.file=file + c.lock = l + c.workingfile=io.open(file,"w") + io.close(c.workingfile) + c.workingfile=io.open(file,"r+") + end + c.Stream=true + return c +end +function bin:streamwrite(d,n) + if self:canStreamWrite() then + if n then + self.workingfile:seek("set",n) + else + self.workingfile:seek("set",self.workingfile:seek("end")) + end + self.workingfile:write(d) + end +end +function bin:streamread(a,b) + a=tonumber(a) + b=tostring(b) + return bin.load(self.file,a,b).data +end +function bin:close() + if self:canStreamWrite() then + self.workingfile:close() + end +end +function bin:open() + if self:canStreamWrite() then + self.workingfile=io.open(self.file,"r+") + end +end +function bin:canStreamWrite() + return (self.Stream==true and self.lock==false) +end +function bin.load(file,s,r) + if not(s) or not(r) then + local f = io.open(file, "rb") + local content = f:read("*a") + f:close() + return bin.new(content) + end + s=s or 0 + r=r or -1 + if type(r)=="number" then + r=r+s-1 + elseif type(r)=="string" then + r=tonumber(r) or -1 + end + local f = io.open(file, "rb") + f:seek("set",s) + local content = f:read((r+1)-s) + f:close() + return bin.new(content) +end +function bin:tofile(filename) + if not(filename) or self.Stream then return nil end + io.mkFile(filename,self.data) +end +function bin.trimNul(s) + for i=1,#s do + if s:sub(i,i)=="\0" then + return s:sub(1,i-1) + end + end + return s +end +function bin:match(pat) + return self.data:match(pat) +end +function bin:gmatch(pat) + return self.data:gmatch(pat) +end +function bin.randomName(n,ext) + n=n or math.random(7,15) + if ext then + a,b=ext:find(".",1,true) + if a and b then + ext=ext:sub(2) + end + end + local str,h = "",0 + strings = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","1","2","3","4","5","6","7","8","9","0","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"} + for i=1,n do + h = math.random(1,#strings) + str = str..""..strings[h] + end + return str.."."..(ext or "tmp") +end +function bin.newTempFile(data) + data=data or "" + local name=bin.randomName() + bin.new():tofile(name) + local tempfile=bin.stream(name,false) + tempfile:streamwrite(data,0) + tempfile:setEndOfFile(#data) + return tempfile +end +function bin:wipe() + if self:canStreamWrite() then + os.remove(self.file) + else + self.data="" + end +end +function bin:setEndOfFile(n) + if self:canStreamWrite() then + local name=bin.randomName() + local tempfile=bin.stream(name,false) + tempfile:streamwrite(self:sub(0,n-1)) + self:close() + os.remove(self.file) + tempfile:close() + os.rename(name,self.file) + self:open() + tempfile=nil + else + self.data=self.data:sub(1,n) + end +end +function bin:reverse() + if self:canStreamWrite() then + local x,f,b=self:getlength(),0,0 + for i=0,math.floor((x-1)/2) do + self:streamwrite(self:sub(i+1,i+1),x-i-1) + self:streamwrite(self:sub(x-i,x-i),i) + end + elseif self.Stream==false then + self.data=string.reverse(self.data) + end +end +function bin:flipbits() + if self:canStreamWrite() then + for i=0,self:getlength()-1 do + self:streamwrite(string.char(255-string.byte(self:streamread(i,i))),i) + end + elseif self.Stream==false then + local temp={} + for i=1,#self.data do + table.insert(temp,string.char(255-string.byte(string.sub(self.data,i,i)))) + end + self.data=table.concat(temp,"") + end +end +function bin:flipbit(i) + if self:canStreamWrite() then + self:streamwrite(string.char(255-string.byte(self:streamread(i-1,i-1))),i-1) + elseif self.Stream==false then + self:mutate(string.char(255-string.byte(string.sub(self.data,i,i))),i) + end +end +function bin:segment(a,b) -- needs to be updated!!! + if self:canStreamWrite() then + --[[local pos=1 + for i=a,b do + self:streamwrite(self:sub(i,i),b-a-i) + end]] + local temp=self:sub(a,b) + self:close() + local f=io.open(self.file,"w") + f:write(temp) + io.close(f) + self:open() + elseif self.Stream==false then + self.data=string.sub(self.data,a,b) + end +end +function bin:insert(i,a) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + if type(i)=="number" then i=string.char(i) end + self.data=string.sub(self.data,1,a)..i..string.sub(self.data,a+1) + end +end +function bin:parseN(n) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + local temp={} + for i=1,#self.data do + if i%n==0 then + table.insert(temp,string.sub(self.data,i,i)) + end + end + self.data=table.concat(temp,"") + end +end +function bin:parse(n,f) + local f = f + local n=n or 1 + if not(f) then return end + for i=1,self:getlength() do + if i%n==0 then + f(i,self,self:sub(i,i)) + end + end +end +function bin.copy(file,tofile,s) + if not(s) then + bin.load(file):tofile(tofile) + else + rf=bin.stream(file) + wf=bin.stream(tofile,false) + for i=1,rf:getlength(),s do + wf:streamwrite(rf:sub(i,i-1+s)) + end + end +end +function bin:getlength() + if self.Stream then + local current = self.workingfile:seek() -- get current position + local size = self.workingfile:seek("end") -- get file size + self.workingfile:seek("set", current) -- restore position + return size + elseif self.Stream==false then + return #self.data + end +end +function bin:sub(a,b) + if self.Stream then + return bin.load(self.file,a-1,tostring(b-1)).data + elseif self.Stream==false then + return string.sub(self.data,a,b) + end +end +function bin:tackB(d) + if self:canStreamWrite() then + -- do something don't know if possible + elseif self.Stream==false then + self.data=d..self.data + end +end +function bin:tackE(d) + if type(d)=="table" then + if d:canStreamWrite() then + d=d:sub(0,d:getlength()) + else + d=d.data + end + end + if self:canStreamWrite() then + self:streamwrite(d) + elseif self.Stream==false then + self.data=self.data..d + end +end +function bin:clone(filename) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + return bin.new(self.data) + end +end +function bin.closeto(a,b,v) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + if type(a)~=type(b) then + error("Attempt to compare unlike types") + elseif type(a)=="number" and type(b)=="number" then + return math.abs(a-b)<=v + elseif type(a)=="table" and type(b)=="table" then + if a.data and b.data then + return (math.abs(string.byte(a.data)-string.byte(b.data)))<=v + else + error("Attempt to compare non-bin data") + end + elseif type(a)=="string" and type(b)=="string" then + return math.abs(string.byte(a)-string.byte(b))<=v + else + error("Attempt to compare non-bin data") + end + end +end +function bin:compare(_bin,t) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + t=t or 1 + local tab={} + local a,b=self:getlength(),_bin:getlength() + if not(a==b) then + print("Unequal Lengths!!! Equalizing...") + if a>b then + _bin.data=_bin.data..string.rep(string.char(0),a-b) + else + self.data=self.data..string.rep(string.char(0),b-a) + end + end + if t==1 then + for i=1,self:getlength() do + table.insert(tab,self:sub(i,i)==_bin:sub(i,i)) + end + else + for i=1,self:getlength() do + table.insert(tab,bin.closeto(self:sub(i,i),_bin:sub(i,i),t)) + end + end + local temp=0 + for i=1,#tab do + if tab[i]==true then + temp=temp+1 + end + end + return (temp/#tab)*100 + end +end +function bin:shift(n) + if self:canStreamWrite() then + local a,b,x,p="","",self:getlength(),0 + for i=1,x do + if i+n>x then + p=(i+n)-(x) + else + p=i+n + end + end + elseif self.Stream==false then + n=n or 0 + local s=#self.data + if n>0 then + self.data = string.sub(self.data,s-n+1)..string.sub(self.data,1,s-n) + elseif n<0 then + n=math.abs(n) + self.data = string.sub(self.data,n+1)..string.sub(self.data,1,n*1) + end + end +end +function bin:delete(a,b) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + if type(a)=="string" then + local tab={} + for i=1,self:getlength() do + if self:getbyte(i)~=string.byte(a) then + table.insert(tab,self:sub(i,i)) + end + end + self.data=table.concat(tab) + elseif a and not(b) then + self.data=self:sub(1,a-1)..self:sub(a+1) + elseif a and b then + self.data=self:sub(1,a-1)..self:sub(b+1) + else + self.data="" + end + end +end +function bin:tonumber(a,b) + local temp={} + if a then + temp.data=self:sub(a,b) + else + temp=self + end + local l,r=0,0 + local g=#temp.data + for i=1,g do + r=r+(256^(g)-i)*string.byte(string.sub(temp.data,i,i)) + l=l+(256^(i-1))*string.byte(string.sub(temp.data,i,i)) + end + return l,r +end +function bin:getbyte(n) + return string.byte(self:sub(n,n)) +end +function bin:encrypt(s) + if self:canStreamWrite() then + s=tonumber(s) or 4546 + math.randomseed(s) + self:shift(math.random(1,self:getlength())) + self:flipbits() + elseif self.Stream==false then + s=tonumber(s) or 4546 + math.randomseed(s) + self:shift(math.random(1,self:getlength())) + self:flipbits() + end +end +function bin:decrypt(s) + if self:canStreamWrite() then + s=tonumber(s) or 4546 + math.randomseed(s) + self:flipbits() + self:shift(-math.random(1,self:getlength())) + elseif self.Stream==false then + s=tonumber(s) or 4546 + math.randomseed(s) + self:flipbits() + self:shift(-math.random(1,self:getlength())) + end +end +function bin:shuffle(s) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + s=tonumber(s) or 4546 + math.randomseed(s) + local t={} + for i=1,self:getlength() do + table.insert(t,self:sub(i,i)) + end + local n = #t + while n >= 2 do + local k = math.random(n) + t[n], t[k] = t[k], t[n] + n = n - 1 + end + self.data=table.concat(t) + end +end +function bin:tobits(i) + return bits.new(self:getbyte(i)) +end +function bin:mutate(a,i) + if self:canStreamWrite() then + self:streamwrite(a,i-1) + elseif self.Stream==false then + self:delete(i) + self:insert(a,i-1) + end +end +function bin:parseA(n,a,t) + if self:canStreamWrite() then + -- do something + elseif self.Stream==false then + local temp={} + for i=1,#self.data do + if i%n==0 then + if t then + table.insert(temp,a) + table.insert(temp,string.sub(self.data,i,i)) + else + table.insert(temp,string.sub(self.data,i,i)) + table.insert(temp,a) + end + else + table.insert(temp,string.sub(self.data,i,i)) + end + end + self.data=table.concat(temp,"") + end +end +function bin:merge(o,t) + if self:canStreamWrite() then + self:close() + self.workingfile=io.open(self.file,"a+") + self.workingfile:write(o.data) + self:close() + self:open() + elseif self.Stream==false then + if not(t) then + self.data=self.data..o.data + else + seld.data=o.data..self.data + end + end +end +function bin:cryptM() + self:flipbits() + self:reverse() +end +function bin.escapeStr(str) + local temp="" + for i=1,#str do + temp=temp.."\\"..string.byte(string.sub(str,i,i)) + end + return temp +end +function bin.ToStr(t) + local dat="{" + for i,v in pairs(t) do + if type(i)=="number" then + i="["..i.."]=" + else + i="[\""..i.."\"]=" + end + if type(v)=="string" then + dat=dat..i.."[["..v.."]]," + elseif type(v)=="number" then + dat=dat..i..v.."," + elseif type(v)=="boolean" then + dat=dat..i..tostring(v).."," + elseif type(v)=="table" then + dat=dat..i..bin.ToStr(v).."," + elseif type(v)=="function" then + dat=dat..i.."assert(loadstring(\""..bin.escapeStr(string.dump(v)).."\"))," + end + end + return string.sub(dat,1,-2).."}" +end +function bin:addBlock(d,n,e) + local temp={} + if type(d)=="table" then + if d.t=="bin" then + temp=d + elseif d.t=="bit" then + temp=bin.new(d:tobytes()) + else + self:addBlock("return "..bin.ToStr(d)) + return + end + elseif type(d)=="string" then + temp=bin.new(d) + if e or not(n) then + temp.data=temp.data.."_EOF" + temp:flipbits() + end + elseif type(d)=="function" then + temp=bin.new(string.dump(d)) + if e or not(n) then + temp.data=temp.data.."_EOF" + temp:flipbits() + end + elseif type(d)=="number" then + local nn=tostring(d) + if nn:find(".",1,true) then + temp=bin.new(nn) + temp.data=temp.data.."_EOF" + temp:flipbits() + else + temp=bits.new(d):tobytes() + if not n then + temp.data=temp.data.."_EOF" + temp:flipbits() + end + end + elseif type(d)=="boolean" then + n=1 + if d then + temp=bits.new(math.random(0,127)):tobytes() + else + temp=bits.new(math.random(128,255)):tobytes() + end + end + if n then + if temp:getlength()n then + temp:segment(1,n) + end + end + self:merge(temp) +end +function bin:getBlock(t,n) + if not(self.Block) then + self.Block=1 + end + local x=self.Block + local temp=bin.new() + if n then + temp=bin.new(self:sub(x,x+n-1)) + self.Block=self.Block+n + end + if t=="stringe" or t=="stre" or t=="se" and n then + temp:flipbits() + return temp.data + elseif t=="string" or t=="str" or t=="s" and n then + return temp.data + elseif t=="number" or t=="num" or t=="n" and n then + return self:tonumber(x,x+n-1) + elseif t=="boolean" or t=="bool" or t=="b" then + self.Block=self.Block+1 + return self:tonumber(x,x)<127 + elseif t=="stringe" or t=="stre" or t=="se" or t=="string" or t=="str" or t=="s" then + local a,b=self:scan("_EOF",self.Block,true) + if not(b) then return nil end + local t=bin.new(self:sub(self.Block,b-4)) + t:flipbits() + self.Block=self.Block+t:getlength()+4 + return tostring(t) + elseif t=="table" or t=="tab" or t=="t" then + temp=self:getBlock("s") + if temp=="return }" then + return {} + end + return assert(loadstring(temp))() + elseif t=="function" or t=="func" or t=="f" then + return assert(loadstring(self:getBlock("s"))) + elseif t=="number" or t=="num" or t=="n" then + local num=bin.new(self:getBlock("s")) + if tonumber(num.data) then + return tonumber(num.data) + end + local a,b=num:tonumber() + return a + elseif n then + -- C data + else + print("Invalid Args!!!") + end +end +function bin:seek(n) + self.Block=self.Block+n +end +function bin.NumtoHEX(num) + local hexstr = '0123456789ABCDEF' + local s = '' + while num > 0 do + local mod = math.fmod(num, 16) + s = string.sub(hexstr, mod+1, mod+1) .. s + num = math.floor(num / 16) + end + if s == '' then + s = '0' + end + return s +end +function bin:getHEX(a,b,e) + a=a or 1 + local temp = self:sub(a,b) + if e then temp=string.reverse(temp) end + return bin.tohex(temp) +end +function bin.HEXtoBin(hex,e) + if e then + return bin.new(string.reverse(bin.fromhex(hex))) + else + return bin.new(bin.fromhex(hex)) + end +end +function bin.HEXtoStr(hex,e) + if e then + return string.reverse(bin.fromhex(hex)) + else + return bin.fromhex(hex) + end +end +function bin:morph(a,b,d) + if self:canStreamWrite() then + local len=self:getlength() + local temp=bin.newTempFile(self:sub(b+1,self:getlength())) + self:streamwrite(d,a-1) + print(temp:sub(1,temp:getlength())) + self:setEndOfFile(len+(b-a)+#d) + self:streamwrite(temp:sub(1,temp:getlength()),a-1) + temp:remove() + elseif self.Stream==false then + if a and b then + self.data=self:sub(1,a-1)..d..self:sub(b+1) + else + print("error both arguments must be numbers and the third a string") + end + end +end +function bin.endianflop(data,n) + n=n or 1 + local tab={} + for i=1,#data,n do + table.insert(tab,1,string.sub(data,i,i+1)) + end + return table.concat(tab) +end +function bin:scan(s,n,f) + n=n or 1 + if self.Stream then + for i=n,self:getlength() do + if f then + local temp=bin.new(self:sub(i,i+#s-1)) + temp:flipbits() + if temp.data==s then + return i,i+#s-1 + end + else + if self:sub(i,i+#s-1)==s then + return i,i+#s-1 + end + end + end + elseif self.Stream==false then + if f then + s=bin.new(s) + s:flipbits() + s=s.data + end + n=n or 1 + local a,b=string.find(self.data,s,n,true) + return a,b + end +end +function bin:fill(s,n) + if self:canStreamWrite() then + self:streamwrite(string.rep(s,n),0) + self:setEndOfFile(n*#s) + elseif self.Stream==false then + self.data=string.rep(s,n) + end +end +function bin:fillrandom(n) + if self:canStreamWrite() then + local t={} + for i=1,n do + table.insert(t,string.char(math.random(0,255))) + end + self:streamwrite(table.concat(t),0) + self:setEndOfFile(n) + elseif self.Stream==false then + local t={} + for i=1,n do + table.insert(t,string.char(math.random(0,255))) + end + self.data=table.concat(t) + end +end +function bin.packLLIB(name,tab,ext) + local temp=bin.new() + temp:addBlock("³Šž³–") + temp:addBlock(bin.getVersion()) + temp:addBlock(tab) + for i=1,#tab do + temp:addBlock(tab[i]) + temp:addBlock(bin.load(tab[i]).data) + end + temp:addBlock("Done") + temp:tofile(name.. ("."..ext or ".llib")) +end +function bin.unpackLLIB(name,exe,todir,over,ext) + local temp=bin.load(name..("."..ext or ".llib")) + local name="" + Head=temp:getBlock("s") + ver=temp:getBlock("s") + infiles=temp:getBlock("t") + if ver~=bin.getVersion() then + print("Incompatable llib file") + return nil + end + local tab={} + while name~="Done" do + name,data=temp:getBlock("s"),bin.new(temp:getBlock("s")) + if string.find(name,".lua",1,true) then + table.insert(tab,data.data) + else + if not(bin.fileExist((todir or "")..name) and not(over)) then + data:tofile((todir or "")..name) + end + end + end + os.remove((todir or "").."Done") + if exe then + for i=1,#tab do + assert(loadstring(tab[i]))() + end + end + return infiles +end +function bin.fileExist(path) + g=io.open(path or '','r') + if path =="" then + p="empty path" + return nil + end + if g~=nil and true or false then + p=(g~=nil and true or false) + end + if g~=nil then + io.close(g) + else + return false + end + return p +end +function bin:shiftbits(n) + if self:canStreamWrite() then + n=n or 0 + if n>=0 then + for i=0,self:getlength() do + print(string.byte(self:sub(i,i))+n%256) + self:streamwrite(string.char(string.byte(self:sub(i,i))+n%256),i-1) + end + else + n=math.abs(n) + for i=0,self:getlength() do + self:streamwrite(string.char((string.byte(self:sub(i,i))+(256-n%256))%256),i-1) + end + end + elseif self.Stream==false then + n=n or 0 + if n>=0 then + for i=1,self:getlength() do + self:morph(i,i,string.char(string.byte(self:sub(i,i))+n%256)) + end + else + n=math.abs(n) + for i=1,self:getlength() do + self:morph(i,i,string.char((string.byte(self:sub(i,i))+(256-n%256))%256)) + end + end + end +end +function bin:shiftbit(n,i) + if self:canStreamWrite() then + i=i-1 + n=n or 0 + if n>=0 then + self:streamwrite(string.char(string.byte(self:sub(i,i))+n%256),i) + else + n=math.abs(n) + self:streamwrite(string.char((string.byte(self:sub(i,i))+(256-n%256))%256),i) + end + elseif self.Stream==false then + n=n or 0 + if n>=0 then + self:morph(i,i,string.char(string.byte(self:sub(i,i))+n%256)) + else + n=math.abs(n) + self:morph(i,i,string.char((string.byte(self:sub(i,i))+(256-n%256))%256)) + end + end +end +function bin.decodeBits(par) + if type(par)=="table" then + if par.t=="bit" then + return bin.new(par:toSbytes()) + end + else + if par:find(" ") then + par=par:gsub(" ","") + end + local temp=bits.new() + temp.data=par + return bin.new((temp:toSbytes()):reverse()) + end +end +function bin.textToBinary(txt) + return bin.new(bits.new(txt:reverse()):getBin()) +end +--[[---------------------------------------- +VFS +------------------------------------------]] +local _require = require +function require(path,vfs) + if bin.fileExist(path..".lvfs") then + local data = bin.loadVFS(path..".lvfs") + if data:fileExist(vsf) then + loadstring(data:readFile(vfs))() + end + else + return _require(path) + end +end +function bin.loadVFS(path) + return bin.newVFS(bin.load(path):getBlock("t")) +end +function bin.copyDir(dir,todir) + local vfs=bin.newVFS(dir,true) + vfs:toFS(todir) + vfs=nil +end +function bin.newVFS(t,l) + if type(t)=="string" then + t=io.parseDir(t,l) + end + local c={} + c.FS= t or {} + function c:merge(vfs) + bin.newVFS(table.merge(self.FS,vfs.FS)) + end + function c:mkdir(path) + table.merge(self.FS,io.pathToTable(path)) + end + function c:scanDir(path) + path=path or "" + local tab={} + if path=="" then + for i,v in pairs(self.FS) do + tab[#tab+1]=i + end + return tab + end + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath-1 do + last=last[spath[i]] + end + return last[spath[#spath]] + end + function c:getFiles(path) + if not self:dirExist(path) then return end + path=path or "" + local tab={} + if path=="" then + for i,v in pairs(self.FS) do + if self:fileExist(i) then + tab[#tab+1]=i + end + end + return tab + end + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath-1 do + last=last[spath[i]] + end + local t=last[spath[#spath]] + for i,v in pairs(t) do + if self:fileExist(path.."/"..i) then + tab[#tab+1]=path.."/"..i + end + end + return tab + end + function c:getDirectories(path) + if not self:dirExist(path) then return end + path=path or "" + local tab={} + if path=="" then + for i,v in pairs(self.FS) do + if self:dirExist(i) then + tab[#tab+1]=i + end + end + return tab + end + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath-1 do + last=last[spath[i]] + end + local t=last[spath[#spath]] + for i,v in pairs(t) do + if self:dirExist(path.."/"..i) then + tab[#tab+1]=path.."/"..i + end + end + return tab + end + function c:mkfile(path,data) + local name=io.getFullName(path) + local temp=path:reverse() + local a,b=temp:find("/") + if not a then + a,b=temp:find("\\") + end + if a then + temp=temp:sub(a+1):reverse() + path=temp + local t,l=io.pathToTable(path) + l[name]=data + table.merge(self.FS,t) + else + self.FS[name]=data + end + end + function c:remove(path) + if path=="" or path==nil then return end + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath-1 do + last=last[spath[i]] + end + last[spath[#spath]]=nil + end + function c:readFile(path) + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath do + last=last[spath[i]] + end + if type(last)=="userdata" then + last=last:read("*all") + end + return last + end + function c:copyFile(p1,p2) + self:mkfile(p2,self:readFile(p1)) + end + function c:moveFile(p1,p2) + self:copyFile(p1,p2) + self:remove(p1) + end + function c:fileExist(path) + return type(self:readFile(path))=="string" + end + function c:dirExist(path) + if path=="" or path==nil then return end + spath=io.splitPath(path) + local last=self.FS + for i=1,#spath-1 do + last=last[spath[i]] + end + if last[spath[#spath]]~=nil then + if type(last[spath[#spath]])=="table" then + return true + end + end + return false + end + function c:tofile(path) + local temp=bin.new() + temp:addBlock(self.FS) + temp:tofile(path) + end + function c:toFS(path) + if path then + if path:sub(-1,-1)~="\\" then + path=path.."\\" + elseif path:find("/") then + path=path:gsub("/","\\") + end + io.mkDir(path) + else + path="" + end + function build(tbl, indent, folder) + if not indent then indent = 0 end + if not folder then folder = "" end + for k, v in pairs(tbl) do + formatting = string.rep(" ", indent) .. k .. ":" + if type(v) == "table" then + if v.t~=nil then + io.mkFile(folder..k,v.data,"wb") + else + if not(io.dirExists(path..folder..string.sub(formatting,1,-2))) then + io.mkDir(folder..string.sub(formatting,1,-2)) + end + build(v,0,folder..string.sub(formatting,1,-2).."\\") + end + elseif type(v)=="string" then + io.mkFile(folder..k,v,"wb") + elseif type(v)=="userdata" then + io.mkFile(folder..k,v:read("*all"),"wb") + end + end + end + build(self.FS,0,path) + end + function c:print() + table.print(self.FS) + end + return c +end +--[[---------------------------------------- +BITS +------------------------------------------]] +function bits.new(n) + if type(n)=="string" then + local t=tonumber(n,2) + if not t then + t={} + for i=#n,1,-1 do + table.insert(t,bits:conv(string.byte(n,i))) + end + n=table.concat(t) + else + n=t + end + end + local temp={} + temp.t="bit" + setmetatable(temp, bits) + if not type(n)=="string" then + local tab={} + while n>=1 do + table.insert(tab,n%2) + n=math.floor(n/2) + end + local str=string.reverse(table.concat(tab)) + if #str%8~=0 then + str=string.rep("0",8-#str%8)..str + end + temp.data=str + else + temp.data=n + end + setmetatable({__tostring=function(self) return self.data end},temp) + return temp +end +function bits:conv(n) + local tab={} + while n>=1 do + table.insert(tab,n%2) + n=math.floor(n/2) + end + local str=string.reverse(table.concat(tab)) + if #str%8~=0 then + str=string.rep("0",8-#str%8)..str + end + return str +end +function bits:add(i) + if type(i)=="number" then + i=bits.new(i) + end + self.data=self:conv(tonumber(self.data,2)+tonumber(i.data,2)) +end +function bits:sub(i) + if type(i)=="number" then + i=bits.new(i) + end + self.data=self:conv(tonumber(self.data,2)-tonumber(i.data,2)) +end +function bits:multi(i) + if type(i)=="number" then + i=bits.new(i) + end + self.data=self:conv(tonumber(self.data,2)*tonumber(i.data,2)) +end +function bits:div(i) + if type(i)=="number" then + i=bits.new(i) + end + self.data=self:conv(tonumber(self.data,2)/tonumber(i.data,2)) +end +function bits:tonumber(s) + if type(s)=="string" then + return tonumber(self.data,2) + end + s=s or 1 + return tonumber(string.sub(self.data,(8*(s-1))+1,8*s),2) or error("Bounds!") +end +function bits:isover() + return #self.data>8 +end +function bits:flipbits() + tab={} + for i=1,#self.data do + if string.sub(self.data,i,i)=="1" then + table.insert(tab,"0") + else + table.insert(tab,"1") + end + end + self.data=table.concat(tab) +end +function bits:tobytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return bin.new(table.concat(tab)) +end +function bits:toSbytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return table.concat(tab) +end +function bits:getBin() + return self.data +end +function bits:getbytes() + print(self.data) + return #self.data/8 +end diff --git a/GuiManager/init.lua b/GuiManager/init.lua new file mode 100644 index 0000000..f8da029 --- /dev/null +++ b/GuiManager/init.lua @@ -0,0 +1,87 @@ +local multi, thread = require("multi").init() +local GLOBAL,THREAD=require("multi.integration.loveManager").init() +local p = print +print = multi.print +-- automatic resource loading will be added soonish +utf8 = require("utf8") +gui = {} +gui.__index = gui +gui.TB={} +gui.Version="VERSION" -- Is it really ready for release? +_GuiPro={ + GLOBAL = GLOBAL, + THREAD = THREAD, + jobqueue = multi:newSystemThreadedJobQueue(), + imagecache = {}, + GBoost=true, + hasDrag=false, + DragItem={}, + Children={}, + Visible=true, + count=0, + x=0, + y=0, + height=0, + width=0, + getChildren=function(self) + return self.Children + end +} +_GuiPro.Clips={} +_GuiPro.rotate=0 +_defaultfont = love.graphics.setNewFont(12) +setmetatable(_GuiPro, gui) +function gui:LoadInterface(file) + local add=".int" + if string.find(file,".",1,true) then add="" end + if love.filesystem.getInfo(file..add) then + a,b=pcall(love.filesystem.load(file..add)) + if a then + --print("Loaded: "..file) + else + print("Error loading file: "..file,b) + end + else + print("File does not exist!") + return false + end +end +function gui.LoadAll(dir) + files=love.filesystem.getDirectoryItems(dir) + for i=1,#files do + if string.sub(files[i],-4)==".int" then + gui:LoadInterface(dir.."/"..files[i]) + end + end +end +-- Start Of Load + +gui.LoadAll("GuiManager/Core") +gui.LoadAll("GuiManager/Image-Animation") +gui.LoadAll("GuiManager/Frame") +gui.LoadAll("GuiManager/Item") +gui.LoadAll("GuiManager/Misc") +gui.LoadAll("GuiManager/Text") +gui.LoadAll("GuiManager/Drawing") + +-- End of Load +gui:respectHierarchy() +_GuiPro.width,_GuiPro.height=love.graphics.getDimensions() +multi:newThread("GuiManager",function() + while true do + thread.sleep(.01) + _GuiPro.width,_GuiPro.height=love.graphics.getDimensions() + end +end) +multi:onDraw(function() + local items=GetAllChildren(_GuiPro) + for i=1,#items do + items[i]:draw() + end +end) +gui.ff=gui:newFrame("",0,0,0,0,0,0,1,1) +gui.ff.Color={0,0,0} +gui.ff:OnUpdate(function(self) + self:BottomStack() +end) +print = p diff --git a/GuiManager/merger.lua b/GuiManager/merger.lua new file mode 100644 index 0000000..d4187a8 --- /dev/null +++ b/GuiManager/merger.lua @@ -0,0 +1,39 @@ +require("utils") +require("bin") +print("Library binder version 1.0\n") +ver=io.getInput("Version #? ") +merged=bin.new() +init=bin.load("GuiManager/init.lua") +init:gsub("gui.Version=\"VERSION\"","gui.Version=\""..ver.."\"") +print("Parsing init file...") +a,b=init.data:find("-- Start Of Load") +c,d=init.data:find("-- End of Load") +_o=init:sub(b+1,c-1) +print("Setting up headers...") +start=init:sub(1,a-1) +_end=init:sub(d+1,-1) +merged:tackE(start.."\n") +print("Parsing paths...") +for path in _o:gmatch("\"(.-)\"") do + files=io.scanDir(path) + for i=1,#files do + merged:tackE(bin.load(path.."/"..files[i]).data.."\n") + end +end +merged:tackE(_end.."\n") +print("Finishing up...") +merged:tofile("GuiManager.lua") +print("GuiManager.lua has been created!") +os.sleep(3) +--[[ +-- Start Of Load +gui.LoadAll("GuiManager/Core") +gui.LoadAll("GuiManager/Animation") +gui.LoadAll("GuiManager/Frame") +gui.LoadAll("GuiManager/Image") +gui.LoadAll("GuiManager/Item") +gui.LoadAll("GuiManager/Misc") +gui.LoadAll("GuiManager/Text") +gui.LoadAll("GuiManager/Drawing") +-- End of Load +]] diff --git a/Library.lua b/Library.lua new file mode 100644 index 0000000..8260136 --- /dev/null +++ b/Library.lua @@ -0,0 +1,319 @@ +if table.unpack then + unpack=table.unpack +end +function table.val_to_str ( v ) + if "string" == type( v ) then + v = string.gsub( v, "\n", "\\n" ) + if string.match( string.gsub(v,"[^'\"]",""), '^"+$' ) then + return "'" .. v .. "'" + end + return '"' .. string.gsub(v,'"', '\\"' ) .. '"' + else + return "table" == type( v ) and table.tostring( v ) or + tostring( v ) + end +end + +function table.key_to_str ( k ) + if "string" == type( k ) and string.match( k, "^[_%a][_%a%d]*$" ) then + return k + else + return "[" .. table.val_to_str( k ) .. "]" + end +end + +function table.tostring( tbl ) + local result, done = {}, {} + for k, v in ipairs( tbl ) do + table.insert( result, table.val_to_str( v ) ) + done[ k ] = true + end + for k, v in pairs( tbl ) do + if not done[ k ] then + table.insert( result, + table.key_to_str( k ) .. "=" .. table.val_to_str( v ) ) + end + end + return "{" .. table.concat( result, "," ) .. "}" +end +function table.merge(t1, t2) + t1,t2= t1 or {},t2 or {} + for k,v in pairs(t2) do + if type(v) == "table" then + if type(t1[k] or false) == "table" then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +Library={} +function Library.optimize(func) + local test=Library.convert(func) + rawset(test,"link",{}) + rawset(test,"last","") + rawset(test,"org",func) + test:inject(function(...) + rawset(test,"last",table.tostring({...})) + if test.link[test.last]~=nil then + return Library.forceReturn(unpack(test.link[test.last])) + end + return {...} + end,1) + test:inject(function(...) + test.link[test.last]={test.org(...)} + return test.org(...) + end) + return test +end +function Library.forceReturn(...) + return {[0]="\1\7\6\3\2\99\125",...} +end +function Library.inject(lib,dat,arg) + if type(lib)=="table" then + if type(dat)=="table" then + table.merge(lib,dat) + elseif type(dat)=="string" then + if lib.Version and dat:match("(%d-)%.(%d-)%.(%d-)") then + lib.Version={dat:match("(%d+)%.(%d+)%.(%d+)")} + elseif dat=="meta" and type(arg)=="table" then + local _mt=getmetatable(lib) or {} + local mt={} + table.merge(mt,arg) + table.merge(_mt,mt) + setmetatable(lib,_mt) + elseif dat=="compat" then + lib["getVersion"]=function(self) return self.Version[1].."."..self.Version[2].."."..self.Version[3] end + if not lib.Version then + lib.Version={1,0,0} + end + elseif dat=="inhert" then + if not(lib["!%"..arg.."%!"]) then print("Wrong Password!!") return end + lib["!%"..arg.."%!"].__index=lib["!!%"..arg.."%!!"] + end + elseif type(dat)=="function" then + for i,v in pairs(lib) do + dat(lib,i,v) + end + end + elseif type(lib)=="function" or type(lib)=="userdata" then + if lib==unpack then + print("function unpack cannot yet be injected!") + return unpack + elseif lib==pairs then + print("function pairs cannot yet be injected!") + return lib + elseif lib==ipairs then + print("function ipairs cannot yet be injected!") + return lib + elseif lib==type then + print("function type cannot yet be injected!") + return lib + end + temp={} + local mt={ + __call=function(t,...) + local consume,MainRet,init={},{},{...} + local tt={} + for i=1,#t.__Link do + tt={} + if t.__Link[i]==t.__Main then + if #consume~=0 then + MainRet={t.__Link[i](unpack(consume))} + else + MainRet={t.__Link[i](unpack(init))} + end + else + if i==1 then + consume=(t.__Link[i](unpack(init))) + else + if type(MainRet)=="table" then + table.merge(tt,MainRet) + end + if type(consume)=="table" then + table.merge(tt,consume) + end + consume={t.__Link[i](unpack(tt))} + end + if i==#t.__Link then + return unpack(consume) + end + if consume then if consume[0]=="\1\7\6\3\2\99\125" then consume[0]=nil return unpack(consume) end end + end + end + if type(MainRet)=="table" then + table.merge(tt,MainRet) + end + if type(consume)=="table" then + table.merge(tt,consume) + end + return unpack(tt) + end, + } + temp.__Link={lib} + temp.__Main=lib + temp.__self=temp + function temp:inject(func,i) + if i then + table.insert(self.__Link,i,func) + else + table.insert(self.__Link,func) + end + end + function temp:consume(func) + for i=1,#self.__Link do + if self.__Link[i]==self.__Main then + self.__Link[i]=func + self.__self.__Main=func + return true + end + end + return false + end + setmetatable(temp,mt) + Library.protect(temp,"lolz") + return temp + else + return "arg1 must be a table or a function" + end +end +function Library.parse(lib) + for i,v in pairs(lib) do + print(i,v) + end +end +function Library.protect(lib,pass) + pass=pass or "*" + local mt={} + local test={ + __index = lib, + __newindex = function(tab, key, value) + local t,b=key:find(tab["!%"..pass.."%!"].__pass,1,true) + if t then + local _k=key:sub(b+1) + rawset(tab,_k,value) + else + error("Cannot alter a protected library!") + end + end, + __metatable = false, + __pass=pass or "*" + } + local _mt=getmetatable(lib) or {} + table.merge(mt,_mt) + table.merge(mt,test) + lib["!%"..pass.."%!"]=test + lib["!!%"..pass.."%!!"]=lib + local temp=setmetatable({},mt) + for i,v in pairs(_G) do + if v==lib then + _G[i]=temp + Library(function(link) + link[i]=v + end) + end + end +end +function Library.unprotect(lib,pass) + if not(lib["!%"..pass.."%!"]) then print("Wrong Password or Library is not Protected!") return end + if lib["!%"..pass.."%!"].__pass==pass then + lib["!%"..pass.."%!"].__newindex=lib["!!%"..pass.."%!!"] + lib["!%"..pass.."%!"].__index=nil + lib["!%"..pass.."%!"].__newindex=nil + lib["!%"..pass.."%!"].__metatable = true + setmetatable(lib["!!%"..pass.."%!!"],lib["!%"..pass.."%!"]) + for i,v in pairs(_G) do + if v==lib then + _G[i]=lib["!!%"..pass.."%!!"] + end + end + lib["!!%"..pass.."%!!"]["!%"..pass.."%!"]=nil + lib["!!%"..pass.."%!!"]["!!%"..pass.."%!!"]=nil + else + print("Wrong Password!!!") + end +end +function Library.addPoll(lib,polldata,ref) + lib.__polldata={} + Library.inject(lib.__polldata,polldata) + if type(ref)=="table" then + Library.inject(ref,"meta",{__newindex=function(t,k,v) + t[k].__polldata=polldata + end}) + end +end +function Library.newPollData(t) + local temp={} + temp.__onPolled=function() end + temp.__pollData=false + temp.__advDisc="" + temp.__pollcalls=-1 -- infinte + for i,v in pairs(t) do + if type(v)=="string" then + temp.__advDisc=v + elseif type(v)=="number" then + temp.__pollcalls=v + elseif type(v)=="table" then + temp[v[1]]=v[2] + elseif type(v)=="function" then + temp.__onPolled=v + elseif type(v)=="boolean" then + temp.__pollData=v + else + temp.__userdata=v + end + end + return temp +end +function Library.convert(...) + local temp,rets={...},{} + for i=1,#temp do + if type(temp[i])=="function" then + table.insert(rets,Library.inject(temp[i])) + else + error("Takes only functions and returns in order from functions given. arg # "..i.." is not a function!!! It is a "..type(temp[i])) + end + end + return unpack(rets) +end +function Library.convertIn(...) + local temp,list={...},{} + for i=1,#temp do + if type(temp[i])=="table" then + for k,v in pairs(temp[i]) do + if type(v)=="function" then + temp[i][k]=Library.inject(temp[i][k]) + end + end + else + error("Takes only tables! Arg "..i.." isn't it is a "..type(temp[i])) + end + end +end +function Library.newInjectedFunction() + return Library.convert(function(...) return unpack{...} end) +end +function Library.capulate(lib) + Library.inject(lib,"meta",{ + __index=function(t,k,v) + for i,_v in pairs(t) do + if k:lower()==i:lower() then + return t[i] + end + end + end, + __newindex=function(t,k,v) + rawset(t,k:lower(),v) + end + }) +end +local link={MainLibrary=Library} +Library.inject(Library,"meta",{ + __Link=link, + __call=function(self,func) func(link) end, +}) +--Library.protect(Library,"N@#P!KLkk1(93320") diff --git a/app.lua b/app.lua new file mode 100644 index 0000000..8ae1c70 --- /dev/null +++ b/app.lua @@ -0,0 +1,88 @@ +multi, thread = require("multi").init() +GLOBAL, THREAD = require("multi.integration.loveManager").init() +theme = {} +theme.menu = Color.new("70687C") +theme.header = Color.new("4B566D") +theme.button = Color.new("F45C35") +theme.input = Color.new("F9988B") +theme.menuitem = Color.new("7F5767") + +local app = {} +app.pages = {} +local headersize = 80 +local menusize = 350 +local spdt = .005 +local spd = 7 +local sliderActive = false +local mm,bb +-- keep at top +local slider = thread:newFunction(function() + local menu,button = mm,bb + if sliderActive then return end + sliderActive = true + if not menu.Visible then + menu.Visible = true + for i=menusize/5,1,-1 do + menu:SetDualDim(-i*spd) + thread.sleep(spdt) + end + menu:SetDualDim(0) + button:SetImage("images/menuX.png") + else + for i=1,menusize/5 do + thread.sleep(spdt) + menu:SetDualDim(-i*spd) + end + menu.Visible = false + button:SetImage("images/menu.png") + end + sliderActive = false +end) +function app.createPage(name,path) + local page = require("pages/"..path).init(app.workspace:newFullFrame(name),app.workspace) + page.Color = theme.menu + table.insert(app.pages,page) + page.Visible = false + page:SetDualDim(nil,nil,nil,nil,.1,.1,.8,.8) + page:setRoundness(10,10,180) + function page:Goto() + for i,v in pairs(app.pages) do + v.Visible = false + end + page.Visible = true + end + local button = app.menu:newTextLabel(name,name,0,(#app.pages-1)*(headersize/2),0,headersize/2,0,0,1) + button:fitFont() + button.Color = theme.menuitem + button:OnReleased(function() + page:Goto() + slider() + end) + return page +end +local function init(a) + app.header = a:newFrame(0,0,0,headersize,0,0,1) + app.header.Color = theme.header + app.workspace = a:newFrame(0,headersize,0,-headersize,0,0,1,1) + app.menu = a:newFrame(0,headersize,menusize,-headersize,0,0,0,1) + app.menu.Color = theme.menu + app.menu:OnReleasedOuter(function(b,self) + if self.Visible then + slider() + end + end) + app.workspace.Color = Color.Black + app.menu.Visible = false + local menubutton = app.header:newImageLabel("images/menu.png",0,0,headersize,headersize) + menubutton.BorderSize = 0 + mm,bb = app.menu,menubutton + menubutton:OnReleased(function() + slider() + end) + local search = app.createPage("Search","search") + app.createPage("Favorites","favs") + search:Goto() +end +return { + init = init +} diff --git a/bin/compressors/lzw.lua b/bin/compressors/lzw.lua new file mode 100644 index 0000000..57653b3 --- /dev/null +++ b/bin/compressors/lzw.lua @@ -0,0 +1,73 @@ +--[[ +LZW String Compression demo for Gideros +This code is MIT licensed, see http://www.opensource.org/licenses/mit-license.php +(C) 2013 - Guava7 +]] +CLZWCompression = {} +function CLZWCompression:InitDictionary(isEncode) + self.mDictionary = {} + -- local s = " !#$%&'\"()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" + local s={} + for i=1,255 do + s[#s+1]=string.char(i) + end + s=table.concat(s) + local len = #s + for i = 1, len do + if isEncode then + self.mDictionary[s:sub(i, i)] = i + else + self.mDictionary[i] = s:sub(i, i) + end + end + self.mDictionaryLen = len +end +function CLZWCompression:Encode(sInput) + self:InitDictionary(true) + local s = "" + local ch + local len = #sInput + local result = {} + local dic = self.mDictionary + local temp + for i = 1, len do + ch = sInput:sub(i, i) + temp = s..ch + if dic[temp] then + s = temp + else + result[#result + 1] = dic[s] + self.mDictionaryLen = self.mDictionaryLen + 1 + dic[temp] = self.mDictionaryLen + s = ch + end + end + result[#result + 1] = dic[s] + return result +end +function CLZWCompression:Decode(data) + self:InitDictionary(false) + local dic = self.mDictionary + local entry + local ch + local prevCode, currCode + local result = {} + prevCode = data[1] + result[#result + 1] = dic[prevCode] + for i = 2, #data do + currCode = data[i] + entry = dic[currCode] + if entry then + ch = entry:sub(1, 1) + result[#result + 1] = entry + else + ch = dic[prevCode]:sub(1, 1) + result[#result + 1] = dic[prevCode]..ch + end + dic[#dic + 1] = dic[prevCode]..ch + prevCode = currCode + end + return table.concat(result) +end + +return CLZWCompression diff --git a/bin/converters/base64.lua b/bin/converters/base64.lua new file mode 100644 index 0000000..d66cc90 --- /dev/null +++ b/bin/converters/base64.lua @@ -0,0 +1,40 @@ +local bin = require("bin") +local base64={} +local bs = { [0] = + 'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P', + 'Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f', + 'g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v', + 'w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/', +} +local bsd=table.flip(bs) +local char=string.char +function base64.encode(s) + local byte, rep, pad = string.byte, string.rep, 2 - ((#s-1) % 3) + s = (s..rep('\0', pad)):gsub("...", function(cs) + local a, b, c = byte(cs, 1, 3) + return bs[bit.rshift(a,2)] .. bs[bit.bor(bit.lshift(bit.band(a,3),4),bit.rshift(b,4))] .. bs[bit.bor(bit.lshift(bit.band(b,15),2),bit.rshift(c,6))] .. bs[bit.band(c,63)] + end) + return s:sub(1, #s-pad) .. rep('=', pad) +end +function base64.decode(s) + local s=s:match("["..s.."=]+") + local p,cc=s:gsub("=","A") + local r="" + local n=0 + s=s:sub(1,#s-#p)..p + for c = 1,#s,4 do + n = bit.lshift(bsd[s:sub(c, c)], 18) + bit.lshift(bsd[s:sub(c+1, c+1)], 12) + bit.lshift(bsd[s:sub(c + 2, c + 2)], 6) + bsd[s:sub(c + 3, c + 3)] + r = r .. char(bit.band(bit.arshift(n, 16), 0xFF)) .. char(bit.band(bit.arshift(n, 8), 0xFF)) .. char(bit.band(n, 0xFF)) + end + return r:sub(1,-(cc+1)) +end +function bin.newFromBase91(data) + return bin.new(bin.fromBase91(data)) +end +function bin.toBase91(s) + return base91.encode(s) +end +function bin.fromBase91(s) + return base91.decode(s) +end +return base64 diff --git a/bin/converters/base91.lua b/bin/converters/base91.lua new file mode 100644 index 0000000..cb2f447 --- /dev/null +++ b/bin/converters/base91.lua @@ -0,0 +1,82 @@ +local bin = require("bin") +local base91={} +local b91enc={[0]= + 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', + 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', + 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', + 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '!', '#', '$', + '%', '&', '(', ')', '*', '+', ',', '.', '/', ':', ';', '<', '=', + '>', '?', '@', '[', ']', '^', '_', '`', '{', '|', '}', '~', '"' +} +local b91dec=table.flip(b91enc) +function base91.decode(d) + local l,v,o,b,n = #d,-1,"",0,0 + for i in d:gmatch(".") do + local c=b91dec[i] + if not(c) then + -- Continue + else + if v < 0 then + v = c + else + v = v+c*91 + b = bit.bor(b, bit.lshift(v,n)) + if bit.band(v,8191) then + n = n + 13 + else + n = n + 14 + end + while true do + o=o..string.char(bit.band(b,255)) + b=bit.rshift(b,8) + n=n-8 + if not (n>7) then + break + end + end + v=-1 + end + end + end + if v + 1>0 then + o=o..string.char(bit.band(bit.bor(b,bit.lshift(v,n)),255)) + end + return o +end +function base91.encode(d) + local b,n,o,l=0,0,"",#d + for i in d:gmatch(".") do + b=bit.bor(b,bit.lshift(string.byte(i),n)) + n=n+8 + if n>13 then + v=bit.band(b,8191) + if v>88 then + b=bit.rshift(b,13) + n=n-13 + else + v=bit.band(b,16383) + b=bit.rshift(b,14) + n=n-14 + end + o=o..b91enc[v % 91] .. b91enc[math.floor(v / 91)] + end + end + if n>0 then + o=o..b91enc[b % 91] + if n>7 or b>90 then + o=o .. b91enc[math.floor(b / 91)] + end + end + return o +end +function bin.newFromBase64(data) + return bin.new(bin.fromBase64(data)) +end +function bin.toBase64(s) + return base64.encode(s) +end +function bin.fromBase64(s) + return base64.decode(s) +end +return base91 diff --git a/bin/hashes/md5.lua b/bin/hashes/md5.lua new file mode 100644 index 0000000..c2cc716 --- /dev/null +++ b/bin/hashes/md5.lua @@ -0,0 +1,394 @@ +local bin = require("bin") +local md5 = { + _VERSION = "md5.lua 1.1.0", + _DESCRIPTION = "MD5 computation in Lua (5.1-3, LuaJIT)", + _URL = "https://github.com/kikito/md5.lua", + _LICENSE = [[ + MIT LICENSE + + Copyright (c) 2013 Enrique García Cota + Adam Baldwin + hanzao + Equi 4 Software + ]] +} + +-- bit lib implementions + +local char, byte, format, rep, sub = + string.char, string.byte, string.format, string.rep, string.sub +local bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift + +local ok, bit = pcall(require, 'bit') +if ok then + bit_or, bit_and, bit_not, bit_xor, bit_rshift, bit_lshift = bit.bor, bit.band, bit.bnot, bit.bxor, bit.rshift, bit.lshift +else + ok, bit = pcall(require, 'bit32') + + if ok then + + bit_not = bit.bnot + + local tobit = function(n) + return n <= 0x7fffffff and n or -(bit_not(n) + 1) + end + + local normalize = function(f) + return function(a,b) return tobit(f(tobit(a), tobit(b))) end + end + + bit_or, bit_and, bit_xor = normalize(bit.bor), normalize(bit.band), normalize(bit.bxor) + bit_rshift, bit_lshift = normalize(bit.rshift), normalize(bit.lshift) + + else + + local function tbl2number(tbl) + local result = 0 + local power = 1 + for i = 1, #tbl do + result = result + tbl[i] * power + power = power * 2 + end + return result + end + + local function expand(t1, t2) + local big, small = t1, t2 + if(#big < #small) then + big, small = small, big + end + -- expand small + for i = #small + 1, #big do + small[i] = 0 + end + end + + local to_bits -- needs to be declared before bit_not + + bit_not = function(n) + local tbl = to_bits(n) + local size = math.max(#tbl, 32) + for i = 1, size do + if(tbl[i] == 1) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + return tbl2number(tbl) + end + + -- defined as local above + to_bits = function (n) + if(n < 0) then + -- negative + return to_bits(bit_not(math.abs(n)) + 1) + end + -- to bits table + local tbl = {} + local cnt = 1 + local last + while n > 0 do + last = n % 2 + tbl[cnt] = last + n = (n-last)/2 + cnt = cnt + 1 + end + + return tbl + end + + bit_or = function(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + for i = 1, #tbl_m do + if(tbl_m[i]== 0 and tbl_n[i] == 0) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + + return tbl2number(tbl) + end + + bit_and = function(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + for i = 1, #tbl_m do + if(tbl_m[i]== 0 or tbl_n[i] == 0) then + tbl[i] = 0 + else + tbl[i] = 1 + end + end + + return tbl2number(tbl) + end + + bit_xor = function(m, n) + local tbl_m = to_bits(m) + local tbl_n = to_bits(n) + expand(tbl_m, tbl_n) + + local tbl = {} + for i = 1, #tbl_m do + if(tbl_m[i] ~= tbl_n[i]) then + tbl[i] = 1 + else + tbl[i] = 0 + end + end + + return tbl2number(tbl) + end + + bit_rshift = function(n, bits) + local high_bit = 0 + if(n < 0) then + -- negative + n = bit_not(math.abs(n)) + 1 + high_bit = 0x80000000 + end + + local floor = math.floor + + for i=1, bits do + n = n/2 + n = bit_or(floor(n), high_bit) + end + return floor(n) + end + + bit_lshift = function(n, bits) + if(n < 0) then + -- negative + n = bit_not(math.abs(n)) + 1 + end + + for i=1, bits do + n = n*2 + end + return bit_and(n, 0xFFFFFFFF) + end + end +end + +-- convert little-endian 32-bit int to a 4-char string +local function lei2str(i) + local f=function (s) return char( bit_and( bit_rshift(i, s), 255)) end + return f(0)..f(8)..f(16)..f(24) +end + +-- convert raw string to big-endian int +local function str2bei(s) + local v=0 + for i=1, #s do + v = v * 256 + byte(s, i) + end + return v +end + +-- convert raw string to little-endian int +local function str2lei(s) + local v=0 + for i = #s,1,-1 do + v = v*256 + byte(s, i) + end + return v +end + +-- cut up a string in little-endian ints of given size +local function cut_le_str(s,...) + local o, r = 1, {} + local args = {...} + for i=1, #args do + table.insert(r, str2lei(sub(s, o, o + args[i] - 1))) + o = o + args[i] + end + return r +end + +local swap = function (w) return str2bei(lei2str(w)) end + +-- An MD5 mplementation in Lua, requires bitlib (hacked to use LuaBit from above, ugh) +-- 10/02/2001 jcw@equi4.com + +local CONSTS = { + 0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee, + 0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501, + 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, + 0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821, + 0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa, + 0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8, + 0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed, + 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, + 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, + 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, + 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, + 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, + 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, + 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, + 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, + 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391, + 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476 +} + +local f=function (x,y,z) return bit_or(bit_and(x,y),bit_and(-x-1,z)) end +local g=function (x,y,z) return bit_or(bit_and(x,z),bit_and(y,-z-1)) end +local h=function (x,y,z) return bit_xor(x,bit_xor(y,z)) end +local i=function (x,y,z) return bit_xor(y,bit_or(x,-z-1)) end +local z=function (ff,a,b,c,d,x,s,ac) + a=bit_and(a+ff(b,c,d)+x+ac,0xFFFFFFFF) + -- be *very* careful that left shift does not cause rounding! + return bit_or(bit_lshift(bit_and(a,bit_rshift(0xFFFFFFFF,s)),s),bit_rshift(a,32-s))+b +end + +local function transform(A,B,C,D,X) + local a,b,c,d=A,B,C,D + local t=CONSTS + + a=z(f,a,b,c,d,X[ 0], 7,t[ 1]) + d=z(f,d,a,b,c,X[ 1],12,t[ 2]) + c=z(f,c,d,a,b,X[ 2],17,t[ 3]) + b=z(f,b,c,d,a,X[ 3],22,t[ 4]) + a=z(f,a,b,c,d,X[ 4], 7,t[ 5]) + d=z(f,d,a,b,c,X[ 5],12,t[ 6]) + c=z(f,c,d,a,b,X[ 6],17,t[ 7]) + b=z(f,b,c,d,a,X[ 7],22,t[ 8]) + a=z(f,a,b,c,d,X[ 8], 7,t[ 9]) + d=z(f,d,a,b,c,X[ 9],12,t[10]) + c=z(f,c,d,a,b,X[10],17,t[11]) + b=z(f,b,c,d,a,X[11],22,t[12]) + a=z(f,a,b,c,d,X[12], 7,t[13]) + d=z(f,d,a,b,c,X[13],12,t[14]) + c=z(f,c,d,a,b,X[14],17,t[15]) + b=z(f,b,c,d,a,X[15],22,t[16]) + + a=z(g,a,b,c,d,X[ 1], 5,t[17]) + d=z(g,d,a,b,c,X[ 6], 9,t[18]) + c=z(g,c,d,a,b,X[11],14,t[19]) + b=z(g,b,c,d,a,X[ 0],20,t[20]) + a=z(g,a,b,c,d,X[ 5], 5,t[21]) + d=z(g,d,a,b,c,X[10], 9,t[22]) + c=z(g,c,d,a,b,X[15],14,t[23]) + b=z(g,b,c,d,a,X[ 4],20,t[24]) + a=z(g,a,b,c,d,X[ 9], 5,t[25]) + d=z(g,d,a,b,c,X[14], 9,t[26]) + c=z(g,c,d,a,b,X[ 3],14,t[27]) + b=z(g,b,c,d,a,X[ 8],20,t[28]) + a=z(g,a,b,c,d,X[13], 5,t[29]) + d=z(g,d,a,b,c,X[ 2], 9,t[30]) + c=z(g,c,d,a,b,X[ 7],14,t[31]) + b=z(g,b,c,d,a,X[12],20,t[32]) + + a=z(h,a,b,c,d,X[ 5], 4,t[33]) + d=z(h,d,a,b,c,X[ 8],11,t[34]) + c=z(h,c,d,a,b,X[11],16,t[35]) + b=z(h,b,c,d,a,X[14],23,t[36]) + a=z(h,a,b,c,d,X[ 1], 4,t[37]) + d=z(h,d,a,b,c,X[ 4],11,t[38]) + c=z(h,c,d,a,b,X[ 7],16,t[39]) + b=z(h,b,c,d,a,X[10],23,t[40]) + a=z(h,a,b,c,d,X[13], 4,t[41]) + d=z(h,d,a,b,c,X[ 0],11,t[42]) + c=z(h,c,d,a,b,X[ 3],16,t[43]) + b=z(h,b,c,d,a,X[ 6],23,t[44]) + a=z(h,a,b,c,d,X[ 9], 4,t[45]) + d=z(h,d,a,b,c,X[12],11,t[46]) + c=z(h,c,d,a,b,X[15],16,t[47]) + b=z(h,b,c,d,a,X[ 2],23,t[48]) + + a=z(i,a,b,c,d,X[ 0], 6,t[49]) + d=z(i,d,a,b,c,X[ 7],10,t[50]) + c=z(i,c,d,a,b,X[14],15,t[51]) + b=z(i,b,c,d,a,X[ 5],21,t[52]) + a=z(i,a,b,c,d,X[12], 6,t[53]) + d=z(i,d,a,b,c,X[ 3],10,t[54]) + c=z(i,c,d,a,b,X[10],15,t[55]) + b=z(i,b,c,d,a,X[ 1],21,t[56]) + a=z(i,a,b,c,d,X[ 8], 6,t[57]) + d=z(i,d,a,b,c,X[15],10,t[58]) + c=z(i,c,d,a,b,X[ 6],15,t[59]) + b=z(i,b,c,d,a,X[13],21,t[60]) + a=z(i,a,b,c,d,X[ 4], 6,t[61]) + d=z(i,d,a,b,c,X[11],10,t[62]) + c=z(i,c,d,a,b,X[ 2],15,t[63]) + b=z(i,b,c,d,a,X[ 9],21,t[64]) + + return bit_and(A+a,0xFFFFFFFF),bit_and(B+b,0xFFFFFFFF), + bit_and(C+c,0xFFFFFFFF),bit_and(D+d,0xFFFFFFFF) +end + +---------------------------------------------------------------- + +local function md5_update(self, s) + self.pos = self.pos + #s + s = self.buf .. s + for ii = 1, #s - 63, 64 do + local X = cut_le_str(sub(s,ii,ii+63),4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4) + assert(#X == 16) + X[0] = table.remove(X,1) -- zero based! + self.a,self.b,self.c,self.d = transform(self.a,self.b,self.c,self.d,X) + end + self.buf = sub(s, math.floor(#s/64)*64 + 1, #s) + return self +end + +local function md5_finish(self) + local msgLen = self.pos + local padLen = 56 - msgLen % 64 + + if msgLen % 64 > 56 then padLen = padLen + 64 end + + if padLen == 0 then padLen = 64 end + + local s = char(128) .. rep(char(0),padLen-1) .. lei2str(bit_and(8*msgLen, 0xFFFFFFFF)) .. lei2str(math.floor(msgLen/0x20000000)) + md5_update(self, s) + + assert(self.pos % 64 == 0) + return lei2str(self.a) .. lei2str(self.b) .. lei2str(self.c) .. lei2str(self.d) +end + +---------------------------------------------------------------- + +function md5.new() + return { a = CONSTS[65], b = CONSTS[66], c = CONSTS[67], d = CONSTS[68], + pos = 0, + buf = '', + update = md5_update, + finish = md5_finish } +end + +function md5.tohex(s) + return format("%08x%08x%08x%08x", str2bei(sub(s, 1, 4)), str2bei(sub(s, 5, 8)), str2bei(sub(s, 9, 12)), str2bei(sub(s, 13, 16))) +end + +function md5.sum(s) + return md5.new():update(s):finish() +end + +function md5.sumhexa(s) + return md5.tohex(md5.sum(s)) +end +bin.md5 = md5 +function bin:getMD5Hash() + self:setSeek(1) + local len=self:getSize() + local md5=bin.md5.new() + local SIZE=2048 + if len>SIZE then + local dat=self:read(SIZE) + while dat~=nil do + md5:update(dat) + dat=self:read(SIZE) + end + return bin.md5.tohex(md5:finish()):upper() + else + return bin.md5.sumhexa(self:getData()):upper() + end +end +return md5 diff --git a/bin/init.lua b/bin/init.lua new file mode 100644 index 0000000..aadea41 --- /dev/null +++ b/bin/init.lua @@ -0,0 +1,1431 @@ +bin={} +bin.Version={6,0,0} +bin.stage='stable' +bin.data='' +bin.t='bin' +bin.__index = bin +bin.__tostring=function(self) return self:getData() end +bin.__len=function(self) return self:getlength() end +bin.lastBlockSize=0 +bin.streams={} +-- Helpers +function bin.getVersion() + return bin.Version[1]..'.'..bin.Version[2]..'.'..bin.Version[3] +end +function table.print(tbl, indent) + if not indent then indent = 0 end + for k, v in pairs(tbl) do + formatting = string.rep(" ", indent) .. k .. ": " + if type(v) == "table" then + print(formatting) + table.print(v, indent+1) + elseif type(v) == 'boolean' then + print(formatting .. tostring(v)) + else + print(formatting .. tostring(v)) + end + end +end +function table.flip(t) + local tt={} + for i,v in pairs(t) do + tt[v]=i + end + return tt +end +function toFraction(n) + local w,p=math.modf(n) + if p~=0 then + p=tonumber(tostring(p):sub(3)) + end + return w,p +end +function io.cleanName(name) + name=name:gsub("\\","") + name=name:gsub("/","") + name=name:gsub(":","") + name=name:gsub("*","") + name=name:gsub("%?","") + name=name:gsub("\"","''") + name=name:gsub("<","") + name=name:gsub(">","") + name=name:gsub("|","") + return name +end +function math.numfix(n,x) + local str=tostring(n) + if #str1 or #d<1 then + error("A byte must be one character!") + else + c.data=string.byte(d) + end + elseif type(d)=="number" then + if d>255 or d<0 then + error("A byte must be between 0 and 255!") + else + c.data=d + end + else + error("cannot use type "..type(d).." as an argument! Takes only strings or numbers!") + end + c.__index=function(self,k) + if k>=0 and k<9 then + if self.data==0 then + return 0 + elseif self.data==255 then + return 1 + else + return bits.ref[self.data][k] + end + end + end + c.__tostring=function(self) + return bits.ref[tostring(self.data)] + end + setmetatable(c,c) + return c +end +function bits.newByteArray(s) + local c={} + if type(s)~="string" then + error("Must be a string type or bin/buffer type") + elseif type(s)=="table" then + if s.t=="sink" or s.t=="buffer" or s.t=="bin" then + local data=s:getData() + for i=1,#data do + c[#c+1]=bits.newByte(data:sub(i,i)) + end + else + error("Must be a string type or bin/buffer type") + end + else + for i=1,#s do + c[#c+1]=bits.newByte(s:sub(i,i)) + end + end + return c +end +function bits.new(n,binary) + local temp={} + temp.t="bits" + temp.Type="bits" + if type(n)=="string" then + if binary then + temp.data=n:match("[10]+") + else + local t={} + for i=#n,1,-1 do + table.insert(t,bits:conv(string.byte(n,i))) + end + temp.data=table.concat(t) + end + elseif type(n)=="number" or type(n)=="table" then + temp.data=basen(n,2) + end + if #temp.data%8~=0 then + temp.data=string.rep('0',8-#temp.data%8)..temp.data + end + setmetatable(temp, bits) + return temp +end +for i=0,255 do + local d=bits.new(i).data + bits.ref[i]={d:match("(%d)(%d)(%d)(%d)(%d)(%d)(%d)(%d)")} + bits.ref[tostring(i)]=d + bits.ref[d]=i + bits.ref["\255"..string.char(i)]=d +end +function bits.numToBytes(n,fit,func) + local num=string.reverse(bits.new(n):toSbytes()) + local ref={["num"]=num,["fit"]=fit} + if fit then + if fit<#num then + if func then + print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!") + func(ref) + else + print("Warning: attempting to store a number that takes up more space than allotted!") + end + return ref.num:sub(1,ref.fit) + elseif fit==#num then + return string.reverse(num) + else + return string.reverse(string.rep("\0",fit-#num)..num) + end + else + return string.reverse(num) + end +end +function bits:conv(n) + local tab={} + while n>=1 do + table.insert(tab,n%2) + n=math.floor(n/2) + end + local str=string.reverse(table.concat(tab)) + if #str%8~=0 or #str==0 then + str=string.rep('0',8-#str%8)..str + end + return str +end +function bits:tonumber(s,e) + if s==0 then + return tonumber(self.data,2) + end + s=s or 1 + return tonumber(string.sub(self.data,(8*(s-1))+1,8*s),2) or error('Bounds!') +end +function bits:isover() + return #self.data>8 +end +function bits:flipbits() + tab={} + for i=1,#self.data do + if string.sub(self.data,i,i)=='1' then + table.insert(tab,'0') + else + table.insert(tab,'1') + end + end + self.data=table.concat(tab) +end +function bits:tobytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return bin.new(table.concat(tab)) +end +function bits:toSbytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return table.concat(tab) +end +function bits:getBin() + return self.data +end +function bits:getbytes() + return #self.data/8 +end +local binNum=require("bin.numbers.BigNum") +local infinabits={} +bin.infinabits = infinabits +infinabits.data='' +infinabits.t='infinabits' +infinabits.Type='infinabits' +infinabits.__index = infinabits +infinabits.__tostring=function(self) return self.data end +infinabits.__len=function(self) return (#self.data)/8 end +local floor,insert = math.floor, table.insert +function basen(n,b) + n=BigNum.new(n) + if not b or b == 10 then return tostring(n) end + local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ" + local t = {} + local sign = "" + if n < BigNum.new(0) then + sign = "-" + n = -n + end + repeat + local d = tonumber(tostring(n % b)) + 1 + n = n / b + insert(t, 1, digits:sub(d,d)) + until n == BigNum.new(0) + return sign .. table.concat(t,"") +end +function base2to10(num) + local n=BigNum.new(0) + for i = #num-1,0,-1 do + nn=BigNum.new(num:sub(i+1,i+1))*(BigNum.new(2)^((#num-i)-1)) + n=n+nn + end + return n +end +function infinabits.newBitBuffer(n) + -- WIP +end +function infinabits.newConverter(bitsIn,bitsOut) + local c={} + -- WIP +end +infinabits.ref={} +function infinabits.newByte(d)-- WIP + local c={} + if type(d)=="string" then + if #d>1 or #d<1 then + error("A byte must be one character!") + else + c.data=string.byte(d) + end + elseif type(d)=="number" then + if d>255 or d<0 then + error("A byte must be between 0 and 255!") + else + c.data=d + end + else + error("cannot use type "..type(d).." as an argument! Takes only strings or numbers!") + end + c.__index=function(self,k) + if k>=0 and k<9 then + if self.data==0 then + return 0 + elseif self.data==255 then + return 1 + else + return infinabits.ref[self.data][k] + end + end + end + c.__tostring=function(self) + return infinabits.ref[tostring(self.data)] + end + setmetatable(c,c) + return c +end +function infinabits.newByteArray(s)-- WIP + local c={} + if type(s)~="string" then + error("Must be a string type or bin/buffer type") + elseif type(s)=="table" then + if s.t=="sink" or s.t=="buffer" or s.t=="bin" then + local data=s:getData() + for i=1,#data do + c[#c+1]=infinabits.newByte(data:sub(i,i)) + end + else + error("Must be a string type or bin/buffer type") + end + else + for i=1,#s do + c[#c+1]=infinabits.newByte(s:sub(i,i)) + end + end + return c +end +function infinabits.new(n,binary) + local temp={} + temp.t="infinabits" + temp.Type="infinabits" + if type(n)=="string" then + if binary then + temp.data=n:match("[10]+") + else + local t={} + for i=#n,1,-1 do + table.insert(t,infinabits:conv(string.byte(n,i))) + end + temp.data=table.concat(t) + end + elseif type(n)=="number" or type(n)=="table" then + temp.data=basen(tostring(n),2) + end + if #temp.data%8~=0 then + temp.data=string.rep('0',8-#temp.data%8)..temp.data + end + setmetatable(temp, infinabits) + return temp +end +for i=0,255 do + local d=infinabits.new(i).data + infinabits.ref[i]={d:match("(%d)(%d)(%d)(%d)(%d)(%d)(%d)(%d)")} + infinabits.ref[tostring(i)]=d + infinabits.ref[d]=i + infinabits.ref["\255"..string.char(i)]=d +end +function infinabits.numToBytes(n,fit,func) + local num=string.reverse(infinabits.new(BigNum.new(n)):toSbytes()) + local ref={["num"]=num,["fit"]=fit} + if fit then + if fit<#num then + if func then + print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!") + func(ref) + else + print("Warning: attempting to store a number that takes up more space than allotted!") + end + return ref.num:sub(1,ref.fit) + elseif fit==#num then + return string.reverse(num) + else + return string.reverse(string.rep("\0",fit-#num)..num) + end + else + return string.reverse(num) + end +end +function infinabits.numToBytes(n,fit,fmt,func) + if fmt=="%e" then + local num=string.reverse(infinabits.new(BigNum.new(n)):toSbytes()) + local ref={["num"]=num,["fit"]=fit} + if fit then + if fit<#num then + if func then + print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!") + func(ref) + else + print("Warning: attempting to store a number that takes up more space than allotted!") + end + return ref.num:sub(1,ref.fit) + elseif fit==#num then + return num + else + return string.rep("\0",fit-#num)..num + end + else + return num + end + + else + local num=string.reverse(infinabits.new(BigNum.new(n)):toSbytes()) + local ref={["num"]=num,["fit"]=fit} + if fit then + if fit<#num then + if func then + print("Warning: attempting to store a number that takes up more space than allotted! Using provided method!") + func(ref) + else + print("Warning: attempting to store a number that takes up more space than allotted!") + end + return ref.num:sub(1,ref.fit) + elseif fit==#num then + return string.reverse(num) + else + return string.reverse(string.rep("\0",fit-#num)..num) + end + else + return string.reverse(num) + end + end +end +function infinabits:conv(n) + local tab={} + local one=BigNum.new(1) + local n=BigNum.new(n) + while n>=one do + table.insert(tab,tonumber(tostring(n%2))) + n=n/2 + end + local str=string.reverse(table.concat(tab)) + if #str%8~=0 or #str==0 then + str=string.rep('0',8-#str%8)..str + end + return str +end +function infinabits:tonumber(s) + if s==0 then + return tonumber(self.data,2) + end + s=s or 1 + return tonumber(tostring(base2to10(string.sub(self.data,(8*(s-1))+1,8*s)))) or error('Bounds!') +end +function infinabits:isover() + return #self.data>8 +end +function infinabits:flipbits() + tab={} + local s=self.data + s=s:gsub("1","_") + s=s:gsub("0","1") + s=s:gsub("_","0") + self.data=s +end +function infinabits:tobytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return bin.new(table.concat(tab)) +end +function infinabits:toSbytes() + local tab={} + for i=self:getbytes(),1,-1 do + table.insert(tab,string.char(self:tonumber(i))) + end + return table.concat(tab) +end +function infinabits:getBin() + return self.data +end +function infinabits:getbytes() + return #self.data/8 +end +local randomGen=require("bin.numbers.random") +function bin.setBitsInterface(int) + bin.defualtBit=int or infinabits +end +bin.setBitsInterface() +function bin.normalizeData(data) -- unified function to allow for all types to string + if type(data)=="string" then return data end + if type(data)=="table" then + if data.Type=="bin" or data.Type=="streamable" or data.Type=="buffer" then + return data:getData() + elseif data.Type=="bits" or data.Type=="infinabits" then + return data:toSbytes() + elseif data.Type=="sink" then + -- LATER + else + return "" + end + elseif type(data)=="userdata" then + if tostring(data):sub(1,4)=="file" then + local cur=data:seek("cur") + data:seek("set",0) + local dat=data:read("*a") + data:seek("set",cur) + return dat + else + error("File handles are the only userdata that can be used!") + end + end +end +function bin.resolveType(tab) -- used in getblock for auto object creation. Internal method + if tab.Type then + if tab.Type=="bin" then + return bin.new(tab.data) + elseif tab.Type=="streamable" then + if bin.fileExist(tab.file) then return nil,"Cannot load the stream file, source file does not exist!" end + return bin.stream(tab.file,tab.lock) + elseif tab.Type=="buffer" then + local buf=bin.newDataBuffer(tab.size) + buf[1]=tab:getData() + return buf + elseif tab.Type=="bits" then + local b=bits.new("") + b.data=tab.data + return b + elseif tab.Type=="infinabits" then + local b=infinabits.new("") + b.data=tab.data + return b + elseif tab.Type=="sink" then + return bin.newSync(tab.data) + else -- maybe a type from another library + return tab + end + else return tab end +end +function bin.fileExist(path) + g=io.open(path or '','r') + if path =='' then + p='empty path' + return nil + end + if g~=nil and true or false then + p=(g~=nil and true or false) + end + if g~=nil then + io.close(g) + else + return false + end + return p +end +function bin.toHex(str) + local str=bin.normalizeData(str) + return (str:gsub('.', function (c) + return string.format('%02X', string.byte(c)) + end)) +end +function bin.fromHex(str) + return (str:gsub('..', function (cc) + return string.char(tonumber(cc, 16)) + end)) +end + +-- Constructors +function bin.new(data) + data=bin.normalizeData(data) + local c = {} + setmetatable(c, bin) + c.data=data + c.Type="bin" + c.t="bin" + c.pos=1 + c.stream=false + return c +end + +function bin.newFromHex(data) + return bin.new(bin.fromHex(data)) +end +function bin.load(path) + if type(path) ~= "string" then error("Path must be a string!") end + local f = io.open(path, 'rb') + local content = f:read('*a') + f:close() + return bin.new(content) +end +function bin.stream(file,l) + if not(l==false) then l=true end + local c=bin.new() + c.Type="streamable" + c.t="streamable" + if bin.streams[file]~=nil then + c.file=file + c.lock = l + c.workingfile=bin.streams[file][1].workingfile + bin.streams[file][2]=bin.streams[file][2]+1 + c.stream=true + return c + end + if bin.fileExist(file) then + c.file=file + c.lock = l + c.workingfile=io.open(file,'rb+') + else + c.file=file + c.lock = l + c.workingfile=io.open(file,'w') + io.close(c.workingfile) + c.workingfile=io.open(file,'rb+') + end + c.stream=true + bin.streams[file]={c,1} + return c +end +function bin.newTempFile() + local c=bin.new() + c.file=file + c.lock = false + c.workingfile=io.tmpfile() + c.stream=true + return c +end +function bin.freshStream(file) + bin.new():tofile(file) + return bin.stream(file,false) +end +function bin.newStreamFileObject(file) + local c=bin.new() + c.Type="streamable" + c.t="streamable" + c.file="FILE_OBJECT" + c.lock = false + c.workingfile=file + c.stream=true + return c +end +-- Core Methods +function bin:canStreamWrite() + return (self.stream and not(self.lock)) +end +function bin:getSeek() + if self.stream then + return self.workingfile:seek("cur")+1 + else + return self.pos + end +end +function bin:setSeek(n) + if self.stream then + self.workingfile:seek("set",n-1) + else + self.pos=n + end +end +function bin:seek(n) + if self.stream then + if not n then return self.workingfile:seek("cur") end + local cur=self.workingfile:seek("cur") + self.workingfile:seek("set",cur+n) + else + if not n then return self.pos end + if #self.data-(self.pos-1)size then + data = data:sub(1,size) + elseif dsize255 then + nn=nn%256 + elseif nn<0 then + nn=256-math.abs(nn) + end + buf[i]=nn + end + self:setSeek(1) + self:write(buf:getData()) +end +function bin:getData(a,b,fmt) + local data="" + if a or b then + data=self:sub(a,b) + else + if self.stream then + local cur=self.workingfile:seek("cur") + self.workingfile:seek("set",0) + data=self.workingfile:read("*a") + self.workingfile:seek("set",cur) + else + data=self.data + end + end + if fmt=="%x" or fmt=="hex" then + return bin.toHex(data):lower() + elseif fmt=="%X" or fmt=="HEX" then + return bin.toHex(data) + elseif fmt=="%b" or fmt=="b64" then + return bin.toB64(data) + elseif fmt then + return bin.new(data):getBlock(fmt,#data) + end + return data +end +function bin:getSize(fmt) + local len=0 + if self.stream then + local cur=self.workingfile:seek("cur") + len=self.workingfile:seek("end") + self.workingfile:seek("set",cur) + else + len=#self.data + end + if fmt=="%b" then + return bin.toB64() + elseif fmt then + return string.format(fmt, len) + else + return len + end +end +function bin:tackE(data,size,h) + local data=bin.normalizeData(data) + local cur=self:getSize() + self:setSeek(self:getSize()+1) + self:write(data,size) + if h then + self:setSeek(cur+1) + end +end +function bin:tonumber(a,b) + local temp={} + if a then + temp.data=self:sub(a,b) + else + temp=self + end + local l,r=0,0 + local g=#temp.data + for i=1,g do + r=r+(256^(g-i))*string.byte(string.sub(temp.data,i,i)) + l=l+(256^(i-1))*string.byte(string.sub(temp.data,i,i)) + end + return r,l +end +function bin.endianflop(data) + return string.reverse(data) +end +function bin:tofile(name) + if self.stream then return end + if not name then error("Must include a filename to save as!") end + file = io.open(name, "wb") + file:write(self.data) + file:close() +end +function bin:close() + if self.stream then + if bin.streams[self.file][2]==1 then + bin.streams[self.file]=nil + self.workingfile:close() + else + bin.streams[self.file][2]=bin.streams[self.file][2]-1 + self.workingfile=io.tmpfile() + self.workingfile:close() + end + end +end +function bin:getBlock(t,n) + local data="" + if not n then + if bin.registerBlocks[t] then + return bin.registerBlocks[t][1](nil,self) + else + error("Unknown format! Cannot read from file: "..tostring(t)) + end + else + if t=="n" or t=="%e" or t=="%E" then + data=self:read(n) + local numB=bin.defualtBit.new(data) + local numL=bin.defualtBit.new(string.reverse(data)) + local little=numL:tonumber(0) + local big=numB:tonumber(0) + if t=="%E" then + return big + elseif t=="%X" then + return bin.toHex(data):upper() + elseif t=="%x" then + return bin.toHex(data):lower() + elseif t=="%b" then + return bin.toB64(data) + elseif t=="%e" then + return little + end + return big,little + elseif t=="s" then + return self:read(n) + elseif bin.registerBlocks[t] then + return bin.registerBlocks[t][1](n,self) + else + error("Unknown format! Cannot read from file: "..tostring(t)) + end + end +end +function bin:addBlock(d,fit,fmt) + if not fmt then fmt=type(d):sub(1,1) end + if bin.registerBlocks[fmt] then + self:tackE(bin.registerBlocks[fmt][2](d,fit,fmt,self,bin.registerBlocks[fmt][2])) + elseif type(d)=="number" then + local data=bin.defualtBit.numToBytes(d,fit or 4,fmt,function() + error("Overflow! Space allotted for number is smaller than the number takes up. Increase the fit!") + end) + self:tackE(data) + elseif type(d)=="string" then + local data=d:sub(1,fit or -1) + if #data<(fit or #data) then + data=data..string.rep("\0",fit-#data) + end + self:tackE(data) + end +end +bin.registerBlocks={} +function bin.registerBlock(t,funcG,funcA) + bin.registerBlocks[t]={funcG,funcA} +end +function bin.newDataBuffer(size,fill) -- fills with \0 or nul or with what you enter + local c={} + local fill=fill or "\0" + c.data={self=c} + c.Type="buffer" + c.size=size or 0 -- 0 means an infinite buffer, sometimes useful + for i=1,c.size do + c.data[i]=fill + end + local mt={ + __index=function(t,k) + if type(k)=="number" then + local data=t.data[k] + if data then + return string.byte(data) + else + error("Index out of range!") + end + elseif type(k)=="string" then + local num=tonumber(k) + if num then + local data=t.data[num] + if data then + return data + else + error("Index out of range!") + end + else + error("Only number-strings and numbers can be indexed!") + end + else + error("Only number-strings and numbers can be indexed!") + end + end, + __newindex=function(t,k,v) + if type(k)~="number" then error("Can only set a buffers data with a numeric index!") end + local data="" + if type(v)=="string" then + data=v + elseif type(v)=="number" then + data=bits.numToBytes(v) + else + -- try to normalize the data of type v + data=bin.normalizeData(v) + end + t:fillBuffer(k,data) + end, + __tostring=function(t) + return t:getData() + end, + } + function c:fillBuffer(a,data) + local len=#data + if len==1 then + self.data[a]=data + else + local i=a-1 + for d in data:gmatch(".") do + i=i+1 + if i>c.size then + return #data-i+a + end + self.data[i]=d + end + return #data-i+(a-1) + end + end + function c:getData(a,b,fmt) -- LATER + local dat=bin.new(table.concat(self.data,"",a,b)) + local n=dat:getSize() + return dat:getBlock(fmt or "s",n) + end + function c:getSize() + return #self:getData() + end + setmetatable(c,mt) + return c +end +function bin:newDataBufferFromStream(pos,size,fill) -- fills with \0 or nul or with what you enter IF the nothing exists inside the bin file. + local s=self:getSize() + if not self.stream then error("Can only created a streamed buffer on a streamable file!") end + if s==0 then + self:write(string.rep("\0",pos+size)) + end + self:setSeek(1) + local c=bin.newDataBuffer(size,fill) + rawset(c,"pos",pos) + rawset(c,"size",size) + rawset(c,"fill",fill) + rawset(c,"bin",self) + rawset(c,"sync",function(self) + local cur=self.bin:getSeek() + self.bin:setSeek(self.pos) + self.bin:write(self:getData(),size) + self.bin:setSeek(cur) + end) + c:fillBuffer(1,self:sub(pos,pos+size)) + function c:fillBuffer(a,data) + local len=#data + if len==1 then + self.data[a]=data + self:sync() + else + local i=a-1 + for d in data:gmatch(".") do + i=i+1 + if i>c.size then + self:sync() + return #data-i+a + end + self.data[i]=d + end + self:sync() + return #data-i+(a-1) + end + end + return c +end +function bin:toDataBuffer() + local s=self:getSize() + -- if self:canStreamWrite() then + -- return self:newDataBufferFromStream(0,s) + -- end + local buf=bin.newDataBuffer(s) + local data=self:read(512) + local i=1 + while data~=nil do + buf[i]=data + data=self:read(512) + i=i+512 + end + return buf +end +function bin:getHash() + if self:getSize()==0 then + return "NaN" + end + n=32 + local rand = randomGen:newND(1,self:getSize(),self:getSize()) + local h,g={},0 + for i=1,n do + g=rand:nextInt() + table.insert(h,bin.toHex(self:sub(g,g))) + end + return table.concat(h,'') +end +function bin:flipbits() + if self:canStreamWrite() then + self:setSeek(1) + for i=1,self:getSize() do + self:write(string.char(255-string.byte(self:sub(i,i)))) + end + else + local temp={} + for i=1,#self.data do + table.insert(temp,string.char(255-string.byte(string.sub(self.data,i,i)))) + end + self.data=table.concat(temp,'') + end +end +function bin:encrypt() + self:flipbits() +end +function bin:decrypt() + self:flipbits() +end +-- Use with small files! +function bin:gsub(...) + local data=self:getData() + local pos=self:getSeek() + self:setSeek(1) + self:write((data:gsub(...)) or data) + self:setSeek(loc) +end +function bin:gmatch(pat) + return self:getData():gmatch(pat) +end +function bin:match(pat) + return self:getData():match(pat) +end +function bin:trim() + local data=self:getData() + local pos=self:getSeek() + self:setSeek(1) + self:write(data:match'^()%s*$' and '' or data:match'^%s*(.*%S)') + self:setSeek(loc) +end +function bin:lines() + local t = {} + local function helper(line) table.insert(t, line) return '' end + helper((self:getData():gsub('(.-)\r?\n', helper))) + return t +end +function bin._lines(str) + local t = {} + local function helper(line) table.insert(t, line) return '' end + helper((str:gsub('(.-)\r?\n', helper))) + return t +end +function bin:wipe() + if self:canStreamWrite() then + self:close() + local c=bin.freshStream(self.file) + self.workingfile=c.workingfile + else + self.data="" + end + self:setSeek(1) +end +function bin:fullTrim(empty) + local t=self:lines() + for i=#t,1,-1 do + t[i]=bin._trim(t[i]) + if empty then + if t[i]=="" then + table.remove(t,i) + end + end + end + self:wipe() + self:write(table.concat(t,"\n")) +end +local __CURRENTVERSION=2 +bin.registerBlock("t",function(SIZE_OR_NIL,ref) + local header=ref:read(3) + if not header:match("(LT.)") then error("Not a valid table struct!") end + if bin.defualtBit.new(header:sub(3,3)):tonumber(1)>__CURRENTVERSION then error("Incompatible Version of LuaTable!") end + local len=ref:getBlock("n",4) -- hehe lets make life easier + local tab={} + local ind + local n=0 + while true do + local _dat=ref:read(2) + if _dat==nil then break end + local it,dt=_dat:match("(.)(.)") + n=n+2 + if it=="N" then -- get the index stuff out of the way first + ind=ref:getBlock("n",4) + n=n+4 + else + indL=ref:getBlock("n",1) + n=n+1+indL + ind=ref:read(indL) + end + if dt=="N" then + tab[ind]=ref:getBlock("d") + n=n+8 + elseif dt=="I" then + tab[ind]=math.huge + ref:getBlock("n",4) + n=n+4 + elseif dt=="i" then + tab[ind]=-math.huge + ref:getBlock("n",4) + n=n+4 + elseif dt=="S" then + local nn=ref:getBlock("n",4) + tab[ind]=ref:read(nn) + n=n+4+nn + elseif dt=="B" then + tab[ind]=({["\255"]=true,["\0"]=false})[ref:read(1)] + n=n+1 + elseif dt=="F" then + local nn=ref:getBlock("n",4) + tab[ind]=loadstring(ref:read(nn)) + n=n+4+nn + elseif dt=="T" then + local cur=ref:getSeek() + local size=ref:getBlock("n",4) + ref:setSeek(cur) + ref:read(4) + if size==7 then + tab[ind]={} + ref:read(7) + n=n+11 + else + local data=bin.new(ref:read(size)) + local dat=data:getBlock("t") + if dat.__RECURSIVE then + tab[ind]=tab + else + tab[ind]=dat + end + n=n+data:getSize()+4 + end + end + if n==len then break end + end + return bin.resolveType(tab) +end,function(d,fit,fmt,self,rec,tabsaw) + -- INGORE FIT WE ARE CREATING A STRUCT!!! + -- fmt will apply to all numbers + local __rem=nil + if not tabsaw then rem=true end + local tabsaw=tabsaw or {} + if rem then + table.insert(tabsaw,d) + end + local bData={} + for i,v in pairs(d) do -- this is for tables, all but userdata is fine. Depending on where you are using lua functions may or may not work + local tp=type(v):sub(1,1):upper() -- uppercase of datatype + if type(i)=="number" then -- Lets handle indexies + if v==math.huge then + tp="I" + v=0 + elseif v==-math.huge then + tp="i" + v=0 + end + table.insert(bData,"N"..tp..bin.defualtBit.numToBytes(i,4)) -- number index? + elseif type(i)=="string" then + if #i>255 then error("A string index cannot be larger than 255 bytes!") end + table.insert(bData,"S"..tp..bin.defualtBit.numToBytes(#i,1)..i) -- string index? + else + error("Only numbers and strings can be a table index!") -- throw error? + end + if type(v)=="number" then + -- How do we handle number data + local temp=bin.new() + temp:addBlock(v,nil,"d") + table.insert(bData,temp.data) + elseif type(v)=="string" then + -- Lets work on strings + table.insert(bData,bin.defualtBit.numToBytes(#v,4)) -- add length of string + table.insert(bData,v) -- add string + elseif type(v)=="boolean" then -- bools are easy :D + table.insert(bData,({[true]="\255",[false]="\0"})[v]) + elseif type(v)=="function" then -- should we allow this? why not... + local dump=string.dump(v) + table.insert(bData,bin.defualtBit.numToBytes(#dump,4)) -- add length of dumped string + table.insert(bData,dump) -- add it + elseif type(v)=="table" then -- tables... + if tabsaw[1]==v then + v={__RECURSIVE=i} + else + tabsaw[i]=v + end + local data=rec(v,nil,"t",self,rec,tabsaw) + table.insert(bData,bin.defualtBit.numToBytes(#data,4)) -- add length of string + table.insert(bData,data) -- add string + end + end + local data=table.concat(bData) + return "LT"..string.char(__CURRENTVERSION)..bin.defualtBit.numToBytes(#data,4)..data +end) +bin.registerBlock("b",function(SIZE_OR_NIL,ref) + return ({["\255"]=true,["\0"]=false})[ref:read(1)] +end,function(d) + return ({[true]="\255",[false]="\0"})[d] +end) +bin.registerBlock("f",function(SIZE_OR_NIL,ref) + local nn=ref:getBlock("n",4) + return loadstring(ref:read(nn)) +end,function(d) + local dump=string.dump(d) + return bin.defualtBit.numToBytes(#dump,4)..dump +end) +bin.registerBlock("d",function(SIZE_OR_NIL,ref) + local w,p=ref:getBlock("n",4),ref:getBlock("n",4) + p=tonumber("0."..tostring(p)) + return w+p +end,function(d,fit,fmt,self,rec,tabsaw) + local w,p = toFraction(d) + local temp=bin.new() + temp:addBlock(w,4) + temp:addBlock(p,4) + return temp.data +end) +if love then + function bin.load(file,s,r) + content, size = love.filesystem.read(file) + local temp=bin.new(content) + temp.filepath=file + return temp + end + function bin.fileExists(name) + return love.filesystem.getInfo(name) + end + function bin:tofile(filename) + if not(filename) or self.Stream then return nil end + love.filesystem.write(filename,self.data) + end + function bin.loadS(path,s,r) + local path = love.filesystem.getSaveDirectory( ).."\\"..path + if type(path) ~= "string" then error("Path must be a string!") end + local f = io.open(path, 'rb') + local content = f:read('*a') + f:close() + return bin.new(content) + end + function bin:tofileS(filename) + if self.stream then return end + local filename = love.filesystem.getSaveDirectory( ).."\\"..filename + print(#self.data,filename) + if not filename then error("Must include a filename to save as!") end + file = io.open(filename, "wb") + file:write(self.data) + file:close() + end + function bin.stream(file) + return bin.newStreamFileObject(love.filesystem.newFile(file)) + end + function bin:getSize(fmt) + local len=0 + if self.stream then + local len=self.workingfile:getSize() + else + len=#self.data + end + if fmt=="%b" then + return bin.toB64() + elseif fmt then + return string.format(fmt, len) + else + return len + end + end + function bin:getSeek() + if self.stream then + return self.workingfile:tell()+1 + else + return self.pos + end + end + function bin:setSeek(n) + if self.stream then + self.workingfile:seek(n-1) + else + self.pos=n + end + end + function bin:seek(n) + if self.stream then + self.workingfile:seek(n) + else + if not n then return self.pos end + if #self.data-(self.pos-1) 0 then + for i = bnum.len - 2 , 0 , -1 do + for j = 0 , RADIX_LEN - string.len( bnum[i] ) - 1 do + temp = temp .. '0' ; + end + temp = temp .. bnum[i] ; + end + if bnum[bnum.len - 1]==nil then + return "nil" + end + temp = bnum[bnum.len - 1] .. temp ; + if bnum.signal == '-' then + temp = bnum.signal .. temp ; + end + return temp ; + else + return "" ; + end +end + +function BigNum.mt.pow( num1 , num2 ) + local bnum1 = BigNum.new( num1 ) ; + local bnum2 = BigNum.new( num2 ) ; + return BigNum.pow( bnum1 , bnum2 ) ; +end + +function BigNum.mt.eq( num1 , num2 ) + local bnum1 = BigNum.new( num1 ) ; + local bnum2 = BigNum.new( num2 ) ; + return BigNum.eq( bnum1 , bnum2 ) ; +end + +function BigNum.mt.lt( num1 , num2 ) + local bnum1 = BigNum.new( num1 ) ; + local bnum2 = BigNum.new( num2 ) ; + return BigNum.lt( bnum1 , bnum2 ) ; +end + +function BigNum.mt.le( num1 , num2 ) + local bnum1 = BigNum.new( num1 ) ; + local bnum2 = BigNum.new( num2 ) ; + return BigNum.le( bnum1 , bnum2 ) ; +end + +function BigNum.mt.unm( num ) + local ret = BigNum.new( num ) + if ret.signal == '+' then + ret.signal = '-' + else + ret.signal = '+' + end + return ret +end + +BigNum.mt.__metatable = "hidden" +BigNum.mt.__tostring = BigNum.mt.tostring ; +BigNum.mt.__add = BigNum.mt.add ; +BigNum.mt.__sub = BigNum.mt.sub ; +BigNum.mt.__mul = BigNum.mt.mul ; +BigNum.mt.__div = BigNum.mt.div ; +BigNum.mt.__pow = BigNum.mt.pow ; +BigNum.mt.__unm = BigNum.mt.unm ; +BigNum.mt.__mod = BigNum.mt.mod ; +BigNum.mt.__eq = BigNum.mt.eq ; +BigNum.mt.__le = BigNum.mt.le ; +BigNum.mt.__lt = BigNum.mt.lt ; +setmetatable( BigNum.mt, { __index = "inexistent field", __newindex = "not available", __metatable="hidden" } ) ; +function BigNum.add( bnum1 , bnum2 , bnum3 ) + local maxlen = 0 ; + local i = 0 ; + local carry = 0 ; + local signal = '+' ; + local old_len = 0 ; + --Handle the signals + if bnum1 == nil or bnum2 == nil or bnum3 == nil then + error("Function BigNum.add: parameter nil") ; + elseif bnum1.signal == '-' and bnum2.signal == '+' then + bnum1.signal = '+' ; + BigNum.sub( bnum2 , bnum1 , bnum3 ) ; + + if not rawequal(bnum1, bnum3) then + bnum1.signal = '-' ; + end + return 0 ; + elseif bnum1.signal == '+' and bnum2.signal == '-' then + bnum2.signal = '+' ; + BigNum.sub( bnum1 , bnum2 , bnum3 ) ; + if not rawequal(bnum2, bnum3) then + bnum2.signal = '-' ; + end + return 0 ; + elseif bnum1.signal == '-' and bnum2.signal == '-' then + signal = '-' ; + end + -- + old_len = bnum3.len ; + if bnum1.len > bnum2.len then + maxlen = bnum1.len ; + else + maxlen = bnum2.len ; + bnum1 , bnum2 = bnum2 , bnum1 ; + end + --School grade sum + for i = 0 , maxlen - 1 do + if bnum2[i] ~= nil then + bnum3[i] = bnum1[i] + bnum2[i] + carry ; + else + bnum3[i] = bnum1[i] + carry ; + end + if bnum3[i] >= RADIX then + bnum3[i] = bnum3[i] - RADIX ; + carry = 1 ; + else + carry = 0 ; + end + end + --Update the answer's size + if carry == 1 then + bnum3[maxlen] = 1 ; + end + bnum3.len = maxlen + carry ; + bnum3.signal = signal ; + for i = bnum3.len, old_len do + bnum3[i] = nil ; + end + return 0 ; +end + +function BigNum.sub( bnum1 , bnum2 , bnum3 ) + local maxlen = 0 ; + local i = 0 ; + local carry = 0 ; + local old_len = 0 ; + if bnum1 == nil or bnum2 == nil or bnum3 == nil then + error("Function BigNum.sub: parameter nil") ; + elseif bnum1.signal == '-' and bnum2.signal == '+' then + bnum1.signal = '+' ; + BigNum.add( bnum1 , bnum2 , bnum3 ) ; + bnum3.signal = '-' ; + if not rawequal(bnum1, bnum3) then + bnum1.signal = '-' ; + end + return 0 ; + elseif bnum1.signal == '-' and bnum2.signal == '-' then + bnum1.signal = '+' ; + bnum2.signal = '+' ; + BigNum.sub( bnum2, bnum1 , bnum3 ) ; + if not rawequal(bnum1, bnum3) then + bnum1.signal = '-' ; + end + if not rawequal(bnum2, bnum3) then + bnum2.signal = '-' ; + end + return 0 ; + elseif bnum1.signal == '+' and bnum2.signal == '-' then + bnum2.signal = '+' ; + BigNum.add( bnum1 , bnum2 , bnum3 ) ; + if not rawequal(bnum2, bnum3) then + bnum2.signal = '-' ; + end + return 0 ; + end + --Tests if bnum2 > bnum1 + if BigNum.compareAbs( bnum1 , bnum2 ) == 2 then + BigNum.sub( bnum2 , bnum1 , bnum3 ) ; + bnum3.signal = '-' ; + return 0 ; + else + maxlen = bnum1.len ; + end + old_len = bnum3.len ; + bnum3.len = 0 ; + --School grade subtraction + for i = 0 , maxlen - 1 do + if bnum2[i] ~= nil then + bnum3[i] = bnum1[i] - bnum2[i] - carry ; + else + bnum3[i] = bnum1[i] - carry ; + end + if bnum3[i] < 0 then + bnum3[i] = RADIX + bnum3[i] ; + carry = 1 ; + else + carry = 0 ; + end + + if bnum3[i] ~= 0 then + bnum3.len = i + 1 ; + end + end + bnum3.signal = '+' ; + --Check if answer's size if zero + if bnum3.len == 0 then + bnum3.len = 1 ; + bnum3[0] = 0 ; + end + if carry == 1 then + error( "Error in function sub" ) ; + end + for i = bnum3.len , max( old_len , maxlen - 1 ) do + bnum3[i] = nil ; + end + return 0 ; +end + +function BigNum.mul( bnum1 , bnum2 , bnum3 ) + local i = 0 ; j = 0 ; + local temp = BigNum.new( ) ; + local temp2 = 0 ; + local carry = 0 ; + local oldLen = bnum3.len ; + if bnum1 == nil or bnum2 == nil or bnum3 == nil then + error("Function BigNum.mul: parameter nil") ; + --Handle the signals + elseif bnum1.signal ~= bnum2.signal then + BigNum.mul( bnum1 , -bnum2 , bnum3 ) ; + bnum3.signal = '-' ; + return 0 ; + end + bnum3.len = ( bnum1.len ) + ( bnum2.len ) ; + --Fill with zeros + for i = 1 , bnum3.len do + bnum3[i - 1] = 0 ; + end + --Places nil where passes through this + for i = bnum3.len , oldLen do + bnum3[i] = nil ; + end + --School grade multiplication + for i = 0 , bnum1.len - 1 do + for j = 0 , bnum2.len - 1 do + carry = ( bnum1[i] * bnum2[j] + carry ) ; + carry = carry + bnum3[i + j] ; + bnum3[i + j] = ( carry % RADIX ) ; + temp2 = bnum3[i + j] ; + carry = math.floor ( carry / RADIX ) ; + end + if carry ~= 0 then + bnum3[i + bnum2.len] = carry ; + end + carry = 0 ; + end + + --Update the answer's size + for i = bnum3.len - 1 , 1 , -1 do + if bnum3[i] ~= nil and bnum3[i] ~= 0 then + break ; + else + bnum3[i] = nil ; + end + bnum3.len = bnum3.len - 1 ; + end + return 0 ; +end + +function BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) + local temp = BigNum.new() ; + local temp2 = BigNum.new() ; + local one = BigNum.new( "1" ) ; + local zero = BigNum.new( "0" ) ; + --Check division by zero + if BigNum.compareAbs( bnum2 , zero ) == 0 then + error( "Function BigNum.div: Division by zero" ) ; + end + --Handle the signals + if bnum1 == nil or bnum2 == nil or bnum3 == nil or bnum4 == nil then + error( "Function BigNum.div: parameter nil" ) ; + elseif bnum1.signal == "+" and bnum2.signal == "-" then + bnum2.signal = "+" ; + BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) ; + bnum2.signal = "-" ; + bnum3.signal = "-" ; + return 0 ; + elseif bnum1.signal == "-" and bnum2.signal == "+" then + bnum1.signal = "+" ; + BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) ; + bnum1.signal = "-" ; + if bnum4 < zero then --Check if remainder is negative + BigNum.add( bnum3 , one , bnum3 ) ; + BigNum.sub( bnum2 , bnum4 , bnum4 ) ; + end + bnum3.signal = "-" ; + return 0 ; + elseif bnum1.signal == "-" and bnum2.signal == "-" then + bnum1.signal = "+" ; + bnum2.signal = "+" ; + BigNum.div( bnum1 , bnum2 , bnum3 , bnum4 ) ; + bnum1.signal = "-" ; + if bnum4 < zero then --Check if remainder is negative + BigNum.add( bnum3 , one , bnum3 ) ; + BigNum.sub( bnum2 , bnum4 , bnum4 ) ; + end + bnum2.signal = "-" ; + return 0 ; + end + temp.len = bnum1.len - bnum2.len - 1 ; + + --Reset variables + BigNum.change( bnum3 , "0" ) ; + BigNum.change( bnum4 , "0" ) ; + + BigNum.copy( bnum1 , bnum4 ) ; + + --Check if can continue dividing + while( BigNum.compareAbs( bnum4 , bnum2 ) ~= 2 ) do + if bnum4[bnum4.len - 1] >= bnum2[bnum2.len - 1] then + BigNum.put( temp , math.floor( bnum4[bnum4.len - 1] / bnum2[bnum2.len - 1] ) , bnum4.len - bnum2.len ) ; + temp.len = bnum4.len - bnum2.len + 1 ; + else + BigNum.put( temp , math.floor( ( bnum4[bnum4.len - 1] * RADIX + bnum4[bnum4.len - 2] ) / bnum2[bnum2.len -1] ) , bnum4.len - bnum2.len - 1 ) ; + temp.len = bnum4.len - bnum2.len ; + end + + if bnum4.signal ~= bnum2.signal then + temp.signal = "-"; + else + temp.signal = "+"; + end + BigNum.add( temp , bnum3 , bnum3 ) ; + temp = temp * bnum2 ; + BigNum.sub( bnum4 , temp , bnum4 ) ; + end + + --Update if the remainder is negative + if bnum4.signal == '-' then + decr( bnum3 ) ; + BigNum.add( bnum2 , bnum4 , bnum4 ) ; + end + return 0 ; +end + +function BigNum.pow( bnum1 , bnum2 ) + local n = BigNum.new( bnum2 ) ; + local y = BigNum.new( 1 ) ; + local z = BigNum.new( bnum1 ) ; + local zero = BigNum.new( "0" ) ; + if bnum2 < zero then + error( "Function BigNum.exp: domain error" ) ; + elseif bnum2 == zero then + return y ; + end + while 1 do + if ( n[0] % 2 ) == 0 then + n = n / 2 ; + else + n = n / 2 ; + y = z * y ; + if n == zero then + return y ; + end + end + z = z * z ; + end +end +-- Português : +BigNum.exp = BigNum.pow + +function BigNum.gcd( bnum1 , bnum2 ) + local a = {} ; + local b = {} ; + local c = {} ; + local d = {} ; + local zero = {} ; + zero = BigNum.new( "0" ) ; + if bnum1 == zero or bnum2 == zero then + return BigNum.new( "1" ) ; + end + a = BigNum.new( bnum1 ) ; + b = BigNum.new( bnum2 ) ; + a.signal = '+' ; + b.signal = '+' ; + c = BigNum.new() ; + d = BigNum.new() ; + while b > zero do + BigNum.div( a , b , c , d ) ; + a , b , d = b , d , a ; + end + return a ; +end +-- Português: +BigNum.mmc = BigNum.gcd + +function BigNum.eq( bnum1 , bnum2 ) + if BigNum.compare( bnum1 , bnum2 ) == 0 then + return true ; + else + return false ; + end +end + +function BigNum.lt( bnum1 , bnum2 ) + if BigNum.compare( bnum1 , bnum2 ) == 2 then + return true ; + else + return false ; + end +end + +function BigNum.le( bnum1 , bnum2 ) + local temp = -1 ; + temp = BigNum.compare( bnum1 , bnum2 ) + if temp == 0 or temp == 2 then + return true ; + else + return false ; + end +end + +function BigNum.compareAbs( bnum1 , bnum2 ) + if bnum1 == nil or bnum2 == nil then + error("Function compare: parameter nil") ; + elseif bnum1.len > bnum2.len then + return 1 ; + elseif bnum1.len < bnum2.len then + return 2 ; + else + local i ; + for i = bnum1.len - 1 , 0 , -1 do + if bnum1[i] > bnum2[i] then + return 1 ; + elseif bnum1[i] < bnum2[i] then + return 2 ; + end + end + end + return 0 ; +end + +function BigNum.compare( bnum1 , bnum2 ) + local signal = 0 ; + + if bnum1 == nil or bnum2 == nil then + error("Funtion BigNum.compare: parameter nil") ; + elseif bnum1.signal == '+' and bnum2.signal == '-' then + return 1 ; + elseif bnum1.signal == '-' and bnum2.signal == '+' then + return 2 ; + elseif bnum1.signal == '-' and bnum2.signal == '-' then + signal = 1 ; + end + if bnum1.len > bnum2.len then + return 1 + signal ; + elseif bnum1.len < bnum2.len then + return 2 - signal ; + else + local i ; + for i = bnum1.len - 1 , 0 , -1 do + if bnum1[i] > bnum2[i] then + return 1 + signal ; + elseif bnum1[i] < bnum2[i] then + return 2 - signal ; + end + end + end + return 0 ; +end + +function BigNum.copy( bnum1 , bnum2 ) + if bnum1 ~= nil and bnum2 ~= nil then + local i ; + for i = 0 , bnum1.len - 1 do + bnum2[i] = bnum1[i] ; + end + bnum2.len = bnum1.len ; + else + error("Function BigNum.copy: parameter nil") ; + end +end + +function BigNum.change( bnum1 , num ) + local j = 0 ; + local len = 0 ; + local num = num ; + local l ; + local oldLen = 0 ; + if bnum1 == nil then + error( "BigNum.change: parameter nil" ) ; + elseif type( bnum1 ) ~= "table" then + error( "BigNum.change: parameter error, type unexpected" ) ; + elseif num == nil then + bnum1.len = 1 ; + bnum1[0] = 0 ; + bnum1.signal = "+"; + elseif type( num ) == "table" and num.len ~= nil then --check if num is a big number + --copy given table to the new one + for i = 0 , num.len do + bnum1[i] = num[i] ; + end + if num.signal ~= '-' and num.signal ~= '+' then + bnum1.signal = '+' ; + else + bnum1.signal = num.signal ; + end + oldLen = bnum1.len ; + bnum1.len = num.len ; + elseif type( num ) == "string" or type( num ) == "number" then + if string.sub( num , 1 , 1 ) == '+' or string.sub( num , 1 , 1 ) == '-' then + bnum1.signal = string.sub( num , 1 , 1 ) ; + num = string.sub(num, 2) ; + else + bnum1.signal = '+' ; + end + num = string.gsub( num , " " , "" ) ; + local sf = string.find( num , "e" ) ; + --Handles if the number is in exp notation + if sf ~= nil then + num = string.gsub( num , "%." , "" ) ; + local e = string.sub( num , sf + 1 ) ; + e = tonumber(e) ; + if e ~= nil and e > 0 then + e = tonumber(e) ; + else + error( "Function BigNum.change: string is not a valid number" ) ; + end + num = string.sub( num , 1 , sf - 2 ) ; + for i = string.len( num ) , e do + num = num .. "0" ; + end + else + sf = string.find( num , "%." ) ; + if sf ~= nil then + num = string.sub( num , 1 , sf - 1 ) ; + end + end + + l = string.len( num ) ; + oldLen = bnum1.len ; + if (l > RADIX_LEN) then + local mod = l-( math.floor( l / RADIX_LEN ) * RADIX_LEN ) ; + for i = 1 , l-mod, RADIX_LEN do + bnum1[j] = tonumber( string.sub( num, -( i + RADIX_LEN - 1 ) , -i ) ); + --Check if string dosn't represents a number + if bnum1[j] == nil then + error( "Function BigNum.change: string is not a valid number" ) ; + bnum1.len = 0 ; + return 1 ; + end + j = j + 1 ; + len = len + 1 ; + end + if (mod ~= 0) then + bnum1[j] = tonumber( string.sub( num , 1 , mod ) ) ; + bnum1.len = len + 1 ; + else + bnum1.len = len ; + end + --Eliminate trailing zeros + for i = bnum1.len - 1 , 1 , -1 do + if bnum1[i] == 0 then + bnum1[i] = nil ; + bnum1.len = bnum1.len - 1 ; + else + break ; + end + end + + else + -- string.len(num) <= RADIX_LEN + bnum1[j] = tonumber( num ) ; + bnum1.len = 1 ; + end + else + error( "Function BigNum.change: parameter error, type unexpected" ) ; + end + + --eliminates the deprecated higher order 'algarisms' + if oldLen ~= nil then + for i = bnum1.len , oldLen do + bnum1[i] = nil ; + end + end + + return 0 ; +end + +function BigNum.put( bnum , int , pos ) + if bnum == nil then + error("Function BigNum.put: parameter nil") ; + end + local i = 0 ; + for i = 0 , pos - 1 do + bnum[i] = 0 ; + end + bnum[pos] = int ; + for i = pos + 1 , bnum.len do + bnum[i] = nil ; + end + bnum.len = pos ; + return 0 ; +end + +--printraw{{{2 +function printraw( bnum ) + local i = 0 ; + if bnum == nil then + error( "Function printraw: parameter nil" ) ; + end + while 1 == 1 do + if bnum[i] == nil then + io.write( ' len '..bnum.len ) ; + if i ~= bnum.len then + io.write( ' ERRO!!!!!!!!' ) ; + end + io.write( "\n" ) ; + return 0 ; + end + io.write( 'r'..bnum[i] ) ; + i = i + 1 ; + end +end +--max{{{2 +function max( int1 , int2 ) + if int1 > int2 then + return int1 ; + else + return int2 ; + end +end + +--decr{{{2 +function decr( bnum1 ) + local temp = {} ; + temp = BigNum.new( "1" ) ; + BigNum.sub( bnum1 , temp , bnum1 ) ; + return 0 ; +end diff --git a/bin/numbers/BigRat.lua b/bin/numbers/BigRat.lua new file mode 100644 index 0000000..40e9777 --- /dev/null +++ b/bin/numbers/BigRat.lua @@ -0,0 +1,227 @@ +require( "bin.numbers.BigNum" ) ; + +BigRat = {} ; +BigRat.mt = {} ; +function BigRat.new( num1 , num2 ) --{{{2 + local bigrat = {} ; + local f ; + setmetatable(bigrat, BigRat.mt) ; + if type( num1 ) == "table" then + if num1.num ~= nil and num1.den ~= nil then + bigrat.num = BigNum.new( num1.num ) ; + bigrat.den = BigNum.new( num1.den ) ; + else + bigrat.num = BigNum.new( num1 ) ; + bigrat.den = BigNum.new( "1" ) ; + end + elseif num1 ~= nil then + if num2 == nil then + bigrat.den = BigNum.new( "1" ) ; + else + bigrat.den = BigNum.new( num2 ) ; + end + bigrat.num = BigNum.new( num1 ) ; + else + bigrat.den = BigNum.new( ) ; + bigrat.num = BigNum.new( ) ; + end + + --Update the signals + if bigrat.den.signal == "-" then + if bigrat.num.signal == "-" then + bigrat.num.signal = "+" ; + else + bigrat.num.signal = "-" ; + end + bigrat.den.signal = "+" ; + end + + return bigrat ; +end + +function BigRat.mt.sub( num1 , num2 ) + local temp = BigRat.new() ; + local brat1 = BigRat.new( num1 ) ; + local brat2 = BigRat.new( num2 ) ; + BigRat.sub( brat1 , brat2 , temp ) ; + return temp ; +end + +function BigRat.mt.add( num1 , num2 ) + local temp = BigRat.new() ; + local brat1 = BigRat.new( num1 ) ; + local brat2 = BigRat.new( num2 ) ; + BigRat.add( brat1 , brat2 , temp ) ; + return temp ; +end + +function BigRat.mt.mul( num1 , num2 ) + local temp = BigRat.new() ; + local brat1 = BigRat.new( num1 ) ; + local brat2 = BigRat.new( num2 ) ; + BigRat.mul( brat1 , brat2 , temp ) ; + return temp ; +end + +function BigRat.mt.div( num1 , num2 ) + local brat1 = BigRat.new( num1 ) ; + local brat2 = BigRat.new( num2 ) ; + local brat3 = BigRat.new() ; + local brat4 = BigRat.new() ; + BigRat.div( brat1 , brat2 , brat3 , brat4 ) ; + return brat3 , brat4 ; +end + +function BigRat.mt.tostring( brat ) + BigRat.simplify( brat ) ; + return BigNum.mt.tostring( brat.num ) .. " / " .. BigNum.mt.tostring( brat.den ) ; +end + +function BigRat.mt.pow ( num1 , num2 ) + local brat1 = BigRat.new( num1 ) ; + local brat2 = BigRat.new( num2 ) ; + return BigRat.pow( brat1 , brat2 ) +end + +function BigRat.mt.eq ( num1 , num2 ) + return BigRat.eq( num1 , num2 ) +end + +function BigRat.mt.lt ( num1 , num2 ) + return BigRat.lt( num1 , num2 ) +end + +function BigRat.mt.le ( num1 , num2 ) + return BigRat.le( num1 , num2 ) +end + +function BigRat.mt.unm ( num ) + local ret = BigRat.new( num ) + if ret.num.signal == '-' then + ret.num.signal = '+' + else + ret.num.signal = '-' + end + return ret +end + +BigRat.mt.__metatable = "hidden" +BigRat.mt.__tostring = BigRat.mt.tostring +BigRat.mt.__add = BigRat.mt.add +BigRat.mt.__sub = BigRat.mt.sub +BigRat.mt.__mul = BigRat.mt.mul +BigRat.mt.__div = BigRat.mt.div +BigRat.mt.__pow = BigRat.mt.pow +BigRat.mt.__unm = BigRat.mt.unm +BigRat.mt.__eq = BigRat.mt.eq +BigRat.mt.__le = BigRat.mt.le +BigRat.mt.__lt = BigRat.mt.lt +setmetatable( BigRat.mt, { __index = "inexistent field", __newindex = "not available", __metatable="hidden" } ) ; +function BigRat.add( brat1 , brat2 , brat3 ) + brat3.den = brat1.den * brat2.den ; + brat3.num = ( brat1.num * brat2.den ) + ( brat2.num * brat1.den ) ; + return brat3 ; +end +function BigRat.sub( brat1 , brat2 , brat3 ) + brat3.den = brat1.den * brat2.den ; + brat3.num = ( brat1.num * brat2.den ) - ( brat2.num * brat1.den ) ; + return brat3 ; +end + +function BigRat.mul( brat1 , brat2 , brat3 ) + brat3.num = brat1.num * brat2.num ; + brat3.den = brat1.den * brat2.den ; + return 0 ; +end + +function BigRat.div( brat1 , brat2 , brat3 ) + brat3.num = brat1.num * brat2.den ; + brat3.den = brat1.den * brat2.num ; + return brat3 ; +end + +function BigRat.pow( bnum1 , bnum2 ) + if bnum1 == nil or bnum2 == nil then + error( "Function BigRat.pow: parameter nil" ) ; + end + local x = BigRat.new( "8" ) ; + local n = BigRat.new( bnum2.den ) ; + local n2 ; + local y = BigRat.new( ) ; + local i ; + local temp = BigRat.new( ) ; + + BigRat.simplify( bnum2 ) ; + temp.num = BigNum.exp( bnum1.num , bnum2.num ) ; + temp.den = BigNum.exp( bnum1.den , bnum2.num ) ; + n2 = n - 1 ; + + for i = 0 , 4 do + y.num = x.num ^ n2.num ; + y.den = x.den ^ n2.num ; + x = (( temp / y ) + ( n2 * x )) / n ; + end + return x ; +end + +function BigRat.simplify( brat ) + if brat == nil then + error( "Function BigRat.simplify: parameter nil" ) ; + end + local gcd = BigNum.new( ) ; + local temp = BigRat.new( brat ) ; + local devnull = BigNum.new( ) ; + local zero = BigNum.new( "0" ) ; + --Check if numerator is zero + if BigNum.compareAbs( brat.num , zero ) == 0 then + brat.den = BigNum.new( "1" ) ; + return 0 ; + end + gcd = BigNum.gcd( brat.num , brat.den ) ; + BigNum.div( temp.num , gcd , brat.num , devnull ) ; + BigNum.div( temp.den , gcd , brat.den , devnull ) ; + --Update the signal + if brat.num.signal == '-' and brat.den.signal == '-' then + brat.num.signal = '+' ; + brat.den.signal = '+' ; + end + return 0 ; +end + +function BigRat.eq( brat1 , brat2 ) + if BigRat.compare( brat1 , brat2 ) == 0 then + return true ; + else + return false ; + end +end + +function BigRat.lt( brat1 , brat2 ) + if BigRat.compare( brat1 , brat2 ) == 2 then + return true ; + else + return false ; + end +end + +function BigRat.le( brat1 , brat2 ) + local temp = -1 ; + temp = BigRat.compare( brat1 , brat2 ) + if temp == 0 or temp == 2 then + return true ; + else + return false ; + end +end + +function BigRat.compare( bnum1 , bnum2 ) + local temp ; + temp = bnum1 - bnum2 ; + if temp.num[0] == 0 and temp.num.len == 1 then --Check if is zero + return 0 ; + elseif temp.num.signal == "-" then + return 2 ; + else + return 1 ; + end +end diff --git a/bin/numbers/no_jit_bit.lua b/bin/numbers/no_jit_bit.lua new file mode 100644 index 0000000..2cfdc1d --- /dev/null +++ b/bin/numbers/no_jit_bit.lua @@ -0,0 +1,333 @@ +--[[ +LICENSE + + (c) 2008-2011 David Manura. Licensed under the same terms as Lua (MIT). +--]] + +local M = {_TYPE='module', _NAME='bit.numberlua', _VERSION='0.3.1.20120131'} + +local floor = math.floor + +local MOD = 2^32 +local MODM = MOD-1 + +local function memoize(f) + local mt = {} + local t = setmetatable({}, mt) + function mt:__index(k) + local v = f(k); t[k] = v + return v + end + return t +end + +local function make_bitop_uncached(t, m) + local function bitop(a, b) + local res,p = 0,1 + while a ~= 0 and b ~= 0 do + local am, bm = a%m, b%m + res = res + t[am][bm]*p + a = (a - am) / m + b = (b - bm) / m + p = p*m + end + res = res + (a+b)*p + return res + end + return bitop +end + +local function make_bitop(t) + local op1 = make_bitop_uncached(t,2^1) + local op2 = memoize(function(a) + return memoize(function(b) + return op1(a, b) + end) + end) + return make_bitop_uncached(op2, 2^(t.n or 1)) +end + +-- ok? probably not if running on a 32-bit int Lua number type platform +function M.tobit(x) + return x % 2^32 +end + +M.bxor = make_bitop {[0]={[0]=0,[1]=1},[1]={[0]=1,[1]=0}, n=4} +local bxor = M.bxor + +function M.bnot(a) return MODM - a end +local bnot = M.bnot + +function M.band(a,b) return ((a+b) - bxor(a,b))/2 end +local band = M.band + +function M.bor(a,b) return MODM - band(MODM - a, MODM - b) end +local bor = M.bor + +local lshift, rshift -- forward declare + +function M.rshift(a,disp) -- Lua5.2 insipred + if disp < 0 then return lshift(a,-disp) end + return floor(a % 2^32 / 2^disp) +end +rshift = M.rshift + +function M.lshift(a,disp) -- Lua5.2 inspired + if disp < 0 then return rshift(a,-disp) end + return (a * 2^disp) % 2^32 +end +lshift = M.lshift + +function M.tohex(x, n) -- BitOp style + n = n or 8 + local up + if n <= 0 then + if n == 0 then return '' end + up = true + n = - n + end + x = band(x, 16^n-1) + return ('%0'..n..(up and 'X' or 'x')):format(x) +end +local tohex = M.tohex + +function M.extract(n, field, width) -- Lua5.2 inspired + width = width or 1 + return band(rshift(n, field), 2^width-1) +end +local extract = M.extract + +function M.replace(n, v, field, width) -- Lua5.2 inspired + width = width or 1 + local mask1 = 2^width-1 + v = band(v, mask1) -- required by spec? + local mask = bnot(lshift(mask1, field)) + return band(n, mask) + lshift(v, field) +end +local replace = M.replace + +function M.bswap(x) -- BitOp style + local a = band(x, 0xff); x = rshift(x, 8) + local b = band(x, 0xff); x = rshift(x, 8) + local c = band(x, 0xff); x = rshift(x, 8) + local d = band(x, 0xff) + return lshift(lshift(lshift(a, 8) + b, 8) + c, 8) + d +end +local bswap = M.bswap + +function M.rrotate(x, disp) -- Lua5.2 inspired + disp = disp % 32 + local low = band(x, 2^disp-1) + return rshift(x, disp) + lshift(low, 32-disp) +end +local rrotate = M.rrotate + +function M.lrotate(x, disp) -- Lua5.2 inspired + return rrotate(x, -disp) +end +local lrotate = M.lrotate + +M.rol = M.lrotate -- LuaOp inspired +M.ror = M.rrotate -- LuaOp insipred + + +function M.arshift(x, disp) -- Lua5.2 inspired + local z = rshift(x, disp) + if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end + return z +end +local arshift = M.arshift + +function M.btest(x, y) -- Lua5.2 inspired + return band(x, y) ~= 0 +end + +M.bit32 = {} -- Lua 5.2 'bit32' compatibility + + +local function bit32_bnot(x) + return (-1 - x) % MOD +end +M.bit32.bnot = bit32_bnot + +local function bit32_bxor(a, b, c, ...) + local z + if b then + a = a % MOD + b = b % MOD + z = bxor(a, b) + if c then + z = bit32_bxor(z, c, ...) + end + return z + elseif a then + return a % MOD + else + return 0 + end +end +M.bit32.bxor = bit32_bxor + +local function bit32_band(a, b, c, ...) + local z + if b then + a = a % MOD + b = b % MOD + z = ((a+b) - bxor(a,b)) / 2 + if c then + z = bit32_band(z, c, ...) + end + return z + elseif a then + return a % MOD + else + return MODM + end +end +M.bit32.band = bit32_band + +local function bit32_bor(a, b, c, ...) + local z + if b then + a = a % MOD + b = b % MOD + z = MODM - band(MODM - a, MODM - b) + if c then + z = bit32_bor(z, c, ...) + end + return z + elseif a then + return a % MOD + else + return 0 + end +end +M.bit32.bor = bit32_bor + +function M.bit32.btest(...) + return bit32_band(...) ~= 0 +end + +function M.bit32.lrotate(x, disp) + return lrotate(x % MOD, disp) +end + +function M.bit32.rrotate(x, disp) + return rrotate(x % MOD, disp) +end + +function M.bit32.lshift(x,disp) + if disp > 31 or disp < -31 then return 0 end + return lshift(x % MOD, disp) +end + +function M.bit32.rshift(x,disp) + if disp > 31 or disp < -31 then return 0 end + return rshift(x % MOD, disp) +end + +function M.bit32.arshift(x,disp) + x = x % MOD + if disp >= 0 then + if disp > 31 then + return (x >= 0x80000000) and MODM or 0 + else + local z = rshift(x, disp) + if x >= 0x80000000 then z = z + lshift(2^disp-1, 32-disp) end + return z + end + else + return lshift(x, -disp) + end +end + +function M.bit32.extract(x, field, ...) + local width = ... or 1 + if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end + x = x % MOD + return extract(x, field, ...) +end + +function M.bit32.replace(x, v, field, ...) + local width = ... or 1 + if field < 0 or field > 31 or width < 0 or field+width > 32 then error 'out of range' end + x = x % MOD + v = v % MOD + return replace(x, v, field, ...) +end + +M.bit = {} -- LuaBitOp "bit" compatibility + +function M.bit.tobit(x) + x = x % MOD + if x >= 0x80000000 then x = x - MOD end + return x +end +local bit_tobit = M.bit.tobit + +function M.bit.tohex(x, ...) + return tohex(x % MOD, ...) +end + +function M.bit.bnot(x) + return bit_tobit(bnot(x % MOD)) +end + +local function bit_bor(a, b, c, ...) + if c then + return bit_bor(bit_bor(a, b), c, ...) + elseif b then + return bit_tobit(bor(a % MOD, b % MOD)) + else + return bit_tobit(a) + end +end +M.bit.bor = bit_bor + +local function bit_band(a, b, c, ...) + if c then + return bit_band(bit_band(a, b), c, ...) + elseif b then + return bit_tobit(band(a % MOD, b % MOD)) + else + return bit_tobit(a) + end +end +M.bit.band = bit_band + +local function bit_bxor(a, b, c, ...) + if c then + return bit_bxor(bit_bxor(a, b), c, ...) + elseif b then + return bit_tobit(bxor(a % MOD, b % MOD)) + else + return bit_tobit(a) + end +end +M.bit.bxor = bit_bxor + +function M.bit.lshift(x, n) + return bit_tobit(lshift(x % MOD, n % 32)) +end + +function M.bit.rshift(x, n) + return bit_tobit(rshift(x % MOD, n % 32)) +end + +function M.bit.arshift(x, n) + return bit_tobit(arshift(x % MOD, n % 32)) +end + +function M.bit.rol(x, n) + return bit_tobit(lrotate(x % MOD, n % 32)) +end + +function M.bit.ror(x, n) + return bit_tobit(rrotate(x % MOD, n % 32)) +end + +function M.bit.bswap(x) + return bit_tobit(bswap(x % MOD)) +end + +return M diff --git a/bin/numbers/random.lua b/bin/numbers/random.lua new file mode 100644 index 0000000..091a7f5 --- /dev/null +++ b/bin/numbers/random.lua @@ -0,0 +1,232 @@ +--[[---------------------------------------- +Random +Not all of this is mine +------------------------------------------]] +--[[------------------------------------ +RandomLua v0.3.1 +Pure Lua Pseudo-Random Numbers Generator +Under the MIT license. +copyright(c) 2011 linux-man +--]]------------------------------------ + +local math_floor = math.floor + +local function normalize(n) + return n % 0x80000000 +end + +local function bit_and(a, b) + local r = 0 + local m = 0 + for m = 0, 31 do + if (a % 2 == 1) and (b % 2 == 1) then r = r + 2^m end + if a % 2 ~= 0 then a = a - 1 end + if b % 2 ~= 0 then b = b - 1 end + a = a / 2 b = b / 2 + end + return normalize(r) +end + +local function bit_or(a, b) + local r = 0 + local m = 0 + for m = 0, 31 do + if (a % 2 == 1) or (b % 2 == 1) then r = r + 2^m end + if a % 2 ~= 0 then a = a - 1 end + if b % 2 ~= 0 then b = b - 1 end + a = a / 2 b = b / 2 + end + return normalize(r) +end + +local function bit_xor(a, b) + local r = 0 + local m = 0 + for m = 0, 31 do + if a % 2 ~= b % 2 then r = r + 2^m end + if a % 2 ~= 0 then a = a - 1 end + if b % 2 ~= 0 then b = b - 1 end + a = a / 2 b = b / 2 + end + return normalize(r) +end + +local function seed() + return normalize(os.time()) +end + +--Mersenne twister +local mersenne_twister = {} +mersenne_twister.__index = mersenne_twister + +function mersenne_twister:randomseed(s) + if not s then s = seed() end + self.mt[0] = normalize(s) + for i = 1, 623 do + self.mt[i] = normalize(0x6c078965 * bit_xor(self.mt[i-1], math_floor(self.mt[i-1] / 0x40000000)) + i) + end +end + +function mersenne_twister:random(a, b) + local y + if self.index == 0 then + for i = 0, 623 do + y = self.mt[(i + 1) % 624] % 0x80000000 + self.mt[i] = bit_xor(self.mt[(i + 397) % 624], math_floor(y / 2)) + if y % 2 ~= 0 then self.mt[i] = bit_xor(self.mt[i], 0x9908b0df) end + end + end + y = self.mt[self.index] + y = bit_xor(y, math_floor(y / 0x800)) + y = bit_xor(y, bit_and(normalize(y * 0x80), 0x9d2c5680)) + y = bit_xor(y, bit_and(normalize(y * 0x8000), 0xefc60000)) + y = bit_xor(y, math_floor(y / 0x40000)) + self.index = (self.index + 1) % 624 + if not a then return y / 0x80000000 + elseif not b then + if a == 0 then return y + else return 1 + (y % a) + end + else + return a + (y % (b - a + 1)) + end +end + +local function twister(s) + local temp = {} + setmetatable(temp, mersenne_twister) + temp.mt = {} + temp.index = 0 + temp:randomseed(s) + return temp +end + +--Linear Congruential Generator +local linear_congruential_generator = {} +linear_congruential_generator.__index = linear_congruential_generator + +function linear_congruential_generator:random(a, b) + local y = (self.a * self.x + self.c) % self.m + self.x = y + if not a then return y / 0x10000 + elseif not b then + if a == 0 then return y + else return 1 + (y % a) end + else + return a + (y % (b - a + 1)) + end +end + +function linear_congruential_generator:randomseed(s) + if not s then s = seed() end + self.x = normalize(s) +end + +local function lcg(s, r) + local temp = {} + setmetatable(temp, linear_congruential_generator) + temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C + if r then + if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes. + elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC + end + temp:randomseed(s) + return temp +end + +-- Multiply-with-carry +local multiply_with_carry = {} +multiply_with_carry.__index = multiply_with_carry + +function multiply_with_carry:random(a, b) + local m = self.m + local t = self.a * self.x + self.c + local y = t % m + self.x = y + self.c = math_floor(t / m) + if not a then return y / 0x10000 + elseif not b then + if a == 0 then return y + else return 1 + (y % a) end + else + return a + (y % (b - a + 1)) + end +end + +function multiply_with_carry:randomseed(s) + if not s then s = seed() end + self.c = self.ic + self.x = normalize(s) +end + +local function mwc(s, r) + local temp = {} + setmetatable(temp, multiply_with_carry) + temp.a, temp.c, temp.m = 1103515245, 12345, 0x10000 --from Ansi C + if r then + if r == 'nr' then temp.a, temp.c, temp.m = 1664525, 1013904223, 0x10000 --from Numerical Recipes. + elseif r == 'mvc' then temp.a, temp.c, temp.m = 214013, 2531011, 0x10000 end--from MVC + end + temp.ic = temp.c + temp:randomseed(s) + return temp +end +-- Little bind for the methods: My code starts +local randomGen={} +randomGen.__index=randomGen +function randomGen:new(s) + local temp={} + setmetatable(temp,randomGen) + temp[1]=twister() + temp[2]=lcg() + temp[3]=mwc() + temp.pos=1 + for i=1,3 do + temp[i]:randomseed(s) + end + return temp +end +function randomGen:randomseed(s) + self.pos=1 + self[1]:randomseed(s) + self[2]:randomseed(s) + self[3]:randomseed(s) +end +function randomGen:randomInt(a,b) + local t=self[self.pos]:random(a,b) + self.pos=self.pos+1 + if self.pos>3 then + self.pos=1 + end + return t +end +function randomGen:newND(a,b,s) + if not(a) or not(b) then error('You must include a range!') end + local temp=randomGen:new(s) + temp.a=a + temp.b=b + temp.range=b-a+1 + temp.dups={no=0} + function temp:nextInt() + local t=self:randomInt(self.a,self.b) + if self.dups[t]==nil then + self.dups[t]=true + self.dups.no=self.dups.no+1 + else + return self:nextInt() + end + if self.dups.no==self.range then + function self:nextInt() + return 1,true + end + return t + else + return t + end + end + function temp:nextIInt() + return function() return self:nextInt() end + end + return temp +end +return randomGen diff --git a/bin/support/vfs.lua b/bin/support/vfs.lua new file mode 100644 index 0000000..dae0b43 --- /dev/null +++ b/bin/support/vfs.lua @@ -0,0 +1 @@ +local bin = require("bin") \ No newline at end of file diff --git a/conf.lua b/conf.lua new file mode 100644 index 0000000..096f054 --- /dev/null +++ b/conf.lua @@ -0,0 +1,39 @@ +function love.conf(t) + t.identity = nil -- The name of the save directory (string) + t.version = "11.1" -- The LOVE version this game was made for (string) + t.console = true -- Attach a console (boolean, Windows only) + + t.window.title = "game" -- The window title (string) + t.window.icon = nil -- Filepath to an image to use as the window's icon (string) + t.window.width = 800 -- The window width (number) + t.window.height = 600 -- The window height (number) + t.window.borderless = false -- Remove all border visuals from the window (boolean) + t.window.resizable = true -- Let the window be user-resizable (boolean) + t.window.minwidth = 1 -- Minimum window width if the window is resizable (number) + t.window.minheight = 1 -- Minimum window height if the window is resizable (number) + t.window.fullscreen = false -- Enable fullscreen (boolean) + t.window.fullscreentype = "desktop" -- Standard fullscreen or desktop fullscreen mode (string) + t.window.vsync = false -- Enable vertical sync (boolean) + t.window.fsaa = 0 -- The number of samples to use with multi-sampled antialiasing (number) + t.window.display = 1 -- Index of the monitor to show the window in (number) + t.window.highdpi = false -- Enable high-dpi mode for the window on a Retina display (boolean) + t.window.srgb = false -- Enable sRGB gamma correction when drawing to the screen (boolean) + t.window.x = nil -- The x-coordinate of the window's position in the specified display (number) + t.window.y = nil -- The y-coordinate of the window's position in the specified display (number) + + t.modules.audio = true -- Enable the audio module (boolean) + t.modules.event = true -- Enable the event module (boolean) + t.modules.graphics = true -- Enable the graphics module (boolean) + t.modules.image = true -- Enable the image module (boolean) + t.modules.joystick = true -- Enable the joystick module (boolean) + t.modules.keyboard = true -- Enable the keyboard module (boolean) + t.modules.math = true -- Enable the math module (boolean) + t.modules.mouse = true -- Enable the mouse module (boolean) + t.modules.physics = true -- Enable the physics module (boolean) + t.modules.sound = true -- Enable the sound module (boolean) + t.modules.system = true -- Enable the system module (boolean) + t.modules.timer = true -- Enable the timer module (boolean) + t.modules.window = true -- Enable the window module (boolean) + t.modules.thread = true -- Enable the thread module (boolean) +end +--1440 x 2560 diff --git a/images/menu.png b/images/menu.png new file mode 100644 index 0000000..8869bea Binary files /dev/null and b/images/menu.png differ diff --git a/images/menuX.png b/images/menuX.png new file mode 100644 index 0000000..682fddb Binary files /dev/null and b/images/menuX.png differ diff --git a/luajit-request/init.lua b/luajit-request/init.lua new file mode 100644 index 0000000..fe5ddf1 --- /dev/null +++ b/luajit-request/init.lua @@ -0,0 +1,397 @@ +--[[ +LuaJIT-Request +Lucien Greathouse +Wrapper for LuaJIT-cURL for easy HTTP(S) requests. + +Copyright (c) 2016 Lucien Greathouse + +This software is provided 'as-is', without any express +or implied warranty. In no event will the authors be held +liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, andto alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must +not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. +]] + +local path = (...):gsub("%.init$", ""):match("%.?(.-)$") .. "." + +local ffi = require("ffi") +local curl = require(path .. "luajit-curl") +local request + +local function url_encode(str) + if (str) then + str = str:gsub("\n", "\r\n") + str = str:gsub("([^%w %-%_%.%~])", function(c) + return string.format ("%%%02X", string.byte(c)) + end) + str = str:gsub(" ", "%%20") + end + return str +end + +local function cookie_encode(str, name) + str = str:gsub("[,;%s]", "") + + if (name) then + str = str:gsub("=", "") + end + + return str +end + +local auth_map = { + BASIC = ffi.cast("long", curl.CURLAUTH_BASIC), + DIGEST = ffi.cast("long", curl.CURLAUTH_DIGEST), + NEGOTIATE = ffi.cast("long", curl.CURLAUTH_NEGOTIATE) +} + +local errors = { + unknown = 0, + timeout = 1, + connect = 2, + resolve_host = 3 +} + +local code_map = { + [curl.CURLE_OPERATION_TIMEDOUT] = { + errors.timeout, "Connection timed out" + }, + [curl.CURLE_COULDNT_RESOLVE_HOST] = { + errors.resolve_host, "Couldn't resolve host" + }, + [curl.CURLE_COULDNT_CONNECT] = { + errors.connect, "Couldn't connect to host" + } +} + +request = { + error = errors, + + version = "2.4.0", + version_major = 2, + version_minor = 4, + version_patch = 0, + + --[[ + Send an HTTP(S) request to the URL at 'url' using the HTTP method 'method'. + Use the 'args' parameter to optionally configure the request: + - method: HTTP method to use. Defaults to "GET", but can be any HTTP verb like "POST" or "PUT" + - headers: Dictionary of additional HTTP headers to send with request + - data: Dictionary or string to send as request body + - cookies: Dictionary table of cookies to send + - timeout: How long to wait for the connection to be made before giving up + - allow_redirects: Whether or not to allow redirection. Defaults to true + - body_stream_callback: A method to call with each piece of the response body. + - header_stream_callback: A method to call with each piece of the resulting header. + - transfer_info_callback: A method to call with transfer progress data. + - auth_type: Authentication method to use. Defaults to "none", but can also be "basic", "digest" or "negotiate" + - username: A username to use with authentication. 'auth_type' must also be specified. + - password: A password to use with authentication. 'auth_type' must also be specified. + - files: A dictionary of file names to their paths on disk to upload via stream. + + If both body_stream_callback and header_stream_callback are defined, a boolean true will be returned instead of the following object. + + The return object is a dictionary with the following members: + - code: The HTTP status code the response gave. Will not exist if header_stream_callback is defined above. + - body: The body of the response. Will not exist if body_stream_callback is defined above. + - headers: A dictionary of headers and their values. Will not exist if header_stream_callback is defined above. + - headers_raw: A raw string containing the actual headers the server sent back. Will not exist if header_stream_callback is defined above. + - set_cookies: A dictionary of cookies given by the "Set-Cookie" header from the server. Will not exist if the server did not set any cookies. + + If an error occured, false will be returned along with a curl error code and a message. + ]] + send = function(url, args) + local handle = curl.curl_easy_init() + local header_chunk + local out_buffer + local headers_buffer + args = args or {} + + local callbacks = {} + local gc_handles = {} + + curl.curl_easy_setopt(handle, curl.CURLOPT_URL, url) + curl.curl_easy_setopt(handle, curl.CURLOPT_SSL_VERIFYPEER, 1) + curl.curl_easy_setopt(handle, curl.CURLOPT_SSL_VERIFYHOST, 2) + + if (args.data and type(args.data) ~= "table") then + local default_content_type = "application/octet-stream" + if (not args.headers) then + args.headers = { + ["content-type"] = default_content_type + } + else + local has_content_type = false + for header_name, _ in pairs(args.headers) do + if header_name:lower() == "content-type" then + has_content_type = true + break + end + end + if not has_content_type then + args.headers["content-type"] = default_content_type + end + end + end + + if (args.method) then + local method = string.upper(tostring(args.method)) + + if (method == "GET") then + curl.curl_easy_setopt(handle, curl.CURLOPT_HTTPGET, 1) + elseif (method == "POST") then + curl.curl_easy_setopt(handle, curl.CURLOPT_POST, 1) + args.data = args.data or "" -- https://github.com/curl/curl/issues/1625#issuecomment-312456910 + else + curl.curl_easy_setopt(handle, curl.CURLOPT_CUSTOMREQUEST, method) + end + end + + if (args.headers) then + for key, value in pairs(args.headers) do + header_chunk = curl.curl_slist_append(header_chunk, tostring(key) .. ":" .. tostring(value)) + end + + curl.curl_easy_setopt(handle, curl.CURLOPT_HTTPHEADER, header_chunk) + end + + if (args.auth_type) then + local auth = string.upper(tostring(args.auth_type)) + + if (auth_map[auth]) then + curl.curl_easy_setopt(handle, curl.CURLOPT_HTTPAUTH, auth_map[auth]) + curl.curl_easy_setopt(handle, curl.CURLOPT_USERNAME, tostring(args.username)) + curl.curl_easy_setopt(handle, curl.CURLOPT_PASSWORD, tostring(args.password or "")) + elseif (auth ~= "NONE") then + error("Unsupported authentication type '" .. auth .. "'") + end + end + + if (args.body_stream_callback) then + local callback = ffi.cast("curl_callback", function(data, size, nmeb, user) + args.body_stream_callback(ffi.string(data, size * nmeb)) + return size * nmeb + end) + + table.insert(callbacks, callback) + + curl.curl_easy_setopt(handle, curl.CURLOPT_WRITEFUNCTION, callback) + else + out_buffer = {} + + local callback = ffi.cast("curl_callback", function(data, size, nmeb, user) + table.insert(out_buffer, ffi.string(data, size * nmeb)) + return size * nmeb + end) + + table.insert(callbacks, callback) + + curl.curl_easy_setopt(handle, curl.CURLOPT_WRITEFUNCTION, callback) + end + + if (args.header_stream_callback) then + local callback = ffi.cast("curl_callback", function(data, size, nmeb, user) + args.header_stream_callback(ffi.string(data, size * nmeb)) + return size * nmeb + end) + + table.insert(callbacks, callback) + + curl.curl_easy_setopt(handle, curl.CURLOPT_HEADERFUNCTION, callback) + else + headers_buffer = {} + + local callback = ffi.cast("curl_callback", function(data, size, nmeb, user) + table.insert(headers_buffer, ffi.string(data, size * nmeb)) + return size * nmeb + end) + + table.insert(callbacks, callback) + + curl.curl_easy_setopt(handle, curl.CURLOPT_HEADERFUNCTION, callback) + end + + if (args.transfer_info_callback) then + local callback = ffi.cast("curl_xferinfo_callback", function(client, dltotal, dlnow, ultotal, ulnow) + args.transfer_info_callback(tonumber(dltotal), tonumber(dlnow), tonumber(ultotal), tonumber(ulnow)) + return 0 + end) + + table.insert(callbacks, callback) + + curl.curl_easy_setopt(handle, curl.CURLOPT_NOPROGRESS, 0) + curl.curl_easy_setopt(handle, curl.CURLOPT_XFERINFOFUNCTION, callback) + end + + if (args.follow_redirects == nil) then + curl.curl_easy_setopt(handle, curl.CURLOPT_FOLLOWLOCATION, true) + else + curl.curl_easy_setopt(handle, curl.CURLOPT_FOLLOWLOCATION, not not args.follow_redirects) + end + + if (args.data) then + if (type(args.data) == "table") then + local buffer = {} + for key, value in pairs(args.data) do + table.insert(buffer, ("%s=%s"):format(url_encode(key), url_encode(value))) + end + + curl.curl_easy_setopt(handle, curl.CURLOPT_POSTFIELDS, table.concat(buffer, "&")) + else + curl.curl_easy_setopt(handle, curl.CURLOPT_POSTFIELDS, tostring(args.data)) + end + end + + local post + if (args.files) then + post = ffi.new("struct curl_httppost*[1]") + local lastptr = ffi.new("struct curl_httppost*[1]") + + for key, value in pairs(args.files) do + local file = ffi.new("char[?]", #value, value) + + table.insert(gc_handles, file) + + local res = curl.curl_formadd( + post, lastptr, + ffi.new("int", curl.CURLFORM_COPYNAME), key, + ffi.new("int", curl.CURLFORM_FILE), file, + ffi.new("int", curl.CURLFORM_END) + ) + end + + curl.curl_easy_setopt(handle, curl.CURLOPT_HTTPPOST, post[0]) + end + + -- Enable the cookie engine + curl.curl_easy_setopt(handle, curl.CURLOPT_COOKIEFILE, "") + + if (args.cookies) then + local cookie_out + + if (type(args.cookies) == "table") then + local buffer = {} + for key, value in pairs(args.cookies) do + table.insert(buffer, ("%s=%s"):format(cookie_encode(key, true), cookie_encode(value))) + end + + cookie_out = table.concat(buffer, "; ") + else + cookie_out = tostring(args.cookies) + end + + curl.curl_easy_setopt(handle, curl.CURLOPT_COOKIE, cookie_out) + end + + if (tonumber(args.timeout)) then + curl.curl_easy_setopt(handle, curl.CURLOPT_CONNECTTIMEOUT, tonumber(args.timeout)) + end + + local code = curl.curl_easy_perform(handle) + + if (code ~= curl.CURLE_OK) then + local num = tonumber(code) + + if (code_map[num]) then + return false, code_map[num][1], code_map[num][2] + end + + return false, request.error.unknown, "Unknown error", num + end + + local out + + if (out_buffer or headers_buffer) then + local headers, status, parsed_headers, raw_cookies, set_cookies + + if (headers_buffer) then + -- In case we got multiple responses (e.g. 100 - Continue or 302 Redirects) + -- we want to only return the last response + local start_index = 1 + for i, resp_line in ipairs(headers_buffer) do + if resp_line:match("^HTTP/(.-)%s+(%d+)%s+(.+)\r\n$") then + start_index = i + end + end + local last_request_headers = {} + for i = start_index, #headers_buffer do + table.insert(last_request_headers, headers_buffer[i]) + end + headers = table.concat(last_request_headers) + status = tonumber(headers:match("%s+(%d+)%s+")) + + parsed_headers = {} + + for key, value in headers:gmatch("\n([^:]+): *([^\r\n]*)") do + parsed_headers[key] = value + end + end + + local cookielist = ffi.new("struct curl_slist*[1]") + curl.curl_easy_getinfo(handle, curl.CURLINFO_COOKIELIST, cookielist) + if cookielist[0] ~= nil then + raw_cookies, set_cookies = {}, {} + local cookielist = ffi.gc(cookielist[0], curl.curl_slist_free_all) + local cookie = cookielist + + repeat + local raw = ffi.string(cookie[0].data) + table.insert(raw_cookies, raw) + + local domain, subdomains, path, secure, expiration, name, value = raw:match("^(.-)\t(.-)\t(.-)\t(.-)\t(.-)\t(.-)\t(.*)$") + set_cookies[name] = value + cookie = cookie[0].next + until cookie == nil + end + + out = { + body = table.concat(out_buffer), + headers = parsed_headers, + raw_cookies = raw_cookies, + set_cookies = set_cookies, + code = status, + raw_headers = headers + } + else + out = true + end + + curl.curl_easy_cleanup(handle) + curl.curl_slist_free_all(header_chunk) + + if (post) then + curl.curl_formfree(post[0]) + end + gc_handles = {} + + for i, v in ipairs(callbacks) do + v:free() + end + + return out + end, + + init = function() + curl.curl_global_init(curl.CURL_GLOBAL_ALL) + end, + + close = function() + curl.curl_global_cleanup() + end +} + +request.init() + +return request diff --git a/luajit-request/luajit-curl.lua b/luajit-request/luajit-curl.lua new file mode 100644 index 0000000..1d7bcfb --- /dev/null +++ b/luajit-request/luajit-curl.lua @@ -0,0 +1,1016 @@ +--[[ +LuaJIT-cURL +Lucien Greathouse +LuaJIT FFI cURL binding aimed at cURL version 7.38.0. + +Copyright (c) 2014 lucien Greathouse + +This software is provided 'as-is', without any express +or implied warranty. In no event will the authors be held +liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, andto alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must +not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. +]] + +local ffi = require("ffi") +local curl = ffi.load("libcurl") + +if (jit.os == "Windows") then + --Windows! + ffi.cdef([[ + //windows layering + enum { + INVALID_SOCKET = ~0, + SOCKET_BAD = ~0 + }; + ]]) +else + --Not Windows! + ffi.cdef([[ + typedef int socket_t; + + enum { + SOCKET_BAD = -1 + }; + ]]) +end + +ffi.cdef([[ + typedef int64_t time_t; + typedef unsigned int size_t; + + typedef size_t (*curl_callback)(char *data, size_t size, size_t nmeb, void *userdata); +]]) + +--curlver.h +ffi.cdef([[ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +enum { + LIBCURL_VERSION_MAJOR = 7, + LIBCURL_VERSION_MINOR = 38, + LIBCURL_VERSION_PATCH = 0, + LIBCURL_VERSION_NUM = 0x072600 +} +]]) + +--cURL's type aliasing, built around curlbuild.h +ffi.cdef([[ + typedef int64_t curl_off_t; +]]) + +--Constants +ffi.cdef([[ +enum { + CURL_GLOBAL_SSL = (1<<0), + CURL_GLOBAL_WIN32 = (1<<1), + CURL_GLOBAL_ALL = (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32), + CURL_GLOBAL_NOTHING = 0, + CURL_GLOBAL_DEFAULT = CURL_GLOBAL_ALL, + CURL_GLOBAL_ACK_EINTR = (1<<2) +}; + +enum { + CURLAUTH_NONE = 0, + CURLAUTH_BASIC = 1, + CURLAUTH_DIGEST = 1<<1, + CURLAUTH_NEGOTIATE = 1<<2 +}; +]]) + +ffi.cdef([[ +typedef void CURL; +typedef int curl_socket_t; +typedef struct curl_httppost { +struct curl_httppost *next; +char *name; +long namelength; +char *contents; +long contentslength; +char *buffer; +long bufferlength; +char *contenttype; +struct curl_slist* contentheader; +struct curl_httppost *more; +long flags; +char *showfilename; +void *userp; +}; +typedef int (*curl_progress_callback)(void *clientp, +double dltotal, +double dlnow, +double ultotal, +double ulnow); +typedef int (*curl_xferinfo_callback)(void *clientp, +curl_off_t dltotal, +curl_off_t dlnow, +curl_off_t ultotal, +curl_off_t ulnow); +typedef size_t (*curl_write_callback)(char *buffer, +size_t size, +size_t nitems, +void *outstream); +typedef enum { +CURLFILETYPE_FILE = 0, +CURLFILETYPE_DIRECTORY, +CURLFILETYPE_SYMLINK, +CURLFILETYPE_DEVICE_BLOCK, +CURLFILETYPE_DEVICE_CHAR, +CURLFILETYPE_NAMEDPIPE, +CURLFILETYPE_SOCKET, +CURLFILETYPE_DOOR, +CURLFILETYPE_UNKNOWN +} curlfiletype; +struct curl_fileinfo { +char *filename; +curlfiletype filetype; +time_t time; +unsigned int perm; +int uid; +int gid; +curl_off_t size; +long int hardlinks; +struct { +char *time; +char *perm; +char *user; +char *group; +char *target; +} strings; +unsigned int flags; +char * b_data; +size_t b_size; +size_t b_used; +}; +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, +void *ptr, +int remains); +typedef long (*curl_chunk_end_callback)(void *ptr); +typedef int (*curl_fnmatch_callback)(void *ptr, +const char *pattern, +const char *string); +typedef int (*curl_seek_callback)(void *instream, +curl_off_t offset, +int origin); +typedef size_t (*curl_read_callback)(char *buffer, +size_t size, +size_t nitems, +void *instream); +typedef enum { +CURLSOCKTYPE_IPCXN, +CURLSOCKTYPE_ACCEPT, +CURLSOCKTYPE_LAST +} curlsocktype; +typedef int (*curl_sockopt_callback)(void *clientp, +curl_socket_t curlfd, +curlsocktype purpose); +struct sockaddr { +uint8_t sa_family; +char sa_data[14]; +}; +struct curl_sockaddr { +int family; +int socktype; +int protocol; +unsigned int addrlen; +struct sockaddr addr; +}; +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, +curlsocktype purpose, +struct curl_sockaddr *address); +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); +typedef enum { +CURLIOE_OK, +CURLIOE_UNKNOWNCMD, +CURLIOE_FAILRESTART, +CURLIOE_LAST +} curlioerr; +typedef enum { +CURLIOCMD_NOP, +CURLIOCMD_RESTARTREAD, +CURLIOCMD_LAST +} curliocmd; +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, +int cmd, +void *clientp); +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); +typedef enum { +CURLINFO_TEXT = 0, +CURLINFO_HEADER_IN, +CURLINFO_HEADER_OUT, +CURLINFO_DATA_IN, +CURLINFO_DATA_OUT, +CURLINFO_SSL_DATA_IN, +CURLINFO_SSL_DATA_OUT, +CURLINFO_END +} curl_infotype; +typedef int (*curl_debug_callback) +(CURL *handle, +curl_infotype type, +char *data, +size_t size, +void *userptr); +typedef enum { +CURLE_OK = 0, +CURLE_UNSUPPORTED_PROTOCOL, +CURLE_FAILED_INIT, +CURLE_URL_MALFORMAT, +CURLE_NOT_BUILT_IN, +CURLE_COULDNT_RESOLVE_PROXY, +CURLE_COULDNT_RESOLVE_HOST, +CURLE_COULDNT_CONNECT, +CURLE_FTP_WEIRD_SERVER_REPLY, +CURLE_REMOTE_ACCESS_DENIED, +CURLE_FTP_ACCEPT_FAILED, +CURLE_FTP_WEIRD_PASS_REPLY, +CURLE_FTP_ACCEPT_TIMEOUT, +CURLE_FTP_WEIRD_PASV_REPLY, +CURLE_FTP_WEIRD_227_FORMAT, +CURLE_FTP_CANT_GET_HOST, +CURLE_HTTP2, +CURLE_FTP_COULDNT_SET_TYPE, +CURLE_PARTIAL_FILE, +CURLE_FTP_COULDNT_RETR_FILE, +CURLE_OBSOLETE20, +CURLE_QUOTE_ERROR, +CURLE_HTTP_RETURNED_ERROR, +CURLE_WRITE_ERROR, +CURLE_OBSOLETE24, +CURLE_UPLOAD_FAILED, +CURLE_READ_ERROR, +CURLE_OUT_OF_MEMORY, +CURLE_OPERATION_TIMEDOUT, +CURLE_OBSOLETE29, +CURLE_FTP_PORT_FAILED, +CURLE_FTP_COULDNT_USE_REST, +CURLE_OBSOLETE32, +CURLE_RANGE_ERROR, +CURLE_HTTP_POST_ERROR, +CURLE_SSL_CONNECT_ERROR, +CURLE_BAD_DOWNLOAD_RESUME, +CURLE_FILE_COULDNT_READ_FILE, +CURLE_LDAP_CANNOT_BIND, +CURLE_LDAP_SEARCH_FAILED, +CURLE_OBSOLETE40, +CURLE_FUNCTION_NOT_FOUND, +CURLE_ABORTED_BY_CALLBACK, +CURLE_BAD_FUNCTION_ARGUMENT, +CURLE_OBSOLETE44, +CURLE_INTERFACE_FAILED, +CURLE_OBSOLETE46, +CURLE_TOO_MANY_REDIRECTS , +CURLE_UNKNOWN_OPTION, +CURLE_TELNET_OPTION_SYNTAX , +CURLE_OBSOLETE50, +CURLE_PEER_FAILED_VERIFICATION, +CURLE_GOT_NOTHING, +CURLE_SSL_ENGINE_NOTFOUND, +CURLE_SSL_ENGINE_SETFAILED, +CURLE_SEND_ERROR, +CURLE_RECV_ERROR, +CURLE_OBSOLETE57, +CURLE_SSL_CERTPROBLEM, +CURLE_SSL_CIPHER, +CURLE_SSL_CACERT, +CURLE_BAD_CONTENT_ENCODING, +CURLE_LDAP_INVALID_URL, +CURLE_FILESIZE_EXCEEDED, +CURLE_USE_SSL_FAILED, +CURLE_SEND_FAIL_REWIND, +CURLE_SSL_ENGINE_INITFAILED, +CURLE_LOGIN_DENIED, +CURLE_TFTP_NOTFOUND, +CURLE_TFTP_PERM, +CURLE_REMOTE_DISK_FULL, +CURLE_TFTP_ILLEGAL, +CURLE_TFTP_UNKNOWNID, +CURLE_REMOTE_FILE_EXISTS, +CURLE_TFTP_NOSUCHUSER, +CURLE_CONV_FAILED, +CURLE_CONV_REQD, +CURLE_SSL_CACERT_BADFILE, +CURLE_REMOTE_FILE_NOT_FOUND, +CURLE_SSH, +CURLE_SSL_SHUTDOWN_FAILED, +CURLE_AGAIN, +CURLE_SSL_CRL_BADFILE, +CURLE_SSL_ISSUER_ERROR, +CURLE_FTP_PRET_FAILED, +CURLE_RTSP_CSEQ_ERROR, +CURLE_RTSP_SESSION_ERROR, +CURLE_FTP_BAD_FILE_LIST, +CURLE_CHUNK_FAILED, +CURLE_NO_CONNECTION_AVAILABLE, +CURL_LAST +} CURLcode; +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, +void *ssl_ctx, +void *userptr); +typedef enum { +CURLPROXY_HTTP = 0, +CURLPROXY_HTTP_1_0 = 1, +CURLPROXY_SOCKS4 = 4, +CURLPROXY_SOCKS5 = 5, +CURLPROXY_SOCKS4A = 6, +CURLPROXY_SOCKS5_HOSTNAME = 7 +} curl_proxytype; +enum curl_khtype { +CURLKHTYPE_UNKNOWN, +CURLKHTYPE_RSA1, +CURLKHTYPE_RSA, +CURLKHTYPE_DSS +}; +struct curl_khkey { +const char *key; +size_t len; +enum curl_khtype keytype; +}; +enum curl_khstat { +CURLKHSTAT_FINE_ADD_TO_FILE, +CURLKHSTAT_FINE, +CURLKHSTAT_REJECT, +CURLKHSTAT_DEFER, +CURLKHSTAT_LAST +}; +enum curl_khmatch { +CURLKHMATCH_OK, +CURLKHMATCH_MISMATCH, +CURLKHMATCH_MISSING, +CURLKHMATCH_LAST +}; +typedef int +(*curl_sshkeycallback) (CURL *easy, +const struct curl_khkey *knownkey, +const struct curl_khkey *foundkey, +enum curl_khmatch, +void *clientp); +typedef enum { +CURLUSESSL_NONE, +CURLUSESSL_TRY, +CURLUSESSL_CONTROL, +CURLUSESSL_ALL, +CURLUSESSL_LAST +} curl_usessl; +typedef enum { +CURLFTPSSL_CCC_NONE, +CURLFTPSSL_CCC_PASSIVE, +CURLFTPSSL_CCC_ACTIVE, +CURLFTPSSL_CCC_LAST +} curl_ftpccc; +typedef enum { +CURLFTPAUTH_DEFAULT, +CURLFTPAUTH_SSL, +CURLFTPAUTH_TLS, +CURLFTPAUTH_LAST +} curl_ftpauth; +typedef enum { +CURLFTP_CREATE_DIR_NONE, +CURLFTP_CREATE_DIR, +CURLFTP_CREATE_DIR_RETRY, +CURLFTP_CREATE_DIR_LAST +} curl_ftpcreatedir; +typedef enum { +CURLFTPMETHOD_DEFAULT, +CURLFTPMETHOD_MULTICWD, +CURLFTPMETHOD_NOCWD, +CURLFTPMETHOD_SINGLECWD, +CURLFTPMETHOD_LAST +} curl_ftpmethod; +typedef enum { +CURLOPT_WRITEDATA = 10000 + 1, +CURLOPT_URL = 10000 + 2, +CURLOPT_PORT = 0 + 3, +CURLOPT_PROXY = 10000 + 4, +CURLOPT_USERPWD = 10000 + 5, +CURLOPT_PROXYUSERPWD = 10000 + 6, +CURLOPT_RANGE = 10000 + 7, +CURLOPT_READDATA = 10000 + 9, +CURLOPT_ERRORBUFFER = 10000 + 10, +CURLOPT_WRITEFUNCTION = 20000 + 11, +CURLOPT_READFUNCTION = 20000 + 12, +CURLOPT_TIMEOUT = 0 + 13, +CURLOPT_INFILESIZE = 0 + 14, +CURLOPT_POSTFIELDS = 10000 + 15, +CURLOPT_REFERER = 10000 + 16, +CURLOPT_FTPPORT = 10000 + 17, +CURLOPT_USERAGENT = 10000 + 18, +CURLOPT_LOW_SPEED_LIMIT = 0 + 19, +CURLOPT_LOW_SPEED_TIME = 0 + 20, +CURLOPT_RESUME_FROM = 0 + 21, +CURLOPT_COOKIE = 10000 + 22, +CURLOPT_HTTPHEADER = 10000 + 23, +CURLOPT_HTTPPOST = 10000 + 24, +CURLOPT_SSLCERT = 10000 + 25, +CURLOPT_KEYPASSWD = 10000 + 26, +CURLOPT_CRLF = 0 + 27, +CURLOPT_QUOTE = 10000 + 28, +CURLOPT_HEADERDATA = 10000 + 29, +CURLOPT_COOKIEFILE = 10000 + 31, +CURLOPT_SSLVERSION = 0 + 32, +CURLOPT_TIMECONDITION = 0 + 33, +CURLOPT_TIMEVALUE = 0 + 34, +CURLOPT_CUSTOMREQUEST = 10000 + 36, +CURLOPT_STDERR = 10000 + 37, +CURLOPT_POSTQUOTE = 10000 + 39, +CURLOPT_OBSOLETE40 = 10000 + 40, +CURLOPT_VERBOSE = 0 + 41, +CURLOPT_HEADER = 0 + 42, +CURLOPT_NOPROGRESS = 0 + 43, +CURLOPT_NOBODY = 0 + 44, +CURLOPT_FAILONERROR = 0 + 45, +CURLOPT_UPLOAD = 0 + 46, +CURLOPT_POST = 0 + 47, +CURLOPT_DIRLISTONLY = 0 + 48, +CURLOPT_APPEND = 0 + 50, +CURLOPT_NETRC = 0 + 51, +CURLOPT_FOLLOWLOCATION = 0 + 52, +CURLOPT_TRANSFERTEXT = 0 + 53, +CURLOPT_PUT = 0 + 54, +CURLOPT_PROGRESSFUNCTION = 20000 + 56, +CURLOPT_PROGRESSDATA = 10000 + 57, +CURLOPT_AUTOREFERER = 0 + 58, +CURLOPT_PROXYPORT = 0 + 59, +CURLOPT_POSTFIELDSIZE = 0 + 60, +CURLOPT_HTTPPROXYTUNNEL = 0 + 61, +CURLOPT_INTERFACE = 10000 + 62, +CURLOPT_KRBLEVEL = 10000 + 63, +CURLOPT_SSL_VERIFYPEER = 0 + 64, +CURLOPT_CAINFO = 10000 + 65, +CURLOPT_MAXREDIRS = 0 + 68, +CURLOPT_FILETIME = 0 + 69, +CURLOPT_TELNETOPTIONS = 10000 + 70, +CURLOPT_MAXCONNECTS = 0 + 71, +CURLOPT_OBSOLETE72 = 0 + 72, +CURLOPT_FRESH_CONNECT = 0 + 74, +CURLOPT_FORBID_REUSE = 0 + 75, +CURLOPT_RANDOM_FILE = 10000 + 76, +CURLOPT_EGDSOCKET = 10000 + 77, +CURLOPT_CONNECTTIMEOUT = 0 + 78, +CURLOPT_HEADERFUNCTION = 20000 + 79, +CURLOPT_HTTPGET = 0 + 80, +CURLOPT_SSL_VERIFYHOST = 0 + 81, +CURLOPT_COOKIEJAR = 10000 + 82, +CURLOPT_SSL_CIPHER_LIST = 10000 + 83, +CURLOPT_HTTP_VERSION = 0 + 84, +CURLOPT_FTP_USE_EPSV = 0 + 85, +CURLOPT_SSLCERTTYPE = 10000 + 86, +CURLOPT_SSLKEY = 10000 + 87, +CURLOPT_SSLKEYTYPE = 10000 + 88, +CURLOPT_SSLENGINE = 10000 + 89, +CURLOPT_SSLENGINE_DEFAULT = 0 + 90, +CURLOPT_DNS_USE_GLOBAL_CACHE = 0 + 91, +CURLOPT_DNS_CACHE_TIMEOUT = 0 + 92, +CURLOPT_PREQUOTE = 10000 + 93, +CURLOPT_DEBUGFUNCTION = 20000 + 94, +CURLOPT_DEBUGDATA = 10000 + 95, +CURLOPT_COOKIESESSION = 0 + 96, +CURLOPT_CAPATH = 10000 + 97, +CURLOPT_BUFFERSIZE = 0 + 98, +CURLOPT_NOSIGNAL = 0 + 99, +CURLOPT_SHARE = 10000 + 100, +CURLOPT_PROXYTYPE = 0 + 101, +CURLOPT_ACCEPT_ENCODING = 10000 + 102, +CURLOPT_PRIVATE = 10000 + 103, +CURLOPT_HTTP200ALIASES = 10000 + 104, +CURLOPT_UNRESTRICTED_AUTH = 0 + 105, +CURLOPT_FTP_USE_EPRT = 0 + 106, +CURLOPT_HTTPAUTH = 0 + 107, +CURLOPT_SSL_CTX_FUNCTION = 20000 + 108, +CURLOPT_SSL_CTX_DATA = 10000 + 109, +CURLOPT_FTP_CREATE_MISSING_DIRS = 0 + 110, +CURLOPT_PROXYAUTH = 0 + 111, +CURLOPT_FTP_RESPONSE_TIMEOUT = 0 + 112, +CURLOPT_IPRESOLVE = 0 + 113, +CURLOPT_MAXFILESIZE = 0 + 114, +CURLOPT_INFILESIZE_LARGE = 30000 + 115, +CURLOPT_RESUME_FROM_LARGE = 30000 + 116, +CURLOPT_MAXFILESIZE_LARGE = 30000 + 117, +CURLOPT_NETRC_FILE = 10000 + 118, +CURLOPT_USE_SSL = 0 + 119, +CURLOPT_POSTFIELDSIZE_LARGE = 30000 + 120, +CURLOPT_TCP_NODELAY = 0 + 121, +CURLOPT_FTPSSLAUTH = 0 + 129, +CURLOPT_IOCTLFUNCTION = 20000 + 130, +CURLOPT_IOCTLDATA = 10000 + 131, +CURLOPT_FTP_ACCOUNT = 10000 + 134, +CURLOPT_COOKIELIST = 10000 + 135, +CURLOPT_IGNORE_CONTENT_LENGTH = 0 + 136, +CURLOPT_FTP_SKIP_PASV_IP = 0 + 137, +CURLOPT_FTP_FILEMETHOD = 0 + 138, +CURLOPT_LOCALPORT = 0 + 139, +CURLOPT_LOCALPORTRANGE = 0 + 140, +CURLOPT_CONNECT_ONLY = 0 + 141, +CURLOPT_CONV_FROM_NETWORK_FUNCTION = 20000 + 142, +CURLOPT_CONV_TO_NETWORK_FUNCTION = 20000 + 143, +CURLOPT_CONV_FROM_UTF8_FUNCTION = 20000 + 144, +CURLOPT_MAX_SEND_SPEED_LARGE = 30000 + 145, +CURLOPT_MAX_RECV_SPEED_LARGE = 30000 + 146, +CURLOPT_FTP_ALTERNATIVE_TO_USER = 10000 + 147, +CURLOPT_SOCKOPTFUNCTION = 20000 + 148, +CURLOPT_SOCKOPTDATA = 10000 + 149, +CURLOPT_SSL_SESSIONID_CACHE = 0 + 150, +CURLOPT_SSH_AUTH_TYPES = 0 + 151, +CURLOPT_SSH_PUBLIC_KEYFILE = 10000 + 152, +CURLOPT_SSH_PRIVATE_KEYFILE = 10000 + 153, +CURLOPT_FTP_SSL_CCC = 0 + 154, +CURLOPT_TIMEOUT_MS = 0 + 155, +CURLOPT_CONNECTTIMEOUT_MS = 0 + 156, +CURLOPT_HTTP_TRANSFER_DECODING = 0 + 157, +CURLOPT_HTTP_CONTENT_DECODING = 0 + 158, +CURLOPT_NEW_FILE_PERMS = 0 + 159, +CURLOPT_NEW_DIRECTORY_PERMS = 0 + 160, +CURLOPT_POSTREDIR = 0 + 161, +CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 = 10000 + 162, +CURLOPT_OPENSOCKETFUNCTION = 20000 + 163, +CURLOPT_OPENSOCKETDATA = 10000 + 164, +CURLOPT_COPYPOSTFIELDS = 10000 + 165, +CURLOPT_PROXY_TRANSFER_MODE = 0 + 166, +CURLOPT_SEEKFUNCTION = 20000 + 167, +CURLOPT_SEEKDATA = 10000 + 168, +CURLOPT_CRLFILE = 10000 + 169, +CURLOPT_ISSUERCERT = 10000 + 170, +CURLOPT_ADDRESS_SCOPE = 0 + 171, +CURLOPT_CERTINFO = 0 + 172, +CURLOPT_USERNAME = 10000 + 173, +CURLOPT_PASSWORD = 10000 + 174, +CURLOPT_PROXYUSERNAME = 10000 + 175, +CURLOPT_PROXYPASSWORD = 10000 + 176, +CURLOPT_NOPROXY = 10000 + 177, +CURLOPT_TFTP_BLKSIZE = 0 + 178, +CURLOPT_SOCKS5_GSSAPI_SERVICE = 10000 + 179, +CURLOPT_SOCKS5_GSSAPI_NEC = 0 + 180, +CURLOPT_PROTOCOLS = 0 + 181, +CURLOPT_REDIR_PROTOCOLS = 0 + 182, +CURLOPT_SSH_KNOWNHOSTS = 10000 + 183, +CURLOPT_SSH_KEYFUNCTION = 20000 + 184, +CURLOPT_SSH_KEYDATA = 10000 + 185, +CURLOPT_MAIL_FROM = 10000 + 186, +CURLOPT_MAIL_RCPT = 10000 + 187, +CURLOPT_FTP_USE_PRET = 0 + 188, +CURLOPT_RTSP_REQUEST = 0 + 189, +CURLOPT_RTSP_SESSION_ID = 10000 + 190, +CURLOPT_RTSP_STREAM_URI = 10000 + 191, +CURLOPT_RTSP_TRANSPORT = 10000 + 192, +CURLOPT_RTSP_CLIENT_CSEQ = 0 + 193, +CURLOPT_RTSP_SERVER_CSEQ = 0 + 194, +CURLOPT_INTERLEAVEDATA = 10000 + 195, +CURLOPT_INTERLEAVEFUNCTION = 20000 + 196, +CURLOPT_WILDCARDMATCH = 0 + 197, +CURLOPT_CHUNK_BGN_FUNCTION = 20000 + 198, +CURLOPT_CHUNK_END_FUNCTION = 20000 + 199, +CURLOPT_FNMATCH_FUNCTION = 20000 + 200, +CURLOPT_CHUNK_DATA = 10000 + 201, +CURLOPT_FNMATCH_DATA = 10000 + 202, +CURLOPT_RESOLVE = 10000 + 203, +CURLOPT_TLSAUTH_USERNAME = 10000 + 204, +CURLOPT_TLSAUTH_PASSWORD = 10000 + 205, +CURLOPT_TLSAUTH_TYPE = 10000 + 206, +CURLOPT_TRANSFER_ENCODING = 0 + 207, +CURLOPT_CLOSESOCKETFUNCTION = 20000 + 208, +CURLOPT_CLOSESOCKETDATA = 10000 + 209, +CURLOPT_GSSAPI_DELEGATION = 0 + 210, +CURLOPT_DNS_SERVERS = 10000 + 211, +CURLOPT_ACCEPTTIMEOUT_MS = 0 + 212, +CURLOPT_TCP_KEEPALIVE = 0 + 213, +CURLOPT_TCP_KEEPIDLE = 0 + 214, +CURLOPT_TCP_KEEPINTVL = 0 + 215, +CURLOPT_SSL_OPTIONS = 0 + 216, +CURLOPT_MAIL_AUTH = 10000 + 217, +CURLOPT_SASL_IR = 0 + 218, +CURLOPT_XFERINFOFUNCTION = 20000 + 219, +CURLOPT_XOAUTH2_BEARER = 10000 + 220, +CURLOPT_DNS_INTERFACE = 10000 + 221, +CURLOPT_DNS_LOCAL_IP4 = 10000 + 222, +CURLOPT_DNS_LOCAL_IP6 = 10000 + 223, +CURLOPT_LOGIN_OPTIONS = 10000 + 224, +CURLOPT_SSL_ENABLE_NPN = 0 + 225, +CURLOPT_SSL_ENABLE_ALPN = 0 + 226, +CURLOPT_EXPECT_100_TIMEOUT_MS = 0 + 227, +CURLOPT_PROXYHEADER = 10000 + 228, +CURLOPT_HEADEROPT = 0 + 229, +CURLOPT_LASTENTRY +} CURLoption; +enum { +CURL_HTTP_VERSION_NONE, +CURL_HTTP_VERSION_1_0, +CURL_HTTP_VERSION_1_1, +CURL_HTTP_VERSION_2_0, +CURL_HTTP_VERSION_LAST +}; +enum { +CURL_RTSPREQ_NONE, +CURL_RTSPREQ_OPTIONS, +CURL_RTSPREQ_DESCRIBE, +CURL_RTSPREQ_ANNOUNCE, +CURL_RTSPREQ_SETUP, +CURL_RTSPREQ_PLAY, +CURL_RTSPREQ_PAUSE, +CURL_RTSPREQ_TEARDOWN, +CURL_RTSPREQ_GET_PARAMETER, +CURL_RTSPREQ_SET_PARAMETER, +CURL_RTSPREQ_RECORD, +CURL_RTSPREQ_RECEIVE, +CURL_RTSPREQ_LAST +}; +enum CURL_NETRC_OPTION { +CURL_NETRC_IGNORED, +CURL_NETRC_OPTIONAL, +CURL_NETRC_REQUIRED, +CURL_NETRC_LAST +}; +enum { +CURL_SSLVERSION_DEFAULT, +CURL_SSLVERSION_TLSv1, +CURL_SSLVERSION_SSLv2, +CURL_SSLVERSION_SSLv3, +CURL_SSLVERSION_TLSv1_0, +CURL_SSLVERSION_TLSv1_1, +CURL_SSLVERSION_TLSv1_2, +CURL_SSLVERSION_LAST +}; +enum CURL_TLSAUTH { +CURL_TLSAUTH_NONE, +CURL_TLSAUTH_SRP, +CURL_TLSAUTH_LAST +}; +typedef enum { +CURL_TIMECOND_NONE, +CURL_TIMECOND_IFMODSINCE, +CURL_TIMECOND_IFUNMODSINCE, +CURL_TIMECOND_LASTMOD, +CURL_TIMECOND_LAST +} curl_TimeCond; + int (curl_strequal)(const char *s1, const char *s2); + int (curl_strnequal)(const char *s1, const char *s2, size_t n); +typedef enum { +CURLFORM_NOTHING, +CURLFORM_COPYNAME, +CURLFORM_PTRNAME, +CURLFORM_NAMELENGTH, +CURLFORM_COPYCONTENTS, +CURLFORM_PTRCONTENTS, +CURLFORM_CONTENTSLENGTH, +CURLFORM_FILECONTENT, +CURLFORM_ARRAY, +CURLFORM_OBSOLETE, +CURLFORM_FILE, +CURLFORM_BUFFER, +CURLFORM_BUFFERPTR, +CURLFORM_BUFFERLENGTH, +CURLFORM_CONTENTTYPE, +CURLFORM_CONTENTHEADER, +CURLFORM_FILENAME, +CURLFORM_END, +CURLFORM_OBSOLETE2, +CURLFORM_STREAM, +CURLFORM_LASTENTRY +} CURLformoption; +struct curl_forms { +CURLformoption option; +const char *value; +}; +typedef enum { +CURL_FORMADD_OK, +CURL_FORMADD_MEMORY, +CURL_FORMADD_OPTION_TWICE, +CURL_FORMADD_NULL, +CURL_FORMADD_UNKNOWN_OPTION, +CURL_FORMADD_INCOMPLETE, +CURL_FORMADD_ILLEGAL_ARRAY, +CURL_FORMADD_DISABLED, +CURL_FORMADD_LAST +} CURLFORMcode; + CURLFORMcode curl_formadd(struct curl_httppost **httppost, +struct curl_httppost **last_post, +...); +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, +size_t len); + int curl_formget(struct curl_httppost *form, void *arg, +curl_formget_callback append); + void curl_formfree(struct curl_httppost *form); + char *curl_getenv(const char *variable); + char *curl_version(void); + char *curl_easy_escape(CURL *handle, +const char *string, +int length); + char *curl_escape(const char *string, +int length); + char *curl_easy_unescape(CURL *handle, +const char *string, +int length, +int *outlength); + char *curl_unescape(const char *string, +int length); + void curl_free(void *p); + CURLcode curl_global_init(long flags); + CURLcode curl_global_init_mem(long flags, +curl_malloc_callback m, +curl_free_callback f, +curl_realloc_callback r, +curl_strdup_callback s, +curl_calloc_callback c); + void curl_global_cleanup(void); +struct curl_slist { +char *data; +struct curl_slist *next; +}; + struct curl_slist *curl_slist_append(struct curl_slist *, +const char *); + void curl_slist_free_all(struct curl_slist *); + time_t curl_getdate(const char *p, const time_t *unused); +struct curl_certinfo { +int num_of_certs; +struct curl_slist **certinfo; +}; +typedef enum { +CURLSSLBACKEND_NONE = 0, +CURLSSLBACKEND_OPENSSL = 1, +CURLSSLBACKEND_GNUTLS = 2, +CURLSSLBACKEND_NSS = 3, +CURLSSLBACKEND_QSOSSL = 4, +CURLSSLBACKEND_GSKIT = 5, +CURLSSLBACKEND_POLARSSL = 6, +CURLSSLBACKEND_CYASSL = 7, +CURLSSLBACKEND_SCHANNEL = 8, +CURLSSLBACKEND_DARWINSSL = 9, +CURLSSLBACKEND_AXTLS = 10 +} curl_sslbackend; +struct curl_tlssessioninfo { +curl_sslbackend backend; +void *internals; +}; +typedef enum { +CURLINFO_NONE, +CURLINFO_EFFECTIVE_URL =1048576 + 1, +CURLINFO_RESPONSE_CODE =2097152 + 2, +CURLINFO_TOTAL_TIME =3145728 + 3, +CURLINFO_NAMELOOKUP_TIME =3145728 + 4, +CURLINFO_CONNECT_TIME =3145728 + 5, +CURLINFO_PRETRANSFER_TIME =3145728 + 6, +CURLINFO_SIZE_UPLOAD =3145728 + 7, +CURLINFO_SIZE_DOWNLOAD =3145728 + 8, +CURLINFO_SPEED_DOWNLOAD =3145728 + 9, +CURLINFO_SPEED_UPLOAD =3145728 + 10, +CURLINFO_HEADER_SIZE =2097152 + 11, +CURLINFO_REQUEST_SIZE =2097152 + 12, +CURLINFO_SSL_VERIFYRESULT =2097152 + 13, +CURLINFO_FILETIME =2097152 + 14, +CURLINFO_CONTENT_LENGTH_DOWNLOAD =3145728 + 15, +CURLINFO_CONTENT_LENGTH_UPLOAD =3145728 + 16, +CURLINFO_STARTTRANSFER_TIME =3145728 + 17, +CURLINFO_CONTENT_TYPE =1048576 + 18, +CURLINFO_REDIRECT_TIME =3145728 + 19, +CURLINFO_REDIRECT_COUNT =2097152 + 20, +CURLINFO_PRIVATE =1048576 + 21, +CURLINFO_HTTP_CONNECTCODE =2097152 + 22, +CURLINFO_HTTPAUTH_AVAIL =2097152 + 23, +CURLINFO_PROXYAUTH_AVAIL =2097152 + 24, +CURLINFO_OS_ERRNO =2097152 + 25, +CURLINFO_NUM_CONNECTS =2097152 + 26, +CURLINFO_SSL_ENGINES =4194304 + 27, +CURLINFO_COOKIELIST =4194304 + 28, +CURLINFO_LASTSOCKET =2097152 + 29, +CURLINFO_FTP_ENTRY_PATH =1048576 + 30, +CURLINFO_REDIRECT_URL =1048576 + 31, +CURLINFO_PRIMARY_IP =1048576 + 32, +CURLINFO_APPCONNECT_TIME =3145728 + 33, +CURLINFO_CERTINFO =4194304 + 34, +CURLINFO_CONDITION_UNMET =2097152 + 35, +CURLINFO_RTSP_SESSION_ID =1048576 + 36, +CURLINFO_RTSP_CLIENT_CSEQ =2097152 + 37, +CURLINFO_RTSP_SERVER_CSEQ =2097152 + 38, +CURLINFO_RTSP_CSEQ_RECV =2097152 + 39, +CURLINFO_PRIMARY_PORT =2097152 + 40, +CURLINFO_LOCAL_IP =1048576 + 41, +CURLINFO_LOCAL_PORT =2097152 + 42, +CURLINFO_TLS_SESSION =4194304 + 43, +CURLINFO_LASTONE = 43 +} CURLINFO; +typedef enum { +CURLCLOSEPOLICY_NONE, +CURLCLOSEPOLICY_OLDEST, +CURLCLOSEPOLICY_LEAST_RECENTLY_USED, +CURLCLOSEPOLICY_LEAST_TRAFFIC, +CURLCLOSEPOLICY_SLOWEST, +CURLCLOSEPOLICY_CALLBACK, +CURLCLOSEPOLICY_LAST +} curl_closepolicy; +typedef enum { +CURL_LOCK_DATA_NONE = 0, +CURL_LOCK_DATA_SHARE, +CURL_LOCK_DATA_COOKIE, +CURL_LOCK_DATA_DNS, +CURL_LOCK_DATA_SSL_SESSION, +CURL_LOCK_DATA_CONNECT, +CURL_LOCK_DATA_LAST +} curl_lock_data; +typedef enum { +CURL_LOCK_ACCESS_NONE = 0, +CURL_LOCK_ACCESS_SHARED = 1, +CURL_LOCK_ACCESS_SINGLE = 2, +CURL_LOCK_ACCESS_LAST +} curl_lock_access; +typedef void (*curl_lock_function)(CURL *handle, +curl_lock_data data, +curl_lock_access locktype, +void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, +curl_lock_data data, +void *userptr); +typedef void CURLSH; +typedef enum { +CURLSHE_OK, +CURLSHE_BAD_OPTION, +CURLSHE_IN_USE, +CURLSHE_INVALID, +CURLSHE_NOMEM, +CURLSHE_NOT_BUILT_IN, +CURLSHE_LAST +} CURLSHcode; +typedef enum { +CURLSHOPT_NONE, +CURLSHOPT_SHARE, +CURLSHOPT_UNSHARE, +CURLSHOPT_LOCKFUNC, +CURLSHOPT_UNLOCKFUNC, +CURLSHOPT_USERDATA, +CURLSHOPT_LAST +} CURLSHoption; + CURLSH *curl_share_init(void); + CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); + CURLSHcode curl_share_cleanup(CURLSH *); +typedef enum { +CURLVERSION_FIRST, +CURLVERSION_SECOND, +CURLVERSION_THIRD, +CURLVERSION_FOURTH, +CURLVERSION_LAST +} CURLversion; +typedef struct { +CURLversion age; +const char *version; +unsigned int version_num; +const char *host; +int features; +const char *ssl_version; +long ssl_version_num; +const char *libz_version; +const char * const *protocols; +const char *ares; +int ares_num; +const char *libidn; +int iconv_ver_num; +const char *libssh_version; +} curl_version_info_data; + curl_version_info_data *curl_version_info(CURLversion); + const char *curl_easy_strerror(CURLcode); + const char *curl_share_strerror(CURLSHcode); + CURLcode curl_easy_pause(CURL *handle, int bitmask); + CURL *curl_easy_init(void); + CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); + CURLcode curl_easy_perform(CURL *curl); + void curl_easy_cleanup(CURL *curl); + CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + CURL* curl_easy_duphandle(CURL *curl); + void curl_easy_reset(CURL *curl); + CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, +size_t *n); + CURLcode curl_easy_send(CURL *curl, const void *buffer, +size_t buflen, size_t *n); +typedef void CURLM; +typedef enum { +CURLM_CALL_MULTI_PERFORM = -1, +CURLM_OK, +CURLM_BAD_HANDLE, +CURLM_BAD_EASY_HANDLE, +CURLM_OUT_OF_MEMORY, +CURLM_INTERNAL_ERROR, +CURLM_BAD_SOCKET, +CURLM_UNKNOWN_OPTION, +CURLM_ADDED_ALREADY, +CURLM_LAST +} CURLMcode; +typedef enum { +CURLMSG_NONE, +CURLMSG_DONE, +CURLMSG_LAST +} CURLMSG; +struct CURLMsg { +CURLMSG msg; +CURL *easy_handle; +union { +void *whatever; +CURLcode result; +} data; +}; +typedef struct CURLMsg CURLMsg; +struct curl_waitfd { +curl_socket_t fd; +short events; +short revents; +}; +typedef struct fd_set { + unsigned int fd_count; /* how many are SET? */ + curl_socket_t fd_array[64]; //FD_SETSIZE, 64 on my machine, TOFIX +} fd_set; + CURLM *curl_multi_init(void); + CURLMcode curl_multi_add_handle(CURLM *multi_handle, +CURL *curl_handle); + CURLMcode curl_multi_remove_handle(CURLM *multi_handle, +CURL *curl_handle); + CURLMcode curl_multi_fdset(CURLM *multi_handle, +fd_set *read_fd_set, +fd_set *write_fd_set, +fd_set *exc_fd_set, +int *max_fd); + CURLMcode curl_multi_wait(CURLM *multi_handle, +struct curl_waitfd extra_fds[], +unsigned int extra_nfds, +int timeout_ms, +int *ret); + CURLMcode curl_multi_perform(CURLM *multi_handle, +int *running_handles); + CURLMcode curl_multi_cleanup(CURLM *multi_handle); + CURLMsg *curl_multi_info_read(CURLM *multi_handle, +int *msgs_in_queue); + const char *curl_multi_strerror(CURLMcode); +typedef int (*curl_socket_callback)(CURL *easy, +curl_socket_t s, +int what, +void *userp, +void *socketp); +typedef int (*curl_multi_timer_callback)(CURLM *multi, +long timeout_ms, +void *userp); + CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, +int *running_handles); + CURLMcode curl_multi_socket_action(CURLM *multi_handle, +curl_socket_t s, +int ev_bitmask, +int *running_handles); + CURLMcode curl_multi_socket_all(CURLM *multi_handle, +int *running_handles); + CURLMcode curl_multi_timeout(CURLM *multi_handle, +long *milliseconds); +typedef enum { +CURLMOPT_SOCKETFUNCTION = 20000 + 1, +CURLMOPT_SOCKETDATA = 10000 + 2, +CURLMOPT_PIPELINING = 0 + 3, +CURLMOPT_TIMERFUNCTION = 20000 + 4, +CURLMOPT_TIMERDATA = 10000 + 5, +CURLMOPT_MAXCONNECTS = 0 + 6, +CURLMOPT_MAX_HOST_CONNECTIONS = 0 + 7, +CURLMOPT_MAX_PIPELINE_LENGTH = 0 + 8, +CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE = 30000 + 9, +CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE = 30000 + 10, +CURLMOPT_PIPELINING_SITE_BL = 10000 + 11, +CURLMOPT_PIPELINING_SERVER_BL = 10000 + 12, +CURLMOPT_MAX_TOTAL_CONNECTIONS = 0 + 13, +CURLMOPT_LASTENTRY +} CURLMoption; + CURLMcode curl_multi_setopt(CURLM *multi_handle, +CURLMoption option, ...); + CURLMcode curl_multi_assign(CURLM *multi_handle, +curl_socket_t sockfd, void *sockp); +]]) + +return curl \ No newline at end of file diff --git a/main.lua b/main.lua new file mode 100644 index 0000000..06e0bf4 --- /dev/null +++ b/main.lua @@ -0,0 +1,16 @@ +print("running!") +require("Library") +local bin = require("bin") +local multi,thread = require("multi"):init() +GLOBAL, THREAD = require("multi.integration.loveManager").init() +require("GuiManager") +require("manga") + +local app = gui:newFullFrame("App") +require("app").init(app) + +-- Main Driver +multi.OnError(function(...) + print(...) +end) +multi:loveloop() diff --git a/manga/init.lua b/manga/init.lua new file mode 100644 index 0000000..3666fdc --- /dev/null +++ b/manga/init.lua @@ -0,0 +1,90 @@ +multi,thread = require("multi"):init() +THREAD = multi.integration.THREAD +local m = {} +m.azlist = {} +m.init = THREAD:newFunction(function() + local http = require("socket.http") + local list = http.request("http://www.mangareader.net/alphabetical") + return list +end,true) +-- return title +function m.getList() + return m.azlist +end +function m.storeList(list) + local go = false + local titles = {} + for link,title in list:gmatch("
  • ([^<]+)[^>]+>
  • ") do + if go and link~="/" and link~="/privacy" then + table.insert(titles,{Title = title,Link = "http://www.mangareader.net"..link}) + end + if title=="Z" then + go = true + end + end + m.azlist = titles +end +-- returns manga +m.getManga = function(title) + local http = require("socket.http") + local manga = http.request(title.Link) + local tab = {} + tab.Cover = manga:match([[
    %s*([^<]*)]]) + tab.AltTitle = manga:match([[Alternate Name:.-([^<]*)]]) + tab.Status = manga:match([[Status:.-([^<]*)]]) + tab.Author = manga:match([[Author:.-([^<]*)]]) + tab.Artist = manga:match([[Artist:.-([^<]*)]]) + tab.ReadingDir = manga:match([[Reading Direction:.-([^<]*)]]) + local data = manga:match([[readmangasum(.*)]]) + tab.Desc = manga:match([[

    (.-)

    ]]) + tab.Chapters = {} + for link,chapter in data:gmatch([[
    ([^<]+)]]) do + if link~="/" and link~="/privacy" then + table.insert(tab.Chapters,{Link = "http://www.mangareader.net"..link,Lead = chapter}) + end + end + return tab +end +local queue = multi:newSystemThreadedJobQueue(16) +queue:doToAll(function() + multi,thread = require("multi"):init() + http = require("socket.http") -- This is important +end) +queue:registerFunction("getImage",function(pageurl) + local page = http.request(pageurl) + return page:match([[id="imgholder.-src="([^"]*)]]) +end) +queue:registerFunction("getPages",function(manga,chapter) + local tab = {} + local page = http.request(manga.Chapters[chapter].Link) + tab.pages = {page:match([[id="imgholder.-src="([^"]*)]])} + tab.nextChapter = "http://www.mangareader.net"..page:match([[Next Chapter:.-href="([^"]*)]]) + for link,page in page:gmatch([[]]) do + table.insert(tab.pages,getImage("http://www.mangareader.net"..link)) + end + return tab +end) +-- returns pages +m.getPages = function(manga,chapter) + local http = require("socket.http") + local tab = {} + local cc = 0 + local page = http.request(manga.Chapters[chapter].Link) + tab.pages = {page:match([[id="imgholder.-src="([^"]*)]])} + tab.nextChapter = "http://www.mangareader.net"..page:match([[Next Chapter:.-href="([^"]*)]]) + local conn = queue.OnJobCompleted(function(jid,link) + table.insert(tab.pages,link) + cc=cc+1 + end) + local count = 0 + for link,page in page:gmatch([[]]) do + queue:pushJob("getImage","http://www.mangareader.net"..link) + count = count + 1 + end + thread.hold(function() + return count==#tab.pages + end) + return tab +end +return m \ No newline at end of file diff --git a/multi/compat/love2d.lua b/multi/compat/love2d.lua new file mode 100644 index 0000000..62cfc86 --- /dev/null +++ b/multi/compat/love2d.lua @@ -0,0 +1,90 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +local multi, thread = require("multi").init() +os.sleep = love.timer.sleep +multi.drawF = {} +function multi:onDraw(func, i) + i = i or 1 + table.insert(self.drawF, i, func) +end +multi.OnKeyPressed = multi:newConnection() +multi.OnKeyReleased = multi:newConnection() +multi.OnMousePressed = multi:newConnection() +multi.OnMouseReleased = multi:newConnection() +multi.OnMouseWheelMoved = multi:newConnection() +multi.OnMouseMoved = multi:newConnection() +multi.OnDraw = multi:newConnection() +multi.OnTextInput = multi:newConnection() +multi.OnUpdate = multi:newConnection() +multi.OnQuit = multi:newConnection() +multi.OnPreLoad(function() + local function Hook(func, conn) + if love[func] ~= nil then + love[func] = Library.convert(love[func]) + love[func]:inject(function(...) + conn:Fire(...) + return {...} + end,1) + elseif love[func] == nil then + love[func] = function(...) + conn:Fire(...) + end + end + end + Hook("quit", multi.OnQuit) + Hook("keypressed", multi.OnKeyPressed) + Hook("keyreleased", multi.OnKeyReleased) + Hook("mousepressed", multi.OnMousePressed) + Hook("mousereleased", multi.OnMouseReleased) + Hook("wheelmoved", multi.OnMouseWheelMoved) + Hook("mousemoved", multi.OnMouseMoved) + Hook("draw", multi.OnDraw) + Hook("textinput", multi.OnTextInput) + Hook("update", multi.OnUpdate) + multi.OnDraw(function() + for i = 1, #multi.drawF do + love.graphics.setColor(255, 255, 255, 255) + multi.drawF[i]() + end + end) +end) + +function multi:loveloop() + local link + link = multi:newThread(function() + local mainloop = love.run() + while true do + thread.yield() + pcall(mainloop) + end + end).OnError(function(...) + print(...) + end) + multi:mainloop() +end +multi.OnQuit(function() + multi.Stop() + love.event.quit() +end) +return multi diff --git a/multi/init.lua b/multi/init.lua new file mode 100644 index 0000000..b53af81 --- /dev/null +++ b/multi/init.lua @@ -0,0 +1,2603 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +local bin = pcall(require,"bin") +local multi = {} +local clock = os.clock +local thread = {} +if not _G["$multi"] then + _G["$multi"] = {multi=multi,thread=thread} +end +multi.Version = "14.0.0" +multi._VERSION = "14.0.0" +multi.stage = "stable" +multi.__index = multi +multi.Name = "multi.root" +multi.Mainloop = {} +multi.Garbage = {} +multi.ender = {} +multi.Children = {} +multi.Active = true +multi.fps = 60 +multi.Type = "mainprocess" +multi.Rest = 0 +multi._type = type +multi.Jobs = {} +multi.queue = {} +multi.jobUS = 2 +multi.clock = os.clock +multi.time = os.time +multi.LinkedPath = multi +multi.lastTime = clock() +math.randomseed(os.time()) +local mainloopActive = false +local isRunning = false +local next +local ncount = 0 +multi.defaultSettings = { + priority = 0, + protect = false, +} +--Do not change these ever...Any other number will not work (Unless you are using enablePriority2()) +multi.Priority_Core = 1 +multi.Priority_High = 4 +multi.Priority_Above_Normal = 16 +multi.Priority_Normal = 64 +multi.Priority_Below_Normal = 256 +multi.Priority_Low = 1024 +multi.Priority_Idle = 4096 +thread.Priority_Core = 3 +thread.Priority_High = 2 +thread.Priority_Above_Normal = 1 +thread.Priority_Normal = 0 +thread.Priority_Below_Normal = -1 +thread.Priority_Low = -2 +thread.Priority_Idle = -3 +multi.PriorityResolve = { + [1]="Core", + [4]="High", + [16]="Above Normal", + [64]="Normal", + [256]="Below Normal", + [1024]="Low", + [4096]="Idle", +} +multi.PStep = 1 +multi.PList = {multi.Priority_Core,multi.Priority_High,multi.Priority_Above_Normal,multi.Priority_Normal,multi.Priority_Below_Normal,multi.Priority_Low,multi.Priority_Idle} +--^^^^ +multi.PriorityTick=1 -- Between 1, 2 and 4 +multi.Priority=multi.Priority_High +multi.threshold=256 +multi.threstimed=.001 +function multi.init() + multi.NIL = {Type="NIL"} + return _G["$multi"].multi,_G["$multi"].thread +end +function multi.queuefinal(self) + self:Destroy() + if self.Parent.Mainloop[#self.Parent.Mainloop] then + if self.Parent.Mainloop[#self.Parent.Mainloop].Type=="alarm" then + self.Parent.Mainloop[#self.Parent.Mainloop]:Reset() + self.Parent.Mainloop[#self.Parent.Mainloop].Active=true + else + self.Parent.Mainloop[#self.Parent.Mainloop]:Resume() + end + else + for i=1,#self.Parent.funcE do + self.Parent.funcE[i](self) + end + self.Parent:Remove() + end +end +if table.unpack and not unpack then + unpack=table.unpack +end +function table.merge(t1, t2) + for k,v in pairs(t2) do + if type(v) == 'table' then + if type(t1[k] or false) == 'table' then + table.merge(t1[k] or {}, t2[k] or {}) + else + t1[k] = v + end + else + t1[k] = v + end + end + return t1 +end +function multi:setThrestimed(n) + self.deltaTarget=n or .1 +end +function multi:enableLoadDetection() + if multi.maxSpd then return end + -- here we are going to run a quick benchMark solo + local temp = multi:newProcessor() + temp:Start() + local t = os.clock() + local stop = false + temp:benchMark(.01):OnBench(function(time,steps) + stop = steps + end) + while not stop do + temp:uManager() + end + temp:Destroy() + multi.maxSpd = stop +end +local MaxLoad = nil +function multi:setLoad(n) + MaxLoad = n +end +local busy = false +local lastVal = 0 +local bb = 0 +function multi:getLoad() + if not multi.maxSpd then multi:enableLoadDetection() end + if busy then return lastVal end + local val = nil + if thread.isThread() then + local bench + multi:benchMark(.01):OnBench(function(time,steps) + bench = steps + bb = steps + end) + thread.hold(function() + return bench + end) + bench = bench^1.5 + val = math.ceil((1-(bench/(multi.maxSpd/2.2)))*100) + else + busy = true + local bench + multi:benchMark(.01):OnBench(function(time,steps) + bench = steps + bb = steps + end) + while not bench do + multi:uManager() + end + bench = bench^1.5 + val = math.ceil((1-(bench/(multi.maxSpd/2.2)))*100) + busy = false + end + if val<0 then val = 0 end + if val > 100 then val = 100 end + lastVal = val + return val,bb*100 +end +function multi:setDomainName(name) + self[name]={} +end +function multi:linkDomain(name) + return self[name] +end +function multi:_Pause() + self.Active=false +end +function multi:setPriority(s) + if type(s)==number then + self.Priority=s + elseif type(s)=='string' then + if s:lower()=='core' or s:lower()=='c' then + self.Priority=self.Priority_Core + elseif s:lower()=='high' or s:lower()=='h' then + self.Priority=self.Priority_High + elseif s:lower()=='above' or s:lower()=='a' then + self.Priority=self.Priority_Above_Normal + elseif s:lower()=='normal' or s:lower()=='n' then + self.Priority=self.Priority_Normal + elseif s:lower()=='below' or s:lower()=='b' then + self.Priority=self.Priority_Below_Normal + elseif s:lower()=='low' or s:lower()=='l' then + self.Priority=self.Priority_Low + elseif s:lower()=='idle' or s:lower()=='i' then + self.Priority=self.Priority_Idle + end + self.solid = true + end + if not self.PrioritySet then + self.defPriority = self.Priority + self.PrioritySet = true + end +end +function multi:ResetPriority() + self.Priority = self.defPriority +end +-- System +function os.getOS() + if package.config:sub(1,1)=='\\' then + return 'windows' + else + return 'unix' + end +end +if os.getOS()=='windows' then + function os.sleep(n) + if n > 0 then os.execute('ping -n ' .. tonumber(n+1) .. ' localhost > NUL') end + end +else + function os.sleep(n) + os.execute('sleep ' .. tonumber(n)) + end +end +function multi.randomString(n) + local str = '' + local strings = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','1','2','3','4','5','6','7','8','9','0','A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'} + for i=1,n do + str = str..''..strings[math.random(1,#strings)] + end + return str +end +function multi:getParentProcess() + return self.Mainloop[self.CID] +end +multi.GetParentProcess=multi.getParentProcess +function multi.Stop() + mainloopActive=false +end +function multi:isHeld() + return self.held +end +multi.important={} +multi.IsHeld=multi.isHeld +function multi.executeFunction(name,...) + if type(_G[name])=='function' then + _G[name](...) + else + multi.print('Error: Not a function') + end +end +function multi:getChildren() + return self.Mainloop +end +function multi:getVersion() + return multi.Version +end +function multi:getPlatform() + if love then + if love.thread then + return "love2d" + end + else + return "lanes" + end +end +function multi:canSystemThread() + return false +end +--Processor +function multi:getError() + if self.error then + return self.error + end +end +function multi:benchMark(sec,p,pt) + local c = 0 + local temp=self:newLoop(function(self,t) + if t>sec then + if pt then + multi.print(pt.." "..c.." Steps in "..sec.." second(s)!") + end + self.tt(sec,c) + self:Destroy() + else + c=c+1 + end + end) + temp:setPriority(p or 1) + function temp:OnBench(func) + self.tt=func + end + self.tt=function() end + return temp +end +function multi.Round(num, numDecimalPlaces) + local mult = 10^(numDecimalPlaces or 0) + return math.floor(num * mult + 0.5) / mult +end +function multi.AlignTable(tab) + local longest = {} + local columns = #tab[1] + local rows = #tab + for i=1, columns do + longest[i] = -math.huge + end + for i = 1,rows do + for j = 1,columns do + tab[i][j] = tostring(tab[i][j]) + if #tab[i][j]>longest[j] then + longest[j] = #tab[i][j] + end + end + end + for i = 1,rows do + for j = 1,columns do + if tab[i][j]~=nil and #tab[i][j]","Uptime","Priority","TID"} + } + local count = 0 + for i,v in pairs(self.Mainloop) do + local name = v.Name or "" + if name~="" then + name = " <"..name..">" + end + count = count + 1 + table.insert(str,{v.Type:sub(1,1):upper()..v.Type:sub(2,-1)..name,multi.Round(os.clock()-v.creationTime,3),self.PriorityResolve[v.Priority],v.TID}) + end + for v,i in pairs(multi.PausedObjects) do + local name = v.Name or "" + if name~="" then + name = " <"..name..">" + end + count = count + 1 + table.insert(str,{v.Type:sub(1,1):upper()..v.Type:sub(2,-1)..name,multi.Round(os.clock()-v.creationTime,3),self.PriorityResolve[v.Priority],v.TID}) + end + if count == 0 then + table.insert(str,{"Currently no processes running!","","",""}) + end + local s = multi.AlignTable(str) + dat = "" + dat2 = "" + if multi.SystemThreads then + for i = 1,#multi.SystemThreads do + dat2 = dat2.."\n" + end + end + local load, steps = multi:getLoad() + if thread.__threads then + for i=1,#thread.__threads do + dat = dat .. "\n" + end + return "Load on "..ProcessName[self.Type=="process"].."<"..(self.Name or "Unnamed")..">"..": "..multi.Round(load,2).."%\nCycles Per Second Per Task: "..steps.."\nMemory Usage: "..math.ceil(collectgarbage("count")).." KB\nThreads Running: "..#thread.__threads.."\nSystemThreads Running: "..#(multi.SystemThreads or {}).."\nPriority Scheme: "..priorityTable[multi.defaultSettings.priority or 0].."\n\n"..s.."\n\n"..dat..dat2 + else + return "Load on "..ProcessName[self.Type=="process"].."<"..(self.Name or "Unnamed")..">"..": "..multi.Round(load,2).."%\nCycles Per Second Per Task: "..steps.."\n\nMemory Usage: "..math.ceil(collectgarbage("count")).." KB\nThreads Running: 0\nPriority Scheme: "..priorityTable[multi.defaultSettings.priority or 0].."\n\n"..s..dat2 + end + elseif t == "t" or t == "table" then + local load,steps = multi:getLoad() + str = { + ProcessName = (self.Name or "Unnamed"), + ThreadCount = #thread.__threads, + MemoryUsage = math.ceil(collectgarbage("count")), + PriorityScheme = priorityTable[multi.defaultSettings.priority or 0], + SystemLoad = multi.Round(load,2), + CyclesPerSecondPerTask = steps, + SystemThreadCount = multi.SystemThreads and #multi.SystemThreads or 0 + } + str.Tasks = {} + str.PausedTasks = {} + str.Threads = {} + str.Systemthreads = {} + for i,v in pairs(self.Mainloop) do + table.insert(str.Tasks,{Link = v, Type=v.Type,Name=v.Name,Uptime=os.clock()-v.creationTime,Priority=self.PriorityResolve[v.Priority],TID = v.TID}) + end + for v,i in pairs(multi.PausedObjects) do + table.insert(str.Tasks,{Link = v, Type=v.Type,Name=v.Name,Uptime=os.clock()-v.creationTime,Priority=self.PriorityResolve[v.Priority],TID = v.TID}) + end + for i=1,#thread.__threads do + table.insert(str.Threads,{Uptime = os.clock()-thread.__threads[i].creationTime,Name = thread.__threads[i].Name,Link = thread.__threads[i],TID = thread.__threads[i].TID}) + end + if multi.SystemThreads then + for i=1,#multi.SystemThreads do + table.insert(str.Systemthreads,{Uptime = os.clock()-multi.SystemThreads[i].creationTime,Name = multi.SystemThreads[i].Name,Link = multi.SystemThreads[i],TID = multi.SystemThreads[i].count}) + end + end + return str + end +end +function multi:endTask(TID) + self.Mainloop[TID]:Destroy() +end +function multi.startFPSMonitior() + if not multi.runFPS then + multi.doFPS(s) + multi.runFPS=true + end +end +function multi.doFPS(s) + multi:benchMark(1):OnBench(doFPS) + if s then + multi.fps=s + end +end +--Helpers +function multi.timer(func,...) + local timer=multi:newTimer() + timer:Start() + args={func(...)} + local t = timer:Get() + timer = nil + return t,unpack(args) +end +function multi:IsAnActor() + return self.Act~=nil +end +function multi:OnMainConnect(func) + table.insert(self.func,func) + return self +end +function multi:reallocate(o,n) + n=n or #o.Mainloop+1 + local int=self.Parent + self:Destroy() + self.Parent=o + table.insert(o.Mainloop,n,self) + self.Active=true +end +multi.Reallocate=multi.Reallocate +function multi:setJobSpeed(n) + self.jobUS=n +end +function multi:hasJobs() + return #self.Jobs>0,#self.Jobs +end +function multi:getJobs() + return #self.Jobs +end +function multi:removeJob(name) + local count = 0 + for i=#self.Jobs,1,-1 do + if self.Jobs[i][2]==name then + table.remove(self.Jobs,i) + count = count + 1 + end + end + return count +end +function multi:FreeMainEvent() + self.func={} +end +function multi:connectFinal(func) + if self.Type=='event' then + self:OnEvent(func) + elseif self.Type=='alarm' then + self:OnRing(func) + elseif self.Type=='step' or self.Type=='tstep' then + self:OnEnd(func) + else + multi.print("Warning!!! "..self.Type.." doesn't contain a Final Connection State! Use "..self.Type..":Break(func) to trigger it's final event!") + self:OnBreak(func) + end +end +multi.ConnectFinal=multi.connectFinal +function multi:Break() + self:Pause() + self.Active=nil + for i=1,#self.ender do + if self.ender[i] then + self.ender[i](self) + end + end +end +function multi:OnBreak(func) + table.insert(self.ender,func) +end +function multi:isPaused() + return not(self.Active) +end +multi.IsPaused=multi.isPaused +function multi:isActive() + return self.Active +end +multi.IsActive=multi.isActive +function multi:getType() + return self.Type +end +multi.GetType=multi.getType +-- Advance Timer stuff +function multi:SetTime(n) + if not n then n=3 end + local c=multi:newBase() + c.Type='timemaster' + c.timer=multi:newTimer() + c.timer:Start() + c.set=n + c.link=self + self._timer=c.timer + function c:Act() + if self.timer:Get()>=self.set then + self.link:Pause() + for i=1,#self.link.funcTM do + self.link.funcTM[i](self.link) + end + self:Destroy() + end + end + return self +end +multi.ResetTime=multi.SetTime +function multi:ResolveTimer(...) + self._timer:Pause() + for i=1,#self.funcTMR do + self.funcTMR[i](self,...) + end + self:Pause() + return self +end +function multi:OnTimedOut(func) + self.funcTM[#self.funcTM+1]=func + return self +end +function multi:OnTimerResolved(func) + self.funcTMR[#self.funcTMR+1]=func + return self +end +-- Timer stuff done +multi.PausedObjects = {} +function multi:Pause() + if self.Type=='mainprocess' then + multi.print("You cannot pause the main process. Doing so will stop all methods and freeze your program! However if you still want to use multi:_Pause()") + else + self.Active=false + local loop = self.Parent.Mainloop + for i=1,#loop do + if loop[i] == self then + multi.PausedObjects[self] = true + table.remove(loop,i) + break + end + end + end + return self +end +function multi:Resume() + if self.Type=='process' or self.Type=='mainprocess' then + self.Active=true + local c=self:getChildren() + for i=1,#c do + c[i]:Resume() + end + else + if self.Active==false then + table.insert(self.Parent.Mainloop,self) + multi.PausedObjects[self] = nil + self.Active=true + end + end + return self +end +function multi:Destroy() + if self.Type=='process' or self.Type=='mainprocess' then + local c=self:getChildren() + for i=1,#c do + self.OnObjectDestroyed:Fire(c[i]) + c[i]:Destroy() + end + else + for i=1,#self.Parent.Mainloop do + if self.Parent.Mainloop[i]==self then + self.Parent.OnObjectDestroyed:Fire(self) + table.remove(self.Parent.Mainloop,i) + self.Destroyed = true + break + end + end + self.Active=false + end + return self +end +function multi:Reset(n) + self:Resume() + return self +end +function multi:isDone() + return self.Active~=true +end +multi.IsDone=multi.isDone +function multi:create(ref) + multi.OnObjectCreated:Fire(ref,self) +end +function multi:setName(name) + self.Name = name + return self +end +multi.SetName = multi.setName +--Constructors [CORE] +local _tid = 0 +function multi:newBase(ins) + if not(self.Type=='mainprocess' or self.Type=='process' or self.Type=='queue') then error('Can only create an object on multi or an interface obj') return false end + local c = {} + if self.Type=='process' or self.Type=='queue' then + setmetatable(c, self.Parent) + else + setmetatable(c, self) + end + c.Active=true + c.func={} + c.funcTM={} + c.funcTMR={} + c.ender={} + c.TID = _tid + c.important={} + c.Act=function() end + c.Parent=self + c.held=false + c.creationTime = os.clock() + if ins then + table.insert(self.Mainloop,ins,c) + else + table.insert(self.Mainloop,c) + end + _tid = _tid + 1 + return c +end +function multi:newProcessor(file) + if not(self.Type=='mainprocess') then error('Can only create an interface on the multi obj') return false end + local c = {} + setmetatable(c, self) + c.Parent=self + c.Active=true + c.func={} + c.Type='process' + c.Mainloop={} + c.Garbage={} + c.Children={} + c.Active=false + c.Rest=0 + c.Jobs={} + c.queue={} + c.jobUS=2 + c.l=self:newLoop(function(self,dt) + if self.link.Active then + c:uManager() + end + end) + c.l.link = c + c.l.Type = "processor" + function c:getController() + return c.l + end + function c:Start() + self.Active = true + return self + end + function c:Resume() + self.Active = false + return self + end + function c:setName(name) + c.l.Name = name + return self + end + function c:Pause() + if self.l then + self.l:Pause() + end + return self + end + function c:Remove() + if self.Type == "process" then + self:__Destroy() + self.l:Destroy() + else + self:__Destroy() + end + end + function c:Destroy() + if self == c then + self.l:Destroy() + else + for i = #c.Mainloop,1,-1 do + if c.Mainloop[i] == self then + table.remove(c.Mainloop,i) + break + end + end + end + end + if file then + self.Cself=c + loadstring('local process=multi.Cself '..io.open(file,'rb'):read('*all'))() + end + -- c.__Destroy = self.Destroy + -- c.Destroy = c.Remove + self:create(c) +--~ c:IngoreObject() + return c +end +function multi:newTimer() + local c={} + c.Type='timer' + local time=0 + local count=0 + local paused=false + function c:Start() + time=os.clock() + return self + end + function c:Get() + if self:isPaused() then return time end + return (clock()-time)+count + end + function c:isPaused() + return paused + end + c.Reset=c.Start + function c:Pause() + time=self:Get() + paused=true + return self + end + function c:Resume() + paused=false + time=os.clock()-time + return self + end + function c:tofile(path) + local m=bin.new() + count=count+self:Get() + m:addBlock(self.Type) + m:addBlock(count) + m:tofile(path) + return self + end + self:create(c) + return c +end +function multi:newConnector() + local c = {Type = "connector"} + return c +end +local CRef = { + Fire = function() end +} +function multi:newConnection(protect,func,kill) + local c={} + c.callback = func + c.Parent=self + c.lock = false + setmetatable(c,{__call=function(self,...) + local t = ... + if type(t)=="table" and t.Type ~= nil then + return self:Fire(args,select(2,...)) + else + return self:connect(...) + end + end}) + c.Type='connector' + c.func={} + c.ID=0 + c.protect=protect or true + c.connections={} + c.fconnections={} + c.FC=0 + function c:holdUT(n) + local n=n or 0 + self.waiting=true + local count=0 + local id=self:connect(function() + count = count + 1 + if n<=count then + self.waiting=false + end + end) + repeat + self.Parent:uManager(multi.defaultSettings) + until self.waiting==false + id:Destroy() + return self + end + c.HoldUT=c.holdUT + function c:fConnect(func) + local temp=self:connect(func) + table.insert(self.fconnections,temp) + self.FC=self.FC+1 + return self + end + c.FConnect=c.fConnect + function c:getConnection(name,ignore) + if ignore then + return self.connections[name] or CRef + else + return self.connections[name] or self + end + end + function c:Lock() + c.lock = true + end + function c:Unlock() + c.lock = false + end + function c:Fire(...) + local ret={} + if self.lock then return end + for i=#self.func,1,-1 do + if self.protect then + if not self.func[i] then return end + local temp={pcall(self.func[i][1],...)} + if temp[1] then + table.remove(temp,1) + table.insert(ret,temp) + else + multi.print(temp[2]) + end + else + if not self.func[i] then return end + table.insert(ret,{self.func[i][1](...)}) + end + if kill then + table.remove(self.func,i) + end + end + return ret + end + function c:Bind(t) + self.func=t + return self + end + function c:Remove() + self.func={} + return self + end + local function conn_helper(self,func,name,num) + self.ID=self.ID+1 + if num then + table.insert(self.func,num,{func,self.ID}) + else + table.insert(self.func,1,{func,self.ID}) + end + local temp = { + Link=self.func, + func=func, + ID=self.ID, + Parent=self, + Fire=function(self,...) + if self.Parent.lock then return end + if self.Parent.protect then + local t=pcall(self.func,...) + if t then + return t + end + else + return self.func(...) + end + end, + Remove=function(self) + for i=1,#self.Link do + if self.Link[i][2]~=nil then + if self.Link[i][2]==self.ID then + table.remove(self.Link,i) + self.remove=function() end + self.Link=nil + self.ID=nil + return true + end + end + end + end, + } + temp.Destroy=temp.Remove + if name then + self.connections[name]=temp + end + if self.callback then + self.callback(temp) + end + return temp + end + function c:connect(...)--func,name,num + local tab = {...} + local funcs={} + for i=1,#tab do + if type(tab[i])=="function" then + funcs[#funcs+1] = tab[i] + end + end + if #funcs>1 then + local ret = {} + for i=1,#funcs do + table.insert(ret,conn_helper(self,funcs[i])) + end + return ret + else + conn_helper(self,tab[1],tab[2],tab[3]) + end + end + c.Connect=c.connect + c.GetConnection=c.getConnection + function c:tofile(path) + local m=bin.new() + m:addBlock(self.Type) + m:addBlock(self.func) + m:tofile(path) + return self + end + return c +end +multi.OnObjectCreated=multi:newConnection() +multi.OnObjectDestroyed=multi:newConnection() +function multi:newJob(func,name) + if not(self.Type=='mainprocess' or self.Type=='process') then error('Can only create an object on multi or an interface obj') return false end + local c = {} + if self.Type=='process' then + setmetatable(c, self.Parent) + else + setmetatable(c, self) + end + c.Active=true + c.func={} + c.Parent=self + c.Type='job' + c.trigfunc=func or function() end + function c:Act() + self:trigfunc(self) + end + table.insert(self.Jobs,{c,name}) + if self.JobRunner==nil then + self.JobRunner=self:newAlarm(self.jobUS):setName("multi.jobHandler") + self.JobRunner:OnRing(function(self) + if #self.Parent.Jobs>0 then + if self.Parent.Jobs[1] then + self.Parent.Jobs[1][1]:Act() + table.remove(self.Parent.Jobs,1) + end + end + self:Reset(self.Parent.jobUS) + end) + end +end +function multi.nextStep(func) + ncount = ncount+1 + if not next then + next = {func} + else + next[#next+1] = func + end +end +--Core Actors +function multi:newEvent(task) + local c=self:newBase() + c.Type='event' + c.Task=task or function() end + function c:Act() + local t = {self.Task(self)} + if t[1] then + self:Pause() + self.returns = t + for _E=1,#self.func do + self.func[_E](self) + end + end + end + function c:SetTask(func) + self.Task=func + return self + end + function c:OnEvent(func) + table.insert(self.func,func) + return self + end + self:setPriority("core") + self:create(c) + return c +end +function multi:newUpdater(skip) + local c=self:newBase() + c.Type='updater' + c.pos=1 + c.skip=skip or 1 + function c:Act() + if self.pos>=self.skip then + self.pos=0 + for i=1,#self.func do + self.func[i](self) + end + end + self.pos=self.pos+1 + end + function c:SetSkip(n) + self.skip=n + return self + end + c.OnUpdate=self.OnMainConnect + self:create(c) + return c +end +function multi:newAlarm(set) + local c=self:newBase() + c.Type='alarm' + c:setPriority("Low") + c.set=set or 0 + local count = 0 + local t = clock() + function c:Act() + if clock()-t>=self.set then + self:Pause() + self.Active=false + for i=1,#self.func do + self.func[i](self) + end + t = clock() + end + end + function c:Resume() + self.Parent.Resume(self) + t = count + t + return self + end + function c:Reset(n) + if n then self.set=n end + self:Resume() + t = clock() + return self + end + function c:OnRing(func) + table.insert(self.func,func) + return self + end + function c:Pause() + count = clock() + self.Parent.Pause(self) + return self + end + self:create(c) + return c +end +function multi:newLoop(func) + local c=self:newBase() + c.Type='loop' + local start=self.clock() + local funcs = {} + if func then + funcs={func} + end + function c:Act() + for i=1,#funcs do + funcs[i](self,clock()-start) + end + end + function c:OnLoop(func) + table.insert(funcs,func) + return self + end + self:create(c) + return c +end +function multi:newFunction(func) + local c={} + c.func=func + mt={ + __index=multi, + __call=function(self,...) + if self.Active then + return self:func(...) + end + return nil,true + end + } + c.Parent=self + function c:Pause() + self.Active=false + return self + end + function c:Resume() + self.Active=true + return self + end + setmetatable(c,mt) + self:create(c) + return c +end +function multi:newStep(start,reset,count,skip) + local c=self:newBase() + think=1 + c.Type='step' + c.pos=start or 1 + c.endAt=reset or math.huge + c.skip=skip or 0 + c.spos=0 + c.count=count or 1*think + c.funcE={} + c.funcS={} + c.start=start or 1 + if start~=nil and reset~=nil then + if start>reset then + think=-1 + end + end + function c:Act() + if self~=nil then + if self.spos==0 then + if self.pos==self.start then + for fe=1,#self.funcS do + self.funcS[fe](self) + end + end + for i=1,#self.func do + self.func[i](self,self.pos) + end + self.pos=self.pos+self.count + if self.pos-self.count==self.endAt then + self:Pause() + for fe=1,#self.funcE do + self.funcE[fe](self) + end + self.pos=self.start + end + end + end + self.spos=self.spos+1 + if self.spos>=self.skip then + self.spos=0 + end + end + c.Reset=c.Resume + function c:OnStart(func) + table.insert(self.funcS,func) + return self + end + function c:OnStep(func) + table.insert(self.func,1,func) + return self + end + function c:OnEnd(func) + table.insert(self.funcE,func) + return self + end + function c:Break() + self.Active=nil + return self + end + function c:Update(start,reset,count,skip) + self.start=start or self.start + self.endAt=reset or self.endAt + self.skip=skip or self.skip + self.count=count or self.count + self:Resume() + return self + end + self:create(c) + return c +end +function multi:newTLoop(func,set) + local c=self:newBase() + c.Type='tloop' + c.set=set or 0 + c.timer=self:newTimer() + c.life=0 + c:setPriority("Low") + if func then + c.func={func} + end + function c:Act() + if self.timer:Get()>=self.set then + self.life=self.life+1 + for i=1,#self.func do + self.func[i](self,self.life) + end + self.timer:Reset() + end + end + function c:Resume() + self.Parent.Resume(self) + self.timer:Resume() + return self + end + function c:Pause() + self.timer:Pause() + self.Parent.Pause(self) + return self + end + function c:OnLoop(func) + table.insert(self.func,func) + return self + end + self:create(c) + return c +end +function multi:setTimeout(func,t) + multi:newThread(function() thread.sleep(t) func() end) +end +function multi:newTrigger(func) + local c={} + c.Type='trigger' + c.trigfunc=func or function() end + function c:Fire(...) + self:trigfunc(...) + return self + end + self:create(c) + return c +end +function multi:newTStep(start,reset,count,set) + local c=self:newBase() + think=1 + c.Type='tstep' + c:setPriority("Low") + c.start=start or 1 + local reset = reset or math.huge + c.endAt=reset + c.pos=start or 1 + c.skip=skip or 0 + c.count=count or 1*think + c.funcE={} + c.timer=self.clock() + c.set=set or 1 + c.funcS={} + function c:Update(start,reset,count,set) + self.start=start or self.start + self.pos=self.start + self.endAt=reset or self.endAt + self.set=set or self.set + self.count=count or self.count or 1 + self.timer=self.clock() + self:Resume() + return self + end + function c:Act() + if self.clock()-self.timer>=self.set then + self:Reset() + if self.pos==self.start then + for fe=1,#self.funcS do + self.funcS[fe](self) + end + end + for i=1,#self.func do + self.func[i](self,self.pos) + end + self.pos=self.pos+self.count + if self.pos-self.count==self.endAt then + self:Pause() + for fe=1,#self.funcE do + self.funcE[fe](self) + end + self.pos=self.start + end + end + end + function c:OnStart(func) + table.insert(self.funcS,func) + return self + end + function c:OnStep(func) + table.insert(self.func,func) + return self + end + function c:OnEnd(func) + table.insert(self.funcE,func) + return self + end + function c:Break() + self.Active=nil + return self + end + function c:Reset(n) + if n then self.set=n end + self.timer=self.clock() + self:Resume() + return self + end + self:create(c) + return c +end +local scheduledjobs = {} +local sthread +function multi:scheduleJob(time,func) + if not sthread then + sthread = multi:newThread("JobScheduler",function() + local time = os.date("*t", os.time()) + local ready = false + while true do + thread.sleep(1) -- Every second we do some tests + time = os.date("*t", os.time()) + for j,job in pairs(scheduledjobs) do + ready = true + for k,v in pairs(job[1]) do + if not (v == time[k]) then + ready = false + end + end + if ready and not job[3] then + job[2]() + job[3] = true + elseif not ready and job[3] then + job[3] = false + end + end + end + end) + end + table.insert(scheduledjobs,{time, func,false}) +end +-- Special Events +local _os = os.exit +function os.exit(n) + multi.OnExit:Fire(n or 0) + _os(n) +end +multi.OnPreLoad = multi:newConnection() +multi.OnLoad = multi:newConnection(nil,nil,true) +multi.OnExit = multi:newConnection(nil,nil,true) +multi.m = {onexit = function() multi.OnExit:Fire() end} +if _VERSION >= "Lua 5.2" then + setmetatable(multi.m, {__gc = multi.m.onexit}) +else + multi.m.sentinel = newproxy(true) + getmetatable(multi.m.sentinel).__gc = multi.m.onexit +end +-- Threading stuff +multi.GlobalVariables={} +if os.getOS()=="windows" then + thread.__CORES=tonumber(os.getenv("NUMBER_OF_PROCESSORS")) +else + thread.__CORES=tonumber(io.popen("nproc --all"):read("*n")) +end +thread.requests = {} +local dFunc = function() return true end +local dRef = {nil,nil,nil} +function thread.request(t,cmd,...) + thread.requests[t.thread] = {cmd,{...}} +end +function thread._Requests() + local t = thread.requests[coroutine.running()] + thread.requests[coroutine.running()] = nil + if t then + local cmd,args = t[1],t[2] + thread[cmd](unpack(args)) + end +end +function thread.exec(func) + func() +end +function thread.sleep(n) + thread._Requests() + dRef[1] = "_sleep_" + dRef[2] = n or 0 + return coroutine.yield(dRef) +end +function thread.hold(n) + thread._Requests() + dRef[1] = "_hold_" + dRef[2] = n or dFunc + return coroutine.yield(dRef) +end +function thread.holdFor(sec,n) + thread._Requests() + dRef[1] = "_holdF_" + dRef[2] = sec + dRef[3] = n or dFunc + return coroutine.yield(dRef) +end +function thread.holdWithin(skip,n) + thread._Requests() + dRef[1] = "_holdW_" + dRef[2] = skip or 1 + dRef[3] = n or dFunc + return coroutine.yield(dRef) +end +function thread.skip(n) + thread._Requests() + dRef[1] = "_skip_" + dRef[2] = n or 1 + return coroutine.yield(dRef) +end +function thread.kill() + dRef[1] = "_kill_" + dRef[2] = "T_T" + return coroutine.yield(dRef) +end +function thread.yield() + thread._Requests() + return thread.sleep(0) +end +function thread.isThread() + return coroutine.running()~=nil +end +function thread.getCores() + return thread.__CORES +end +function thread.set(name,val) + multi.GlobalVariables[name]=val + return true +end +function thread.get(name) + return multi.GlobalVariables[name] +end +function thread.waitFor(name) + thread.hold(function() return thread.get(name)~=nil end) + return thread.get(name) +end +function multi.hold(func,no) + if thread.isThread() and not(no) then + if type(func) == "function" or type(func) == "table" then + return thread.hold(func) + end + return thread.sleep(func) + end + local death = false + if type(func)=="number" then + multi:newThread("Hold_func",function() + thread.sleep(func) + death = true + end) + while not death do + multi.scheduler:Act() + end + else + local rets + multi:newThread("Hold_func",function() + rets = {thread.hold(func)} + death = true + end) + while not death do + multi.scheduler:Act() + end + return unpack(rets) + end +end +function multi.holdFor(n,func) + local temp + multi:newThread(function() + thread.sleep(n) + temp = true + end) + return multi.hold(function() + if func() then + return func() + elseif temp then + return multi.NIL, "TIMEOUT" + end + end) +end +function thread:newFunction(func,holdme) + local done = false + return function(...) + local rets, err + local function wait(no) + if thread.isThread() and not (no) then + return multi.hold(function() + if err then + return multi.NIL, err + elseif rets then + return unpack(rets) + end + end) + else + while not rets do + multi.scheduler:Act() + end + return unpack(rets) + end + end + local t = multi:newThread("TempThread",func,...) + t.OnDeath(function(self,status,...) rets = {...} end) + t.OnError(function(self,e) err = e end) + if holdme then + return wait() + end + local temp = { + isTFunc = true, + wait = wait, + connect = function(f) + t.OnDeath(function(self,status,...) if done == false then f(...) done = true end end) + t.OnError(function(self,err) if done == false then f(self,err) done = true end end) + end + } + return temp,temp,temp,temp,temp,temp,temp + end +end +function thread.run(func) + local threaddata,t2,t3,t4,t5,t6 + local t = multi:newThread("Temp_Thread",func) + t.OnDeath(function(self,status, r1,r2,r3,r4,r5,r6) + threaddata,t2,t3,t4,t5,t6 = r1,r2,r3,r4,r5,r6 + end) + return thread.hold(function() + return threaddata,t2,t3,t4,t5,t6 + end) +end +function thread.testFor(name,_val,sym) + thread.hold(function() + local val = thread.get(name)~=nil + if val then + if sym == "==" or sym == "=" then + return _val==val + elseif sym == ">" then + return _val>val + elseif sym == "<" then + return _val=" then + return _val>=val + end + end + end) + return thread.get(name) +end +function multi.print(...) + if multi.defaultSettings.print then + print(...) + end +end +local initT = false +local threadCount = 0 +local threadid = 0 +thread.__threads = {} +local threads = thread.__threads +local Gref = _G +function multi:newThread(name,func,...) + multi.OnLoad:Fire() + local func = func or name + if type(name) == "function" then + name = "Thread#"..threadCount + end + local env = {} + setmetatable(env,{ + __index = Gref, + __newindex = function(t,k,v) + if type(v)=="function" then + rawset(t,k,thread:newFunction(v)) + else + if type(v)=="table" then + if v.isTFunc then + if not _G["_stack_"] or #_G["_stack_"]==0 then + _G["_stack_"] = {} + local s = _G["_stack_"] + local a,b,c,d,e,f,g = v.wait(true) + table.insert(s,a) + table.insert(s,b) + table.insert(s,c) + table.insert(s,d) + table.insert(s,e) + table.insert(s,f) + local x = table.remove(_G["_stack_"]) + rawset(t,k,x) + else + local x = table.remove(_G["_stack_"]) + rawset(t,k,x) + end + else + Gref[k]=v + end + else + Gref[k]=v + end + end + end + }) + setfenv(func,env) + local c={} + c.TempRets = {nil,nil,nil,nil,nil,nil,nil,nil,nil,nil} + c.startArgs = {...} + c.ref={} + c.Name=name + c.thread=coroutine.create(func) + c.sleep=1 + c.Type="thread" + c.TID = threadid + c.firstRunDone=false + c.timer=multi:newTimer() + c._isPaused = false + c.returns = {} + c.OnError = multi:newConnection(true,nil,true) + c.OnDeath = multi:newConnection(true,nil,true) + function c:isPaused() + return self._isPaused + end + local resumed = false + function c:Pause() + if not self._isPaused then + thread.request(self,"exec",function() + thread.hold(function() + return resumed + end) + resumed = false + self._isPaused = false + end) + self._isPaused = true + end + end + function c:Resume() + resumed = true + end + function c:Kill() + thread.request(self,"kill") + end + c.Destroy = c.Kill + function c.ref:send(name,val) + ret=coroutine.yield({Name=name,Value=val}) + end + function c.ref:get(name) + return self.Globals[name] + end + function c.ref:kill() + dRef[1] = "_kill_" + dRef[2] = "I Was killed by You!" + err = coroutine.yield(dRef) + if err then + error("Failed to kill a thread! Exiting...") + end + end + function c.ref:sleep(n) + if type(n)=="function" then + ret=thread.hold(n) + elseif type(n)=="number" then + ret=thread.sleep(tonumber(n) or 0) + else + error("Invalid Type for sleep!") + end + end + function c.ref:syncGlobals(v) + self.Globals=v + end + table.insert(threads,c) + if initT==false then + multi.initThreads() + end + c.creationTime = os.clock() + threadid = threadid + 1 + return c +end +function multi.initThreads(justThreads) + initT = true + multi.scheduler=multi:newLoop():setName("multi.thread") + multi.scheduler.Type="scheduler" + function multi.scheduler:setStep(n) + self.skip=tonumber(n) or 24 + end + multi.scheduler.skip=0 + local t0,t1,t2,t3,t4,t5,t6 + local r1,r2,r3,r4,r5,r6 + local ret,_ + local function CheckRets(i) + if ret~=nil then + if not threads[i] then return end + threads[i].TempRets[1] = ret + threads[i].TempRets[2] = r1 + threads[i].TempRets[3] = r2 + threads[i].TempRets[4] = r3 + threads[i].TempRets[5] = r4 + threads[i].TempRets[6] = r5 + threads[i].TempRets[7] = r6 + end + end + local function helper(i) + if type(ret)=="table" then + if ret[1]=="_kill_" then + threads[i].OnDeath:Fire(threads[i],"killed",ret,r1,r2,r3,r4,r5,r6) + table.remove(threads,i) + ret = nil + elseif ret[1]=="_sleep_" then + threads[i].sec = ret[2] + threads[i].time = clock() + threads[i].task = "sleep" + threads[i].__ready = false + ret = nil + elseif ret[1]=="_skip_" then + threads[i].count = ret[2] + threads[i].pos = 0 + threads[i].task = "skip" + threads[i].__ready = false + ret = nil + elseif ret[1]=="_hold_" then + if type(ret[2])=="table" and ret[2].Type=='connector' then + local letsgo + ret[2](function(...) letsgo = {...} end) + ret[2] = function() + if letsgo then + return unpack(letsgo) + end + end + end + threads[i].func = ret[2] + threads[i].task = "hold" + threads[i].__ready = false + ret = nil + elseif ret[1]=="_holdF_" then + threads[i].sec = ret[2] + threads[i].func = ret[3] + threads[i].task = "holdF" + threads[i].time = clock() + threads[i].__ready = false + ret = nil + elseif ret[1]=="_holdW_" then + threads[i].count = ret[2] + threads[i].pos = 0 + threads[i].func = ret[3] + threads[i].task = "holdW" + threads[i].time = clock() + threads[i].__ready = false + ret = nil + end + CheckRets(i) + end + end + multi.scheduler:OnLoop(function(self) + for i=#threads,1,-1 do + if not threads[i].__started then + if coroutine.running() ~= threads[i].thread then + _,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6) + CheckRets(i) + end + threads[i].__started = true + helper(i) + end + if not _ then + threads[i].OnError:Fire(threads[i],ret) + end + if threads[i] and coroutine.status(threads[i].thread)=="dead" then + local tr = threads[i].TempRets + if ret == nil then + threads[i].OnDeath:Fire(threads[i],"ended",tr[1],tr[2],tr[3],tr[4],tr[5],tr[6],tr[7]) + else + threads[i].OnDeath:Fire(threads[i],"ended",ret,r1,r2,r3,r4,r5,r6) + end + table.remove(threads,i) + elseif threads[i] and threads[i].task == "skip" then + threads[i].pos = threads[i].pos + 1 + if threads[i].count==threads[i].pos then + threads[i].task = "" + threads[i].__ready = true + end + elseif threads[i] and threads[i].task == "hold" then --GOHERE + t0,t1,t2,t3,t4,t5,t6 = threads[i].func() + if t0 then + if t0==multi.NIL then + t0 = nil + end + threads[i].task = "" + threads[i].__ready = true + end + elseif threads[i] and threads[i].task == "sleep" then + if clock() - threads[i].time>=threads[i].sec then + threads[i].task = "" + threads[i].__ready = true + end + elseif threads[i] and threads[i].task == "holdF" then + t0,t1,t2,t3,t4,t5,t6 = threads[i].func() + if t0 then + threads[i].task = "" + threads[i].__ready = true + elseif clock() - threads[i].time>=threads[i].sec then + threads[i].task = "" + threads[i].__ready = true + t0 = nil + t1 = "TIMEOUT" + end + elseif threads[i] and threads[i].task == "holdW" then + threads[i].pos = threads[i].pos + 1 + t0,t1,t2,t3,t4,t5,t6 = threads[i].func() + if t0 then + threads[i].task = "" + threads[i].__ready = true + elseif threads[i].count==threads[i].pos then + threads[i].task = "" + threads[i].__ready = true + t0 = nil + t1 = "TIMEOUT" + end + end + if threads[i] and threads[i].__ready then + threads[i].__ready = false + if coroutine.running() ~= threads[i].thread then + _,ret,r1,r2,r3,r4,r5,r6=coroutine.resume(threads[i].thread,t0,t1,t2,t3,t4,t5,t6) + CheckRets(i) + end + end + helper(i) + end + end) + if justThreads then + while true do + multi.scheduler:Act() + end + end +end +function multi:threadloop() + multi.initThreads(true) +end +multi.OnError=multi:newConnection() +function multi:newThreadedProcess(name) + local c = {} + local holding = false + local kill = false + setmetatable(c, multi) + function c:newBase(ins) + local ct = {} + ct.Active=true + ct.func={} + ct.ender={} + ct.Act=function() end + ct.Parent=self + ct.held=false + ct.ref=self.ref + table.insert(self.Mainloop,ct) + return ct + end + c.Parent=self + c.Active=true + c.func={} + c.Type='threadedprocess' + c.Mainloop={} + c.Garbage={} + c.Children={} + c.Active=true + c.Rest=0 + c.updaterate=.01 + c.restRate=.1 + c.Jobs={} + c.queue={} + c.jobUS=2 + c.rest=false + function c:getController() + return nil + end + function c:Start() + self.rest=false + return self + end + function c:Resume() + self.rest=false + return self + end + function c:Pause() + self.rest=true + return self + end + function c:Remove() + self.ref:kill() + return self + end + function c:Kill() + kill = true + return self + end + function c:Sleep(n) + holding = true + if type(n)=="number" then + multi:newAlarm(n):OnRing(function(a) + holding = false + a:Destroy() + end):setName("multi.TPSleep") + elseif type(n)=="function" then + multi:newEvent(n):OnEvent(function(e) + holding = false + e:Destroy() + end):setName("multi.TPHold") + end + return self + end + c.Hold=c.Sleep + multi:newThread(name,function(ref) + while true do + thread.hold(function() + return not(holding) + end) + c:uManager() + end + end) + return c +end +function multi:newHyperThreadedProcess(name) + if not name then error("All threads must have a name!") end + local c = {} + setmetatable(c, multi) + local ind = 0 + local holding = true + local kill = false + function c:newBase(ins) + local ct = {} + ct.Active=true + ct.func={} + ct.ender={} + ct.Act=function() end + ct.Parent=self + ct.held=false + ct.ref=self.ref + ind = ind + 1 + multi:newThread("Proc <"..name.."> #"..ind,function() + while true do + thread.hold(function() + return not(holding) + end) + if kill then + err=coroutine.yield({"_kill_"}) + if err then + error("Failed to kill a thread! Exiting...") + end + end + ct:Act() + end + end) + return ct + end + c.Parent=self + c.Active=true + c.func={} + c.Type='hyperthreadedprocess' + c.Mainloop={} + c.Garbage={} + c.Children={} + c.Active=true + c.Rest=0 + c.updaterate=.01 + c.restRate=.1 + c.Jobs={} + c.queue={} + c.jobUS=2 + c.rest=false + function c:getController() + return nil + end + function c:Start() + holding = false + return self + end + function c:Resume() + holding = false + return self + end + function c:Pause() + holding = true + return self + end + function c:Remove() + self.ref:kill() + return self + end + function c:Kill() + kill = true + return self + end + function c:Sleep(b) + holding = true + if type(b)=="number" then + local t = os.clock() + multi:newAlarm(b):OnRing(function(a) + holding = false + a:Destroy() + end):setName("multi.HTPSleep") + elseif type(b)=="function" then + multi:newEvent(b):OnEvent(function(e) + holding = false + e:Destroy() + end):setName("multi.HTPHold") + end + return self + end + c.Hold=c.Sleep + return c +end +-- Multi runners +function multi:mainloop(settings) + multi.OnPreLoad:Fire() + multi.defaultSettings = settings or multi.defaultSettings + self.uManager=self.uManagerRef + local p_c,p_h,p_an,p_n,p_bn,p_l,p_i = self.Priority_Core,self.Priority_High,self.Priority_Above_Normal,self.Priority_Normal,self.Priority_Below_Normal,self.Priority_Low,self.Priority_Idle + local P_LB = p_i + if not isRunning then + local protect = false + local priority = false + local stopOnError = true + local delay = 3 + if settings then + priority = settings.priority + if settings.auto_priority then + priority = -1 + end + if settings.preLoop then + settings.preLoop(self) + end + if settings.stopOnError then + stopOnError = settings.stopOnError + end + if settings.auto_stretch then + p_i = p_i * settings.auto_stretch + end + if settings.auto_delay then + delay = settings.auto_delay + end + if settings.auto_lowerbound then + P_LB = settings.auto_lowerbound + end + protect = settings.protect + end + local t,tt = clock(),0 + isRunning=true + local lastTime = clock() + rawset(self,'Start',clock()) + mainloopActive = true + local Loop=self.Mainloop + local PS=self + local PStep = 1 + local autoP = 0 + local solid,sRef + local cc=0 + multi.OnLoad:Fire() + while mainloopActive do + if next then + local DD = table.remove(next,1) + while DD do + DD() + DD = table.remove(next,1) + end + end + if priority == 1 then + for _D=#Loop,1,-1 do + for P=1,7 do + if Loop[_D] then + if (PS.PList[P])%Loop[_D].Priority==0 then + if Loop[_D].Active then + self.CID=_D + if not protect then + Loop[_D]:Act() + else + local status, err=pcall(Loop[_D].Act,Loop[_D]) + if err then + Loop[_D].error=err + self.OnError:Fire(Loop[_D],err) + if stopOnError then + Loop[_D]:Destroy() + end + end + end + end + end + end + end + end + elseif priority == 2 then + for _D=#Loop,1,-1 do + if Loop[_D] then + if (PStep)%Loop[_D].Priority==0 then + if Loop[_D].Active then + self.CID=_D + if not protect then + Loop[_D]:Act() + else + local status, err=pcall(Loop[_D].Act,Loop[_D]) + if err then + Loop[_D].error=err + self.OnError:Fire(Loop[_D],err) + if stopOnError then + Loop[_D]:Destroy() + end + end + end + end + end + end + end + PStep=PStep+1 + if PStep==p_i then + PStep=0 + end + elseif priority == 3 then + cc=cc+1 + if cc == 1000 then + tt = clock()-t + t = clock() + cc=0 + end + for _D=#Loop,1,-1 do + if Loop[_D] then + if Loop[_D].Priority == p_c or (Loop[_D].Priority == p_h and tt<.5) or (Loop[_D].Priority == p_an and tt<.125) or (Loop[_D].Priority == p_n and tt<.063) or (Loop[_D].Priority == p_bn and tt<.016) or (Loop[_D].Priority == p_l and tt<.003) or (Loop[_D].Priority == p_i and tt<.001) then + if Loop[_D].Active then + self.CID=_D + if not protect then + Loop[_D]:Act() + else + local status, err=pcall(Loop[_D].Act,Loop[_D]) + if err then + Loop[_D].error=err + self.OnError:Fire(Loop[_D],err) + if stopOnError then + Loop[_D]:Destroy() + end + end + end + end + end + end + end + elseif priority == -1 then + for _D=#Loop,1,-1 do + sRef = Loop[_D] + if Loop[_D] then + if (sRef.Priority == p_c) or PStep==0 then + if sRef.Active then + self.CID=_D + if not protect then + if sRef.solid then + sRef:Act() + solid = true + else + time = multi.timer(sRef.Act,sRef) + sRef.solid = true + solid = false + end + if Loop[_D] and not solid then + if time == 0 then + Loop[_D].Priority = p_c + else + Loop[_D].Priority = P_LB + end + end + else + if Loop[_D].solid then + Loop[_D]:Act() + solid = true + else + time, status, err=multi.timer(pcall,Loop[_D].Act,Loop[_D]) + Loop[_D].solid = true + solid = false + end + if Loop[_D] and not solid then + if time == 0 then + Loop[_D].Priority = p_c + else + Loop[_D].Priority = P_LB + end + end + if err then + Loop[_D].error=err + self.OnError:Fire(Loop[_D],err) + if stopOnError then + Loop[_D]:Destroy() + end + end + end + end + end + end + end + PStep=PStep+1 + if PStep>p_i then + PStep=0 + if clock()-lastTime>delay then + lastTime = clock() + for i = 1,#Loop do + Loop[i]:ResetPriority() + end + end + end + else + for _D=#Loop,1,-1 do + if Loop[_D] then + if Loop[_D].Active then + self.CID=_D + if not protect then + Loop[_D]:Act() + else + local status, err=pcall(Loop[_D].Act,Loop[_D]) + if err then + Loop[_D].error=err + self.OnError:Fire(Loop[_D],err) + if stopOnError then + Loop[_D]:Destroy() + end + end + end + end + end + end + end + end + else + return "Already Running!" + end +end +function multi:uManager(settings) + multi.OnPreLoad:Fire() + multi.defaultSettings = settings or multi.defaultSettings + self.t,self.tt = clock(),0 + if settings then + priority = settings.priority + if settings.auto_priority then + priority = -1 + end + if settings.preLoop then + settings.preLoop(self) + end + if settings.stopOnError then + stopOnError = settings.stopOnError + end + multi.defaultSettings.p_i = self.Priority_Idle + if settings.auto_stretch then + multi.defaultSettings.p_i = settings.auto_stretch*self.Priority_Idle + end + multi.defaultSettings.delay = settings.auto_delay or 3 + multi.defaultSettings.auto_lowerbound = settings.auto_lowerbound or self.Priority_Idle + protect = settings.protect + end + multi.OnLoad:Fire() + self.uManager=self.uManagerRef +end +function multi:uManagerRef(settings) + if self.Active then + if next then + local DD = table.remove(next,1) + while DD do + DD() + DD = table.remove(next,1) + end + end + local Loop=self.Mainloop + local PS=self + if multi.defaultSettings.priority==1 then + for _D=#Loop,1,-1 do + for P=1,7 do + if Loop[_D] then + if (PS.PList[P])%Loop[_D].Priority==0 then + if Loop[_D].Active then + self.CID=_D + if not multi.defaultSettings.protect then + Loop[_D]:Act() + else + local status, err=pcall(Loop[_D].Act,Loop[_D]) + if err then + Loop[_D].error=err + self.OnError:Fire(Loop[_D],err) + if multi.defaultSettings.stopOnError then + Loop[_D]:Destroy() + end + end + end + end + end + end + end + end + elseif multi.defaultSettings.priority==2 then + for _D=#Loop,1,-1 do + if Loop[_D] then + if (PS.PStep)%Loop[_D].Priority==0 then + if Loop[_D].Active then + self.CID=_D + if not multi.defaultSettings.protect then + Loop[_D]:Act() + else + local status, err=pcall(Loop[_D].Act,Loop[_D]) + if err then + Loop[_D].error=err + self.OnError:Fire(Loop[_D],err) + if multi.defaultSettings.stopOnError then + Loop[_D]:Destroy() + end + end + end + end + end + end + end + PS.PStep=PS.PStep+1 + if PS.PStep>self.Priority_Idle then + PS.PStep=0 + end + elseif priority == 3 then + self.tt = clock()-self.t + self.t = clock() + for _D=#Loop,1,-1 do + if Loop[_D] then + if Loop[_D].Priority == self.Priority_Core or (Loop[_D].Priority == self.Priority_High and tt<.5) or (Loop[_D].Priority == self.Priority_Above_Normal and tt<.125) or (Loop[_D].Priority == self.Priority_Normal and tt<.063) or (Loop[_D].Priority == self.Priority_Below_Normal and tt<.016) or (Loop[_D].Priority == self.Priority_Low and tt<.003) or (Loop[_D].Priority == self.Priority_Idle and tt<.001) then + if Loop[_D].Active then + self.CID=_D + if not protect then + Loop[_D]:Act() + else + local status, err=pcall(Loop[_D].Act,Loop[_D]) + if err then + Loop[_D].error=err + self.OnError:Fire(Loop[_D],err) + if multi.defaultSettings.stopOnError then + Loop[_D]:Destroy() + end + end + end + end + end + end + end + elseif priority == -1 then + for _D=#Loop,1,-1 do + local sRef = Loop[_D] + if Loop[_D] then + if (sRef.Priority == self.Priority_Core) or PStep==0 then + if sRef.Active then + self.CID=_D + if not protect then + if sRef.solid then + sRef:Act() + solid = true + else + time = multi.timer(sRef.Act,sRef) + sRef.solid = true + solid = false + end + if Loop[_D] and not solid then + if time == 0 then + Loop[_D].Priority = self.Priority_Core + else + Loop[_D].Priority = multi.defaultSettings.auto_lowerbound + end + end + else + if Loop[_D].solid then + Loop[_D]:Act() + solid = true + else + time, status, err=multi.timer(pcall,Loop[_D].Act,Loop[_D]) + Loop[_D].solid = true + solid = false + end + if Loop[_D] and not solid then + if time == 0 then + Loop[_D].Priority = self.Priority_Core + else + Loop[_D].Priority = multi.defaultSettings.auto_lowerbound + end + end + if err then + Loop[_D].error=err + self.OnError:Fire(Loop[_D],err) + if multi.defaultSettings.stopOnError then + Loop[_D]:Destroy() + end + end + end + end + end + end + end + self.PStep=self.PStep+1 + if self.PStep>multi.defaultSettings.p_i then + self.PStep=0 + if clock()-self.lastTime>multi.defaultSettings.delay then + self.lastTime = clock() + for i = 1,#Loop do + Loop[i]:ResetPriority() + end + end + end + else + for _D=#Loop,1,-1 do + if Loop[_D] then + if Loop[_D].Active then + self.CID=_D + if not multi.defaultSettings.protect then + Loop[_D]:Act() + else + local status, err=pcall(Loop[_D].Act,Loop[_D]) + if err then + Loop[_D].error=err + self.OnError:Fire(Loop[_D],err) + end + end + end + end + end + end + end +end +-- State Saving Stuff +function multi:IngoreObject() + self.Ingore=true + return self +end +function multi:ToString() + if self.Ingore then return end + local t=self.Type + local data; + multi.print(t) + if t:sub(-6)=="Thread" then + data={ + Type=t, + rest=self.rest, + updaterate=self.updaterest, + restrate=self.restrate, + name=self.name, + func=self.func, + important=self.important, + Active=self.Active, + ender=self.ender, + held=self.held, + } + else + data={ + Type=t, + func=self.func, + funcTM=self.funcTM, + funcTMR=self.funcTMR, + important=self.important, + ender=self.ender, + held=self.held, + } + end + if t=="eventThread" or t=="event" then + table.merge(data,{ + Task=self.Task, + }) + elseif t=="loopThread" or t=="loop" then + table.merge(data,{ + Start=self.Start, + }) + elseif t=="stepThread" or t=="step" then + table.merge(data,{ + funcE=self.funcE, + funcS=self.funcS, + pos=self.pos, + endAt=self.endAt, + start=self.start, + spos=self.spos, + skip=self.skip, + count=self.count, + }) + elseif t=="tloopThread" then + table.merge(data,{ + restN=self.restN, + }) + elseif t=="tloop" then + table.merge(data,{ + set=self.set, + life=self.life, + }) + elseif t=="tstepThread" or t=="tstep" then + table.merge(data,{ + funcE=self.funcE, + funcS=self.funcS, + pos=self.pos, + endAt=self.endAt, + start=self.start, + spos=self.spos, + skip=self.skip, + count=self.count, + timer=self.timer, + set=self.set, + reset=self.reset, + }) + elseif t=="updaterThread" or t=="updater" then + table.merge(data,{ + pos=self.pos, + skip=self.skip, + }) + elseif t=="alarmThread" or t=="alarm" then + table.merge(data,{ + set=self.set, + }) + elseif t=="timemaster" then + -- Weird stuff is going on here! + -- Need to do some testing + table.merge(data,{ + timer=self.timer, + _timer=self._timer, + set=self.set, + link=self.link, + }) + elseif t=="process" or t=="mainprocess" then + local loop=self.Mainloop + local dat={} + for i=1,#loop do + local ins=loop[i]:ToString() + if ins~=nil then + table.insert(dat,ins) + end + end + local str=bin.new() + str:addBlock({Type=t}) + str:addBlock(#dat,4,"n") + for i=1,#dat do + str:addBlock(#dat[i],4,"n") + str:addBlock(dat[i]) + end + return str.data + end + for i,v in pairs(self.important) do + data[v]=self[v] + end + local str=bin.new() + str:addBlock(data) + return str.data +end +function multi:newFromString(str) + if type(str)=="table" then + if str.Type=="bin" then + str=str.data + end + end + local handle=bin.new(str) + local data=handle:getBlock("t") + local t=data.Type + if t=="mainprocess" then + local objs=handle:getBlock("n",4) + for i=1,objs do + self:newFromString(handle:getBlock("s",(handle:getBlock("n",4)))) + end + return self + elseif t=="process" then + local temp=multi:newProcessor() + local objs=handle:getBlock("n",4) + for i=1,objs do + temp:newFromString(handle:getBlock("s",(handle:getBlock("n",4)))) + end + return temp + elseif t=="step" then -- GOOD + local item=self:newStep() + table.merge(item,data) + return item + elseif t=="tstep" then -- GOOD + local item=self:newTStep() + table.merge(item,data) + return item + elseif t=="tloop" then -- GOOD + local item=self:newTLoop() + table.merge(item,data) + return item + elseif t=="event" then -- GOOD + local item=self:newEvent(data.task) + table.merge(item,data) + return item + elseif t=="alarm" then -- GOOD + local item=self:newAlarm() + table.merge(item,data) + return item + elseif t=="updater" then -- GOOD + local item=self:newUpdater() + table.merge(item,data) + return item + elseif t=="loop" then -- GOOD + local item=self:newLoop() + table.merge(item,data) + return item + end +end +function multi:Important(varname) + table.insert(important,varname) +end +function multi:ToFile(path) + bin.new(self:ToString()):tofile(path) +end +function multi:fromFile(path) + self:newFromString(bin.load(path)) +end +function multi:SetStateFlag(opt) + -- +end +function multi:quickStateSave(b) + -- +end +function multi:saveState(path,opt) + -- +end +function multi:loadState(path) + -- +end +function multi:setDefualtStateFlag(opt) + -- +end +return multi diff --git a/multi/integration/code.code-workspace b/multi/integration/code.code-workspace new file mode 100644 index 0000000..8f77322 --- /dev/null +++ b/multi/integration/code.code-workspace @@ -0,0 +1,8 @@ +{ + "folders": [ + { + "path": "C:\\Users\\Ryan\\Desktop\\Code Tests" + } + ], + "settings": {} +} \ No newline at end of file diff --git a/multi/integration/lanesManager/extensions.lua b/multi/integration/lanesManager/extensions.lua new file mode 100644 index 0000000..7c93108 --- /dev/null +++ b/multi/integration/lanesManager/extensions.lua @@ -0,0 +1,139 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +local multi, thread = require("multi"):init() +local GLOBAL, THREAD = multi.integration.GLOBAL,multi.integration.THREAD +function multi:newSystemThreadedQueue(name) + local c = {} + c.linda = lanes.linda() + function c:push(v) + self.linda:send("Q", v) + end + function c:pop() + return ({self.linda:receive(0, "Q")})[2] + end + function c:peek() + return self.linda:get("Q") + end + function c:init() + return self + end + GLOBAL[name or "_"] = c + return c +end +function multi:newSystemThreadedTable(name) + local c = {} + c.link = lanes.linda() + setmetatable(c,{ + __index = function(t,k) + return c.link:get(k) + end, + __newindex = function(t,k,v) + c.link:set(k,v) + end + }) + function c:init() + return self + end + GLOBAL[name or "_"] = c + return c +end +function multi:newSystemThreadedJobQueue(n) + local c = {} + c.cores = n or THREAD.getCores()*2 + c.OnJobCompleted = multi:newConnection() + local funcs = multi:newSystemThreadedTable() + local queueJob = multi:newSystemThreadedQueue() + local queueReturn = multi:newSystemThreadedQueue() + local doAll = multi:newSystemThreadedQueue() + local ID=1 + local jid = 1 + function c:doToAll(func) + for i=1,c.cores do + doAll:push{ID,func} + end + ID = ID + 1 + end + function c:registerFunction(name,func) + funcs[name]=func + end + function c:pushJob(name,...) + queueJob:push{name,jid,{...}} + jid = jid + 1 + end + multi:newThread("JobQueueManager",function() + while true do + local job = thread.hold(function() + return queueReturn:pop() + end) + local id = table.remove(job,1) + c.OnJobCompleted:Fire(id,unpack(job)) + end + end) + for i=1,c.cores do + multi:newSystemThread("SystemThreadedJobQueue",function(queue) + local multi,thread = require("multi"):init() + local idle = os.clock() + local clock = os.clock + local ref = 0 + setmetatable(_G,{__index = funcs}) + multi:newThread("JobHandler",function() + while true do + local dat = thread.hold(function() + return queueJob:pop() + end) + idle = clock() + local name = table.remove(dat,1) + local jid = table.remove(dat,1) + local args = table.remove(dat,1) + queueReturn:push{jid, funcs[name](unpack(args)),queue} + end + end) + multi:newThread("DoAllHandler",function() + while true do + local dat = thread.hold(function() + return doAll:peek() + end) + if dat then + if dat[1]>ref then + idle = clock() + ref = dat[1] + dat[2]() + doAll:pop() + end + end + end + end) + multi:newThread("IdleHandler",function() + while true do + thread.hold(function() + return clock()-idle>3 + end) + THREAD.sleep(.01) + end + end) + multi:mainloop() + end,i).priority = thread.Priority_Core + end + return c +end \ No newline at end of file diff --git a/multi/integration/lanesManager/init.lua b/multi/integration/lanesManager/init.lua new file mode 100644 index 0000000..6e187e5 --- /dev/null +++ b/multi/integration/lanesManager/init.lua @@ -0,0 +1,139 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +package.path = "?/init.lua;?.lua;" .. package.path +multi, thread = require("multi").init() -- get it all and have it on all lanes +if multi.integration then -- This allows us to call the lanes manager from supporting modules without a hassel + return { + init = function() + return multi.integration.GLOBAL, multi.integration.THREAD + end + } +end +-- Step 1 get lanes +lanes = require("lanes").configure() +multi.SystemThreads = {} +multi.isMainThread = true +function multi:canSystemThread() + return true +end +function multi:getPlatform() + return "lanes" +end +-- Step 2 set up the Linda objects +local __GlobalLinda = lanes.linda() -- handles global stuff +local __SleepingLinda = lanes.linda() -- handles sleeping stuff +local GLOBAL,THREAD = require("multi.integration.lanesManager.threads").init(__GlobalLinda,__SleepingLinda) +local threads = {} +local count = 1 +local started = false +local livingThreads = {} +function THREAD:newFunction(func,holup) + return function(...) + local t = multi:newSystemThread("SystemThreadedFunction",function(...) + return func(...) + end,...) + return thread:newFunction(function() + return thread.hold(function() + return t.thread:join(.001) + end) + end,holup)() + end +end +function multi:newSystemThread(name, func, ...) + multi.InitSystemThreadErrorHandler() + rand = math.random(1, 10000000) + local c = {} + local __self = c + c.name = name + c.Name = name + c.Id = count + c.loadString = {"base","package","os","io","math","table","string","coroutine"} + livingThreads[count] = {true, name} + c.Type = "sthread" + c.creationTime = os.clock() + c.alive = true + c.priority = thread.Priority_Normal + local args = {...} + c.thread = lanes.gen(table.concat(c.loadString,","),{globals={ + THREAD_NAME=name, + THREAD_ID=count + },priority=c.priority}, func)(unpack(args)) + count = count + 1 + function c:kill() + self.thread:cancel() + multi.print("Thread: '" .. self.name .. "' has been stopped!") + self.alive = false + end + table.insert(multi.SystemThreads, c) + c.OnError = multi:newConnection() + GLOBAL["__THREADS__"] = livingThreads + return c +end +multi.OnSystemThreadDied = multi:newConnection() +function multi.InitSystemThreadErrorHandler() + if started == true then + return + end + started = true + multi:newThread( +"ThreadErrorHandler", + function() + local threads = multi.SystemThreads + while true do + thread.sleep(.5) -- switching states often takes a huge hit on performance. half a second to tell me there is an error is good enough. + for i = #threads, 1, -1 do + local v, err, t = threads[i].thread:join(.001) + if err then + if err:find("Thread was killed!") then + print(err) + livingThreads[threads[i].Id] = {false, threads[i].Name} + threads[i].alive = false + multi.OnSystemThreadDied:Fire(threads[i].Id) + GLOBAL["__THREADS__"] = livingThreads + table.remove(threads, i) + elseif err:find("stack traceback") then + print(err) + threads[i].OnError:Fire(threads[i], err, "Error in systemThread: '" .. threads[i].name .. "' <" .. err .. ">") + threads[i].alive = false + livingThreads[threads[i].Id] = {false, threads[i].Name} + multi.OnSystemThreadDied:Fire(threads[i].Id) + GLOBAL["__THREADS__"] = livingThreads + table.remove(threads, i) + end + end + end + end + end + ) +end +multi.print("Integrated Lanes!") +multi.integration = {} -- for module creators +multi.integration.GLOBAL = GLOBAL +multi.integration.THREAD = THREAD +require("multi.integration.lanesManager.extensions") +return { + init = function() + return GLOBAL, THREAD + end +} diff --git a/multi/integration/lanesManager/threads.lua b/multi/integration/lanesManager/threads.lua new file mode 100644 index 0000000..e761e08 --- /dev/null +++ b/multi/integration/lanesManager/threads.lua @@ -0,0 +1,101 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +local function getOS() + if package.config:sub(1, 1) == "\\" then + return "windows" + else + return "unix" + end +end +local function INIT(__GlobalLinda,__SleepingLinda) + local THREAD = {} + function THREAD.set(name, val) + __GlobalLinda:set(name, val) + end + function THREAD.get(name) + __GlobalLinda:get(name) + end + function THREAD.waitFor(name) + local function wait() + math.randomseed(os.time()) + __SleepingLinda:receive(.001, "__non_existing_variable") + end + repeat + wait() + until __GlobalLinda:get(name) + return __GlobalLinda:get(name) + end + if getOS() == "windows" then + THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS")) + else + THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n")) + end + function THREAD.getCores() + return THREAD.__CORES + end + function THREAD.getThreads() + return GLOBAL.__THREADS__ + end + if os.getOS() == "windows" then + THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS")) + else + THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n")) + end + function THREAD.kill() -- trigger the lane destruction + error("Thread was killed!") + end + function THREAD.getName() + return THREAD_NAME + end + function THREAD.getID() + return THREAD_ID + end + _G.THREAD_ID = 0 + function THREAD.sleep(n) + math.randomseed(os.time()) + __SleepingLinda:receive(n, "__non_existing_variable") + end + function THREAD.hold(n) + local function wait() + math.randomseed(os.time()) + __SleepingLinda:receive(.001, "__non_existing_variable") + end + repeat + wait() + until n() + end + local GLOBAL = {} + setmetatable(GLOBAL, { + __index = function(t, k) + return __GlobalLinda:get(k) + end, + __newindex = function(t, k, v) + __GlobalLinda:set(k, v) + end + }) + return GLOBAL, THREAD +end +return {init = function(g,s) + return INIT(g,s) +end} \ No newline at end of file diff --git a/multi/integration/loveManager/extensions.lua b/multi/integration/loveManager/extensions.lua new file mode 100644 index 0000000..aeb3b2d --- /dev/null +++ b/multi/integration/loveManager/extensions.lua @@ -0,0 +1,176 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +local multi, thread = require("multi").init() +GLOBAL = multi.integration.GLOBAL +THREAD = multi.integration.THREAD +function multi:newSystemThreadedQueue(name) + local c = {} + c.Name = name + local fRef = {"func",nil} + function c:init() + local q = {} + q.chan = love.thread.getChannel(self.Name) + function q:push(dat) + if type(dat) == "function" then + fRef[2] = THREAD.dump(dat) + self.chan:push(fRef) + return + else + self.chan:push(dat) + end + end + function q:pop() + local dat = self.chan:pop() + if type(dat)=="table" and dat[1]=="func" then + return THREAD.loadDump(dat[2]) + else + return dat + end + end + function q:peek() + local dat = self.chan:peek() + if type(dat)=="table" and dat[1]=="func" then + return THREAD.loadDump(dat[2]) + else + return dat + end + end + return q + end + THREAD.package(name,c) + return c +end +function multi:newSystemThreadedTable(name) + local c = {} + c.name = name + function c:init() + return THREAD.createTable(self.name) + end + THREAD.package(name,c) + return c +end +local jqc = 1 +function multi:newSystemThreadedJobQueue(n) + local c = {} + c.cores = n or THREAD.getCores() + c.registerQueue = {} + c.funcs = THREAD.createStaticTable("__JobQueue_"..jqc.."_table") + c.queue = love.thread.getChannel("__JobQueue_"..jqc.."_queue") + c.queueReturn = love.thread.getChannel("__JobQueue_"..jqc.."_queueReturn") + c.queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll") + c.id = 0 + c.OnJobCompleted = multi:newConnection() + local allfunc = 0 + function c:doToAll(func) + local f = THREAD.dump(func) + for i = 1, self.cores do + self.queueAll:push({allfunc,f}) + end + allfunc = allfunc + 1 + end + function c:registerFunction(name,func) + if self.funcs[name] then + error("A function by the name "..name.." has already been registered!") + end + self.funcs[name] = func + end + function c:pushJob(name,...) + self.id = self.id + 1 + self.queue:push{name,self.id,...} + return self.id + end + multi:newThread("jobManager",function() + while true do + thread.yield() + local dat = c.queueReturn:pop() + if dat then + print(dat) + c.OnJobCompleted:Fire(unpack(dat)) + end + end + end) + print("Cores: ",c.cores) + for i=1,c.cores do + multi:newSystemThread("JobQueue_"..jqc.."_worker_"..i,function(jqc) + local multi, thread = require("multi"):init() + local function atomic(channel) + return channel:pop() + end + require("love.timer") + local clock = os.clock + local funcs = THREAD.createStaticTable("__JobQueue_"..jqc.."_table") + local queue = love.thread.getChannel("__JobQueue_"..jqc.."_queue") + local queueReturn = love.thread.getChannel("__JobQueue_"..jqc.."_queueReturn") + local lastProc = clock() + local queueAll = love.thread.getChannel("__JobQueue_"..jqc.."_queueAll") + local registry = {} + setmetatable(_G,{__index = funcs}) + multi:newThread("startUp",function() + while true do + thread.yield() + local all = queueAll:peek() + if all and not registry[all[1]] then + lastProc = os.clock() + THREAD.loadDump(queueAll:pop()[2])() + end + end + end) + multi:newThread("runner",function() + thread.sleep(.1) + while true do + thread.yield() + local all = queueAll:peek() + if all and not registry[all[1]] then + lastProc = os.clock() + THREAD.loadDump(queueAll:pop()[2])() + end + local dat = queue:performAtomic(atomic) + if dat then + lastProc = os.clock() + local name = table.remove(dat,1) + local id = table.remove(dat,1) + local tab = {funcs[name](unpack(dat))} + table.insert(tab,1,id) + queueReturn:push(tab) + end + end + end):OnError(function(...) + error(...) + end) + multi:newThread("Idler",function() + while true do + thread.yield() + if clock()-lastProc> 2 then + THREAD.sleep(.05) + else + THREAD.sleep(.001) + end + end + end) + multi:mainloop() + end,jqc) + end + jqc = jqc + 1 + return c +end \ No newline at end of file diff --git a/multi/integration/loveManager/init.lua b/multi/integration/loveManager/init.lua new file mode 100644 index 0000000..9097609 --- /dev/null +++ b/multi/integration/loveManager/init.lua @@ -0,0 +1,82 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +if ISTHREAD then + error("You cannot require the loveManager from within a thread!") +end +local ThreadFileData = [[ +ISTHREAD = true +THREAD = require("multi.integration.loveManager.threads") -- order is important! +sThread = THREAD +__IMPORTS = {...} +__FUNC__=table.remove(__IMPORTS,1) +__THREADID__=table.remove(__IMPORTS,1) +__THREADNAME__=table.remove(__IMPORTS,1) +stab = THREAD.createStaticTable(__THREADNAME__) +GLOBAL = THREAD.getGlobal() +multi, thread = require("multi").init() +stab["returns"] = {THREAD.loadDump(__FUNC__)(unpack(__IMPORTS))} +]] +local multi, thread = require("multi.compat.love2d"):init() +local THREAD = {} +__THREADID__ = 0 +__THREADNAME__ = "MainThread" +multi.integration={} +multi.integration.love2d={} +local THREAD = require("multi.integration.loveManager.threads") +local GLOBAL = THREAD.getGlobal() +local THREAD_ID = 1 +local OBJECT_ID = 0 +function THREAD:newFunction(func,holup) + return function(...) + local t = multi:newSystemThread("SystemThreadedFunction",func,...) + return thread:newFunction(function() + return thread.hold(function() + if t.stab["returns"] then + return unpack(t.stab.returns) + end + end) + end,holup)() + end +end +function multi:newSystemThread(name,func,...) + local c = {} + c.name = name + c.ID=THREAD_ID + c.thread=love.thread.newThread(ThreadFileData) + c.thread:start(THREAD.dump(func),c.ID,c.name,...) + c.stab = THREAD.createStaticTable(name) + GLOBAL["__THREAD_"..c.ID] = {ID=c.ID,Name=c.name,Thread=c.thread} + GLOBAL["__THREAD_COUNT"] = THREAD_ID + THREAD_ID=THREAD_ID+1 + return c +end +function love.threaderror(thread, errorstr) + print("Thread error!\n"..errorstr) +end +multi.integration.GLOBAL = GLOBAL +multi.integration.THREAD = THREAD +require("multi.integration.loveManager.extensions") +return {init=function() + return GLOBAL,THREAD +end} \ No newline at end of file diff --git a/multi/integration/loveManager/threads.lua b/multi/integration/loveManager/threads.lua new file mode 100644 index 0000000..be04fa2 --- /dev/null +++ b/multi/integration/loveManager/threads.lua @@ -0,0 +1,221 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +require("love.timer") +require("love.system") +require("love.data") +local socket = require("socket") +local multi, thread = require("multi").init() +local threads = {} +function threads.loadDump(d) + return loadstring(d:getString()) +end +function threads.dump(func) + return love.data.newByteData(string.dump(func)) +end +local fRef = {"func",nil} +local function manage(channel, value) + channel:clear() + if type(value) == "function" then + fRef[2] = THREAD.dump(value) + channel:push(fRef) + return + else + channel:push(value) + end +end +local function RandomVariable(length) + local res = {} + math.randomseed(socket.gettime()*10000) + for i = 1, length do + res[#res+1] = string.char(math.random(97, 122)) + end + return table.concat(res) +end +local GNAME = "__GLOBAL_" +local proxy = {} +function threads.set(name,val) + if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end + proxy[name]:performAtomic(manage, val) +end +function threads.get(name) + if not proxy[name] then proxy[name] = love.thread.getChannel(GNAME..name) end + local dat = proxy[name]:peek() + if type(dat)=="table" and dat[1]=="func" then + return THREAD.loadDump(dat[2]) + else + return dat + end +end +function threads.waitFor(name) + if thread.isThread() then + return thread.hold(function() + return threads.get(name) + end) + end + while threads.get(name)==nil do + love.timer.sleep(.001) + end + local dat = threads.get(name) + if type(dat) == "table" and dat.init then + dat.init = threads.loadDump(dat.init) + end + return dat +end +function threads.package(name,val) + local init = val.init + val.init=threads.dump(val.init) + GLOBAL[name]=val + val.init=init +end +function threads.getCores() + return love.system.getProcessorCount() +end +function threads.kill() + error("Thread Killed!") +end +function threads.getThreads() + local t = {} + for i=1,GLOBAL["__THREAD_COUNT"] do + t[#t+1]=GLOBAL["__THREAD_"..i] + end + return t +end +function threads.getThread(n) + return GLOBAL["__THREAD_"..n] +end +function threads.getName() + return __THREADNAME__ +end +function threads.getID() + return __THREADID__ +end +function threads.sleep(n) + love.timer.sleep(n) +end +function threads.getGlobal() + return setmetatable({}, + { + __index = function(t, k) + return THREAD.get(k) + end, + __newindex = function(t, k, v) + THREAD.set(k,v) + end + } + ) +end +function threads.createTable(n) + local _proxy = {} + local function set(name,val) + if not _proxy[name] then _proxy[name] = love.thread.getChannel(n..name) end + _proxy[name]:performAtomic(manage, val) + end + local function get(name) + if not _proxy[name] then _proxy[name] = love.thread.getChannel(n..name) end + local dat = _proxy[name]:peek() + if type(dat)=="table" and dat[1]=="func" then + return THREAD.loadDump(dat[2]) + else + return dat + end + end + return setmetatable({}, + { + __index = function(t, k) + return get(k) + end, + __newindex = function(t, k, v) + set(k,v) + end + } + ) +end +function threads.getConsole() + local c = {} + c.queue = love.thread.getChannel("__CONSOLE__") + function c.print(...) + c.queue:push{...} + end + function c.error(err) + c.queue:push{"ERROR in <"..__THREADNAME__..">: "..err,__THREADID__} + error(err) + end + return c +end +if not ISTHREAD then + local clock = os.clock + local lastproc = clock() + local queue = love.thread.getChannel("__CONSOLE__") + multi:newThread("consoleManager",function() + while true do + thread.yield() + dat = queue:pop() + if dat then + lastproc = clock() + print(unpack(dat)) + end + if clock()-lastproc>2 then + thread.sleep(.1) + end + end + end) +end +function threads.createStaticTable(n) + local __proxy = {} + local function set(name,val) + if __proxy[name] then return end + local chan = love.thread.getChannel(n..name) + if chan:getCount()>0 then return end + chan:performAtomic(manage, val) + __proxy[name] = val + end + local function get(name) + if __proxy[name] then return __proxy[name] end + local dat = love.thread.getChannel(n..name):peek() + if type(dat)=="table" and dat[1]=="func" then + __proxy[name] = THREAD.loadDump(dat[2]) + return __proxy[name] + else + __proxy[name] = dat + return __proxy[name] + end + end + return setmetatable({}, + { + __index = function(t, k) + return get(k) + end, + __newindex = function(t, k, v) + set(k,v) + end + } + ) +end +function threads.hold(n) + local dat + while not(dat) do + dat = n() + end +end +return threads \ No newline at end of file diff --git a/multi/integration/luvitManager.lua b/multi/integration/luvitManager.lua new file mode 100644 index 0000000..73ee666 --- /dev/null +++ b/multi/integration/luvitManager.lua @@ -0,0 +1,137 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] + +-- This module probably will not be maintained any longer! +package.path = "?/init.lua;?.lua;" .. package.path +local function _INIT(luvitThread, timer) + -- lots of this stuff should be able to stay the same + function os.getOS() + if package.config:sub(1, 1) == "\\" then + return "windows" + else + return "unix" + end + end + -- Step 1 get setup threads on luvit... Sigh how do i even... + local multi, thread = require("multi").init() + isMainThread = true + function multi:canSystemThread() + return true + end + function multi:getPlatform() + return "luvit" + end + local multi = multi + -- Step 2 set up the Global table... is this possible? + local GLOBAL = {} + setmetatable( + GLOBAL, + { + __index = function(t, k) + --print("No Global table when using luvit integration!") + return nil + end, + __newindex = function(t, k, v) + --print("No Global table when using luvit integration!") + end + } + ) + local THREAD = {} + function THREAD.set(name, val) + --print("No Global table when using luvit integration!") + end + function THREAD.get(name) + --print("No Global table when using luvit integration!") + end + local function randomString(n) + local str = "" + local strings = {"a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","1","2","3","4","5","6","7","8","9","0","A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"} + for i = 1, n do + str = str .. "" .. strings[math.random(1, #strings)] + end + return str + end + function THREAD.waitFor(name) + --print("No Global table when using luvit integration!") + end + function THREAD.testFor(name, val, sym) + --print("No Global table when using luvit integration!") + end + function THREAD.getCores() + return THREAD.__CORES + end + if os.getOS() == "windows" then + THREAD.__CORES = tonumber(os.getenv("NUMBER_OF_PROCESSORS")) + else + THREAD.__CORES = tonumber(io.popen("nproc --all"):read("*n")) + end + function THREAD.kill() -- trigger the thread destruction + error("Thread was Killed!") + end + -- hmmm if im cleaver I can get this to work... but since data passing isn't going to be a thing its probably not important + function THREAD.sleep(n) + --print("No Global table when using luvit integration!") + end + function THREAD.hold(n) + --print("No Global table when using luvit integration!") + end + -- Step 5 Basic Threads! + local function entry(path, name, func, ...) + local timer = require "timer" + local luvitThread = require "thread" + package.path = path + loadstring(func)(...) + end + function multi:newSystemThread(name, func, ...) + local c = {} + local __self = c + c.name = name + c.Type = "sthread" + c.thread = {} + c.func = string.dump(func) + function c:kill() + -- print("No Global table when using luvit integration!") + end + luvitThread.start(entry, package.path, name, c.func, ...) + return c + end + multi.print("Integrated Luvit!") + multi.integration = {} -- for module creators + multi.integration.GLOBAL = GLOBAL + multi.integration.THREAD = THREAD + require("multi.integration.shared") + -- Start the main mainloop... This allows you to process your multi objects, but the engine on the main thread will be limited to .001 or 1 millisecond sigh... + local interval = + timer.setInterval( + 1, + function() + multi:uManager() + end + ) + return multi +end +return {init = function(threadHandle, timerHandle) + local multi = _INIT(threadHandle, timerHandle) + return GLOBAL, THREAD +end} diff --git a/multi/integration/networkManager/channel.lua b/multi/integration/networkManager/channel.lua new file mode 100644 index 0000000..1bc88b8 --- /dev/null +++ b/multi/integration/networkManager/channel.lua @@ -0,0 +1,11 @@ +_G["__CHANNEL__"] = {} +local channel = {} +channel.__index = channel + +-- Creates/Gets a channel of name +function channel:newChannel(name) + local chan = _G["__CHANNEL__"] + if chan then + + end +end \ No newline at end of file diff --git a/multi/integration/networkManager/childNode.lua b/multi/integration/networkManager/childNode.lua new file mode 100644 index 0000000..e991b70 --- /dev/null +++ b/multi/integration/networkManager/childNode.lua @@ -0,0 +1,23 @@ +local multi, thread = require("multi"):init() +local cmd = require("multi.integration.networkManager.cmds") +local node = require("multi.integration.networkManager.node") +local net = require("net") +local bin = require("bin") +local child = {} +child.__index = child +function multi:newChildNode(cd) + local c = {} + setmetatable(c,child) + local name + if cd then + if cd.name then + name = cd.name + end + c.node = node:new(cd.nodePort or cmd.defaultPort,nil,name) + if cd.managerHost then + cd.managerPort = cd.managerPort or cmd.defaultManagerPort + c.node:registerWithManager(cd.managerHost,cd.managerPort) + end + end + return c +end \ No newline at end of file diff --git a/multi/integration/networkManager/clientSide.lua b/multi/integration/networkManager/clientSide.lua new file mode 100644 index 0000000..4e91615 --- /dev/null +++ b/multi/integration/networkManager/clientSide.lua @@ -0,0 +1,12 @@ +return function(self,data) + local cmd,data = data:match("!(.-)!(.*)") + --print(">",cmd,data) + if cmd == "PONG" then + self:send("!PONG!") + elseif cmd == "CHANNEL" then + -- + elseif cmd == "RETURNS" then + local rets = bin.new(data):getBlock("t") + self.node.master.OnDataReturned:Fire(rets) + end +end \ No newline at end of file diff --git a/multi/integration/networkManager/cmds.lua b/multi/integration/networkManager/cmds.lua new file mode 100644 index 0000000..c6ccba0 --- /dev/null +++ b/multi/integration/networkManager/cmds.lua @@ -0,0 +1,19 @@ +local cmds = { + defaultManagerPort = 0XDE2, + defaultWait = 0X002, + defaultPort = 0X000, -- We will let the OS assign us one + standardSkip = 0X018, + ERROR = 0X000, + PING = 0X001, + PONG = 0X002, + QUEUE = 0X003, + TASK = 0X004, + INITNODE = 0X005, + INITMASTER = 0X006, + GLOBAL = 0X007, + LOAD = 0X008, + CALL = 0X009, + REG = 0X00A, + CONSOLE = 0X00B, +} +return cmds \ No newline at end of file diff --git a/multi/integration/networkManager/extensions.lua b/multi/integration/networkManager/extensions.lua new file mode 100644 index 0000000..0752381 --- /dev/null +++ b/multi/integration/networkManager/extensions.lua @@ -0,0 +1,23 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] \ No newline at end of file diff --git a/multi/integration/networkManager/init.lua b/multi/integration/networkManager/init.lua new file mode 100644 index 0000000..98f9831 --- /dev/null +++ b/multi/integration/networkManager/init.lua @@ -0,0 +1,57 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +local multi, thread = require("multi"):init() +local net = require("net") +local bin = require("bin") +local char = string.char +local byte = string.byte +bin.setBitsInterface(infinabits) +--[[ +--[=[ Pre reqs: +- Network contains nodes +- Network can broadcast/has nodemanager/ is simple and can be scanned + +Outline: +- multi:newMasterNode(connectionDetails) +-- master:setDefaultNode(nodeName) -- Set default node +-- master:newNetworkThread(nodeName,func,...) -- Thread is ran on a random node or the default one if set if nodeName is set to nil +-- master:newNetworkChannel(nodeName) +-- master:sendTo(nodeName,data) +- multi:newNode(connectionDetails) +- multi:newNodeManager(connectionDetails) -- This will be incharge of a lot of data handling +]=] + +local nGLOBAL, nTHREAD = require("multi.integration.networkManager"):init() +local master = multi:newMasterNode() +master:newNetworkThread("simpleNode",function(a,b,c) + print(a,b,c) +end,1,2,3) +]] + +-- The init file should provide the structure that all the other modules build off of +return { + init = function() + -- + end +} \ No newline at end of file diff --git a/multi/integration/networkManager/masterNode.lua b/multi/integration/networkManager/masterNode.lua new file mode 100644 index 0000000..2ea9b1e --- /dev/null +++ b/multi/integration/networkManager/masterNode.lua @@ -0,0 +1,163 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +local multi, thread = require("multi"):init() +local cmd = require("multi.integration.networkManager.cmds") +local node = require("multi.integration.networkManager.node") +local net = require("net") +local bin = require("bin") +local master = {} +master.__index = master +function master:addNode(ip,port) + return node:new(ip,port) +end +function master:getNodesFromBroadcast() + net:newCastedClients("NODE_.+") + net.OnCastedClientInfo(function(client, n, ip, port) + self.nodes[n] = node:new(client) + end) +end +function master:getNodesFromManager(ip,port) + local mn = self.nodes + if not self.manager then + self.manager = net:newTCPClient(ip,port) + if not self.manager then + error("Unable to connect to the node Manager! Is it running? Perhaps the hostname or port is incorrect!") + end + end + self.manager.OnDataRecieved(function(self,data,client) + local cmd = data:match("!(.+)!") + data = data:gsub("!"..cmd.."!","") + if cmd == "NODE" then + local n,h,p = data:match("(.-)|(.-)|(.+)") + mn[n] = node:new(h,tonumber(p)) + end + end) + self.manager:send("!NODES!") +end +function master:setDefaultNode(nodeName) + if self:nodeExists(nodeName) then + self.defaultNode = nodeName + end +end +function master:getRandomNode() + local t = {} + for i,v in pairs(self.nodes) do t[#t+1] = i end + return t[math.random(1,#t)] +end +local netID = 0 +function master:newNetworkThread(nodeName,func,...) + local args = {...} + local dat = bin.new() + local ret + local nID = netID + local conn = multi:newConnection() + multi:newThread(function() + dat:addBlock{ + args = args, + func = func, + id = netID + } + netID = netID + 1 + if type(nodeName) == "function" then + func = nodeName + nodeName = self.defaultNode or self:getRandomNode() + if not func then + error("You must provide a function!") + end + end + self:sendTo(nodeName,"!N_THREAD!"..dat.data) + self.OnDataReturned(function(rets) + if rets.ID == nID then + conn:Fire(unpack(rets.rets)) + end + end) + end) + return conn +end +function master:newNetworkChannel(nodeName) + -- +end +function master:sendTo(nodeName,data) + self:queue("send",nodeName,data) +end +function master:demandNodeExistance(nodeName) + if self.nodes[nodeName] then + return multi.hold(self.nodes[nodeName]:ping().pong) + else + return false + end +end +function master:queue(c,...) + table.insert(self._queue,{c,{...}}) +end +function multi:newMasterNode(cd) + local c = {} + setmetatable(c, master) + c.OnNodeDiscovered = multi:newConnection() + c.OnNodeRemoved = multi:newConnection() + c.OnDataRecieved = multi:newConnection() + c.OnDataReturned = multi:newConnection() + c.defaultNode = "" + c.nodes = {} + setmetatable(c.nodes, + {__newindex = function(t,k,v) + rawset(t,k,v) + v.master = c + c.OnNodeDiscovered:Fire(k,v) + end}) + c._queue = {} + if cd then + if cd.nodeHost then + cd.nodePort = cd.nodePort or cmd.defaultPort + local n,no = c:addNode(cd.nodeHost,cd.nodePort) + if n then + c.nodes[n] = no + end + elseif cd.managerHost then + cd.managerPort = cd.managerPort or cmd.defaultManagerPort + c:getNodesFromManager(cd.managerHost,cd.managerPort) + else + c:getNodesFromBroadcast() + end + else + c:getNodesFromBroadcast() + end + multi:newThread("CMDQueueProcessor",function() + while true do + thread.skip(128) + local data = table.remove(c._queue,1) + if data then + local cmd = data[1] + if cmd == "send" then + local nodeName = data[2][1] + local dat = data[2][2] + c.nodes[nodeName]:send(dat) + end + end + end + end):OnError(function(...) + print(...) + end) + return c +end \ No newline at end of file diff --git a/multi/integration/networkManager/node.lua b/multi/integration/networkManager/node.lua new file mode 100644 index 0000000..79140c8 --- /dev/null +++ b/multi/integration/networkManager/node.lua @@ -0,0 +1,104 @@ +local net = require("net") +local cmd = require("multi.integration.networkManager.cmds") +local multi,thread = require("multi"):init() +local node = {} +node.__index = node +local rand = {} +for i = 65,90 do + rand[#rand+1] = string.char(i) +end +local function randName(n) + local str = {} + for i=1,(n or 10) do + str[#str+1] = rand[math.random(1,#rand)] + end + return table.concat(str) +end +local getNames = thread:newFunction(function(names) + local listen = socket.udp() -- make a new socket + listen:setsockname(net.getLocalIP(), 11111) + listen:settimeout(0) + local data, ip, port = listen:receivefrom() + thread.holdWithin(1,function() + if data then + local n, tp, ip, port = data:match("(%S-)|(%S-)|(%S-):(%d+)") + if n then + names[n]=true + end + end + end) + return multi.NIL +end) +local function setName(ref,name) + if name then + ref.name = "NODE_"..name + ref.connection:broadcast(name) + return + end + local names = {} + getNames(names).wait() -- Prevents duplicate names from spawning! + local name = randName() + while names["NODE_"..name] do + name = randName() + end + ref.name = "NODE_"..name + ref.connection:broadcast(ref.name) +end +node.ServerCode = require("multi.integration.networkManager.serverSide") +node.ClientCode = require("multi.integration.networkManager.clientSide") +function node.random() + return randName(12) +end +function node:registerWithManager(ip,port) + if self.type ~= "server" then return end + if not self.manager then + self.manager = net:newTCPClient(ip,port) + if not self.manager then + error("Unable to connect to the node Manager! Is it running? Perhaps the hostname or port is incorrect!") + end + end + thread:newFunction(function() + thread.hold(function() return self.name end) + self.manager:send("!REG_NODE!"..self.name.."|"..net.getLocalIP().."|"..self.connection.port) + end)() +end +function node:new(host,port,name) + local c = {} + c.links = {} + setmetatable(c,node) + if type(host)=="number" or type(host)=="nil" then + c.connection = net:newTCPServer(host or cmd.defaultPort) + c.connection:enableBinaryMode() + c.type = "server" + c.connection.node = c + c.connection.OnDataRecieved(self.ServerCode) + setName(c) + elseif type(host)=="table" and host.Type == "tcp" then + c.connection = host + c.connection:enableBinaryMode() + c.type = "client" + c.connection.node = c + c.connection.OnDataRecieved(self.ClientCode) + c.name = "MASTER_NODE" + elseif type(host) == "string" and type(port)=="number" then + c.connection = net:newTCPClient(host, port) + c.connection:enableBinaryMode() + c.type = "client" + c.connection.node = c + c.connection.OnDataRecieved(self.ClientCode) + c.name = "MASTER_NODE" + else + error("Invalid arguments!") + end + return c +end +function node:ping() + if self.type ~= "client" then return end + self:send("!PING!") + return {pong=self.connection.OnDataRecieved} +end +function node:send(data) + if self.type ~= "client" then return end + self.connection:send(data) +end +return node \ No newline at end of file diff --git a/multi/integration/networkManager/nodeManager.lua b/multi/integration/networkManager/nodeManager.lua new file mode 100644 index 0000000..d312ac2 --- /dev/null +++ b/multi/integration/networkManager/nodeManager.lua @@ -0,0 +1,25 @@ +local multi, thread = require("multi"):init() +local cmd = require("multi.integration.networkManager.cmds") +local net = require("net") +local bin = require("bin") +local nodes = { -- Testing stuff + +} +function multi:newNodeManager(port) + print("Running node manager on port: "..(port or cmd.defaultManagerPort)) + local server = net:newTCPServer(port or cmd.defaultManagerPort) + server.OnDataRecieved(function(serv, data, client) + local cmd = data:match("!(.+)!") + data = data:gsub("!"..cmd.."!","") + if cmd == "NODES" then + for i,v in ipairs(nodes) do + -- Sample data + serv:send(client, "!NODE!".. v[1].."|"..v[2].."|"..v[3]) + end + elseif cmd == "REG_NODE" then + local name, ip, port = data:match("(.-)|(.-)|(.+)") + table.insert(nodes,{name,ip,port}) + print("Registering Node:",name, ip, port) + end + end) +end \ No newline at end of file diff --git a/multi/integration/networkManager/serverSide.lua b/multi/integration/networkManager/serverSide.lua new file mode 100644 index 0000000..4970142 --- /dev/null +++ b/multi/integration/networkManager/serverSide.lua @@ -0,0 +1,24 @@ +local bin, bits = require("bin").init() +return function(self,data,client) + local cmd,data = data:match("!(.-)!(.*)") + --print("SERVER",cmd,data) + if cmd == "PING" then + self:send(client,"!PONG!") + elseif cmd == "N_THREAD" then + print(1) + local dat = bin.new(data) + print(2) + local t = dat:getBlock("t") + print(3) + local ret = bin.new() + print(4) + ret:addBlock{ID = t.id,rets = {t.func(unpack(t.args))}} + print(5) + print(client,"!RETURNS!"..ret:getData()) + self:send(client,"!RETURNS!"..ret:getData()) + print(6) + elseif cmd == "CHANNEL" then + local dat = bin.new(data):getBlock("t") + + end +end \ No newline at end of file diff --git a/multi/integration/networkManager/threads.lua b/multi/integration/networkManager/threads.lua new file mode 100644 index 0000000..0752381 --- /dev/null +++ b/multi/integration/networkManager/threads.lua @@ -0,0 +1,23 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] \ No newline at end of file diff --git a/multi/integration/networkManager/utils.lua b/multi/integration/networkManager/utils.lua new file mode 100644 index 0000000..2591e38 --- /dev/null +++ b/multi/integration/networkManager/utils.lua @@ -0,0 +1,4 @@ +local bin = require("bin") +local utils = {} +-- Will contain data that handles sterilizing and managing data +return utils \ No newline at end of file diff --git a/multi/integration/shared.lua b/multi/integration/shared.lua new file mode 100644 index 0000000..4174cf9 --- /dev/null +++ b/multi/integration/shared.lua @@ -0,0 +1,304 @@ +--[[ +MIT License + +Copyright (c) 2020 Ryan Ward + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sub-license, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +]] +function multi:newSystemThreadedConnection(name, protect) + local c = {} + c.name = name or error("You must provide a name for the connection object!") + c.protect = protect or false + c.idle = nil + local sThread = multi.integration.THREAD + local GLOBAL = multi.integration.GLOBAL + local connSync = multi:newSystemThreadedQueue(c.name .. "_CONN_SYNC") + local connFire = multi:newSystemThreadedQueue(c.name .. "_CONN_FIRE") + function c:init() + local multi = require("multi") + if love then -- lets make sure we don't reference up-values if using love2d + GLOBAL = _G.GLOBAL + sThread = _G.sThread + end + local conn = {} + conn.obj = multi:newConnection() + setmetatable( + conn, + { + __call = function(self, ...) + return self:connect(...) + end + } + ) + local ID = sThread.getID() + local sync = sThread.waitFor(self.name .. "_CONN_SYNC"):init() + local fire = sThread.waitFor(self.name .. "_CONN_FIRE"):init() + local connections = {} + if not multi.isMainThread then + connections = {0} + end + sync:push {"INIT", ID} -- Register this as an active connection! + function conn:connect(func) + return self.obj(func) + end + function conn:holdUT(n) + self.obj:holdUT(n) + end + function conn:Remove() + self.obj:Remove() + end + function conn:Fire(...) + for i = 1, #connections do + fire:push {connections[i], ID, {...}} + end + end + function conn:FireTo(to, ...) + local good = false + for i = 1, #connections do + if connections[i] == to then + good = true + break + end + end + if not good then + return multi.print("NonExisting Connection!") + end + fire:push {to, ID, {...}} + end + -- FIRE {TO,FROM,{ARGS}} + local data + local clock = os.clock + conn.OnConnectionAdded = multi:newConnection() + multi:newLoop( + function() + data = fire:peek() + if type(data) == "table" and data[1] == ID then + if data[2] == ID and conn.IgnoreSelf then + fire:pop() + return + end + fire:pop() + conn.obj:Fire(unpack(data[3])) + end + data = sync:peek() + if data ~= nil and data[1] == "SYNCA" and data[2] == ID then + sync:pop() + multi.nextStep( + function() + conn.OnConnectionAdded:Fire(data[3]) + end + ) + table.insert(connections, data[3]) + end + if type(data) == "table" and data[1] == "SYNCR" and data[2] == ID then + sync:pop() + for i = 1, #connections do + if connections[i] == data[3] then + table.remove(connections, i) + end + end + end + end + ):setName("STConn.syncer") + return conn + end + local cleanUp = {} + multi.OnSystemThreadDied( + function(ThreadID) + for i = 1, #syncs do + connSync:push {"SYNCR", syncs[i], ThreadID} + end + cleanUp[ThreadID] = true + end + ) + multi:newThread( + c.name .. " Connection-Handler", + function() + local data + local clock = os.clock + local syncs = {} + while true do + if not c.idle then + thread.sleep(.5) + else + if clock() - c.idle >= 15 then + c.idle = nil + end + thread.skip() + end + data = connSync:peek() + if data ~= nil and data[1] == "INIT" then + connSync:pop() + c.idle = clock() + table.insert(syncs, data[2]) + for i = 1, #syncs do + connSync:push {"SYNCA", syncs[i], data[2]} + end + end + data = connFire:peek() + if data ~= nil and cleanUp[data[1]] then + local meh = data[1] + connFire:pop() -- lets remove dead thread stuff + multi:newAlarm(15):OnRing( + function(a) + cleanUp[meh] = nil + end + ) + end + end + end + ) + GLOBAL[c.name] = c + return c +end +function multi:SystemThreadedBenchmark(n) + n = n or 1 + local cores = multi.integration.THREAD.getCores() + local queue = multi:newSystemThreadedQueue("THREAD_BENCH_QUEUE"):init() + local sThread = multi.integration.THREAD + local GLOBAL = multi.integration.GLOBAL + local c = {} + for i = 1, cores do + multi:newSystemThread( + "STHREAD_BENCH", + function(n) + local multi = require("multi") + if multi:getPlatform() == "love2d" then + GLOBAL = _G.GLOBAL + sThread = _G.sThread + end -- we cannot have upvalues... in love2d globals, not locals must be used + queue = sThread.waitFor("THREAD_BENCH_QUEUE"):init() -- always wait for when looking for a variable at the start of the thread! + multi:benchMark(n):OnBench( + function(self, count) + queue:push(count) + sThread.kill() + error("Thread was killed!") + end + ) + multi:mainloop() + end, + n + ) + end + multi:newThread( + "THREAD_BENCH", + function() + local count = 0 + local cc = 0 + while true do + thread.skip(1) + local dat = queue:pop() + if dat then + cc = cc + 1 + count = count + dat + if cc == cores then + c.OnBench:Fire(count) + thread.kill() + end + end + end + end + ) + c.OnBench = multi:newConnection() + return c +end +function multi:newSystemThreadedConsole(name) + local c = {} + c.name = name + local sThread = multi.integration.THREAD + local GLOBAL = multi.integration.GLOBAL + function c:init() + _G.__Needs_Multi = true + local multi = require("multi") + if multi:getPlatform() == "love2d" then + GLOBAL = _G.GLOBAL + sThread = _G.sThread + end + local cc = {} + if multi.isMainThread then + if GLOBAL["__SYSTEM_CONSOLE__"] then + cc.stream = sThread.waitFor("__SYSTEM_CONSOLE__"):init() + else + cc.stream = multi:newSystemThreadedQueue("__SYSTEM_CONSOLE__"):init() + multi:newLoop( + function() + local data = cc.stream:pop() + if data then + local dat = table.remove(data, 1) + if dat == "w" then + io.write(unpack(data)) + elseif dat == "p" then + print(unpack(data)) + end + end + end + ):setName("ST.consoleSyncer") + end + else + cc.stream = sThread.waitFor("__SYSTEM_CONSOLE__"):init() + end + function cc:write(msg) + self.stream:push({"w", tostring(msg)}) + end + function cc:print(...) + local tab = {...} + for i = 1, #tab do + tab[i] = tostring(tab[i]) + end + self.stream:push({"p", unpack(tab)}) + end + return cc + end + GLOBAL[c.name] = c + return c +end +function multi:newSystemThreadedExecute(cmd) + local c = {} + local GLOBAL = multi.integration.GLOBAL -- set up locals incase we are using lanes + local sThread = multi.integration.THREAD -- set up locals incase we are using lanes + local name = "Execute_Thread" .. multi.randomString(16) + c.name = name + GLOBAL[name .. "CMD"] = cmd + multi:newSystemThread( + name, + function() + if love then -- lets make sure we don't reference upvalues if using love2d + GLOBAL = _G.GLOBAL + sThread = _G.sThread + name = __THREADNAME__ -- global data same as the name we used in this functions creation + end -- Lanes should take the local upvalues ^^^ + cmd = sThread.waitFor(name .. "CMD") + local ret = os.execute(cmd) + GLOBAL[name .. "R"] = ret + end + ) + c.OnCMDFinished = multi:newConnection() + c.looper = + multi:newLoop( + function(self) + local ret = GLOBAL[self.link.name .. "R"] + if ret then + self.link.OnCMDFinished:Fire(ret) + self:Destroy() + end + end + ) + c.looper.link = c + return c +end diff --git a/pages/favs.lua b/pages/favs.lua new file mode 100644 index 0000000..aa80b6b --- /dev/null +++ b/pages/favs.lua @@ -0,0 +1,7 @@ +local function init(page) + page.Color = Color.new("7c2d5b") + return page +end +return { + init = init +} \ No newline at end of file diff --git a/pages/search.lua b/pages/search.lua new file mode 100644 index 0000000..0f2479c --- /dev/null +++ b/pages/search.lua @@ -0,0 +1,28 @@ +local mangaReader = require("manga") +local multi,thread = require("multi"):init() +local function init(page,workspace) + local nav = page:newFrame(10,10,-20,40,0,0,1) + nav.Color = theme.header + nav:setRoundness(5,5,60) + local search = nav:newTextButton("Search","Search",5,5,60,-10,0,0,0,1) + search.Color = theme.button--Color.new("2196F3") + search:fitFont() + local func = thread:newFunction(function() + mangaReader.storeList(mangaReader.init()) + local title = mangaReader.getList()[643] + local manga = mangaReader.getManga(title) + local page = mangaReader.getPages(manga,1) + + end) + search:OnReleased(function() + func() + end) + local bar = nav:newTextBox("","",70,5,-75,-10,0,0,1,1) + bar:fitFont() + bar.Color = theme.input + bar.XTween = 1 + return page +end +return { + init = init +} \ No newline at end of file