├── LICENSE ├── README.md ├── assets ├── cube.png ├── icon.png ├── screenshot.png └── verdana.ttf ├── conf.lua ├── interface ├── collisions.lua ├── interface.lua ├── roundrect.lua └── scrollbar.lua └── utilities ├── copy.lua └── recursive.lua /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Pablo Mayobre 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Cube 2 | ==== 3 | ![Cube](https://github.com/Positive07/cube/blob/master/assets/cube.png) 4 | 5 | Cube is an application made for [LÖVE](http://www.love2d.org), that is capable of running .love files 6 | 7 | This allows you to modify the .love file behavior anyway you want without modifying the file itself. 8 | 9 | The primary objetive of this project is to support a wide variety of LÖVE versions so that anyone can run any .love file in the latest version of LÖVE even if the file was designed for an older version itself. 10 | 11 | This also means that game authors (Lovers) wont need to reimplement the game for the lastest LÖVE version. 12 | 13 | Other projects like [Vapor](https://www.github.com/josefnpat/Vapor) will benefit from it since they will able to support more Games 14 | ![Cube interface](https://github.com/Positive07/cube/blob/master/assets/screenshot.png) 15 | ###Support 16 | 17 | We are in need of support, this project has many benefits like the sandbox, and the compatibility but it also brings troubles, so if you can help with any of this things please dont doubt to make a pull request or send me a PM 18 | 19 | There is a somewhat complete list of missing features and needed things in this [Trello board](https://trello.com/b/LB5l35bS/cube) 20 | 21 | If you find an issue or bug dont doubt on reporting it, also if you want to give support in any other way send me a message 22 | 23 | ###Structure 24 | 25 | This is code is made so that it can be useful for other projects, this means that it doesnt use a monolithic structure, it has a structure so that anyone can come and add things or take things. 26 | 27 | The structure is the following: 28 | 29 | * `assets`: This folders contains the assets of Cube, we try to use a minimal set of assets 30 | * `interface`: This is a folder containing the interface, like the drawing operations, the listing of files and folders, etc. 31 | * `run`: This folders contains fun things, this is what reads .love files and interprets .lua files, handles the environment recognices the version and modifies the files 32 | * `versions`: This folder contains the different LÖVE versions in separate folders, each folder contains a .lua file per LOVE module (`audio.lua`, `graphics.lua`, etc), and a `init.lua` file that groups them together 33 | * `utilities`: This are additional functions that lets Cube do neat things like copying files to the save directory and such 34 | 35 | We will try to make the API simple so that other projects can use the `run` and the `versions` folders without the others. 36 | 37 | ###License 38 | 39 | This project is Licensed under the MIT License, this means it is Open Source, you can do whatever you want with it (even sell it as part of your project), giving appropiate credits, and knowing that this is given without any warranty, this may be buggy and may blow your computer up so use it under your own risk, dont blame me 40 | -------------------------------------------------------------------------------- /assets/cube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pablomayobre/cube/d5389fe9fb37ad38b28e26fa180864599c586f23/assets/cube.png -------------------------------------------------------------------------------- /assets/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pablomayobre/cube/d5389fe9fb37ad38b28e26fa180864599c586f23/assets/icon.png -------------------------------------------------------------------------------- /assets/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pablomayobre/cube/d5389fe9fb37ad38b28e26fa180864599c586f23/assets/screenshot.png -------------------------------------------------------------------------------- /assets/verdana.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pablomayobre/cube/d5389fe9fb37ad38b28e26fa180864599c586f23/assets/verdana.ttf -------------------------------------------------------------------------------- /conf.lua: -------------------------------------------------------------------------------- 1 | love.conf = function (t) 2 | t.identity = "Cube" 3 | t.window.title = "Cube" 4 | t.author = "Positive07" 5 | t.url = "https://www.github.com/Positive07/cube" 6 | t.license = "MIT License" 7 | t.version = "0.9.1" 8 | 9 | t.console = true 10 | t.window.icon = "assets/icon.png" 11 | t.window.width = 600 12 | t.window.height = 500 13 | t.window.minwidth = 600 14 | t.window.minheight = 500 15 | t.window.borderless = false 16 | t.window.resizable = false 17 | 18 | t.window.fullscreen = false 19 | t.window.fullscreentype = "desktop" 20 | t.window.vsync = true 21 | t.window.fsaa = 0 22 | t.window.display = 1 23 | t.window.highdpi = false 24 | t.window.srgb = false 25 | t.screen = t.window 26 | end -------------------------------------------------------------------------------- /interface/collisions.lua: -------------------------------------------------------------------------------- 1 | local collisions = { 2 | --Checks if a point is within a box 3 | --Arguments: 4 | -- x = x position of the point 5 | -- y = y position of the point 6 | -- xb = x position of the box 7 | -- yb = y position of the box 8 | -- wb = width of the box 9 | -- hb = height of the box 10 | --Returns: true if the point is inside the box, false if not 11 | box = function (x, y, xb, yb, wb, hb) 12 | return xb < x and x < (xb + wb) and yb < y and y < (yb + hb) 13 | end; 14 | --Checks if a point is within a circle 15 | --Arguments: 16 | -- x = x position of the point 17 | -- y = y position of the point 18 | -- xc = x position of the circle 19 | -- yc = y position of the circle 20 | -- rc = radius of the circle 21 | --Returns: true if the point is inside the circle, false if not 22 | circle = function (x, y, xc, yc, rc) 23 | local dx = x - xc 24 | local dy = y - yc 25 | return dx^2 + dy^2 < rc ^ 2 26 | end; 27 | --Checks collisions between two rectangles 28 | --Arguments: 29 | -- x1 = x position of the first box 30 | -- y1 = y position of the first box 31 | -- w1 = width of the first box 32 | -- h1 = height of the first box 33 | -- x2 = x position of the second box 34 | -- y2 = y position of the second box 35 | -- w2 = width of the second box 36 | -- h2 = height of the second box 37 | --Returns: true if the boxes collide false if not 38 | boxes = function (x1, y1, w1, h1, x2, y2, w2, h2) 39 | return x1 < (x2 + w2) and x2 < (x1 + w1) and y1 < (y2 + h2) and y2 < (y1 + h1) 40 | end; 41 | --Checks collisions between two circles 42 | --Arguments: 43 | -- ax = x position of the first circle 44 | -- ay = y position of the first circle 45 | -- ar = radius of the first circle 46 | -- bx = x position of the second circle 47 | -- by = y position of the second circle 48 | -- br = radius of the second circle 49 | --Returns: true if the circles collide false if not 50 | circles = function (ax, ay, ar, bx, by, br) 51 | local dx = bx - ax 52 | local dy = by - ay 53 | return dx^2 + dy^2 < (ar + br)^2 54 | end 55 | } 56 | return collisions -------------------------------------------------------------------------------- /interface/interface.lua: -------------------------------------------------------------------------------- 1 | local rounded = require "interface.roundrect" 2 | local scrollbar = require "interface.scrollbar" 3 | local recursive = require "utilities.recursive" 4 | local collisions = require "interface.collisions" 5 | 6 | local w,h = love.window.getDimensions() 7 | local cube = love.graphics.newImage("assets/cube.png") 8 | 9 | local display = { 10 | folder = {"Games"}, 11 | folders = {}, 12 | files = {}, 13 | lineheight = 18, 14 | font = love.graphics.newFont("assets/verdana.ttf",16), --Didnt know what font to use so... yeah VERDANA!! 15 | half = 3, 16 | reload = false 17 | } 18 | 19 | local run = function (file) 20 | if string.match(file,"[/\\]*([%w,%s]*%.love)$") then 21 | execution.run = true 22 | execution.firsttime = true 23 | love.filesystem.mount(table.concat(display.folder,"/").."/"..file,execution.folder) 24 | display.folder = {execution.folder} 25 | execution.file = table.concat(display.folder,"/").."/"..file 26 | display.reload = true 27 | else 28 | print "false" 29 | end 30 | end 31 | local open = function (file) 32 | display.folder[#display.folder + 1] = file 33 | display.reload = true 34 | end 35 | 36 | display.folders, display.files = recursive(table.concat(display.folder,"/")) 37 | display.height = (#display.folders + #display.files) * display.lineheight 38 | scrollbar.update(display.height) 39 | 40 | local interface = { 41 | update = function (reload) 42 | if reload or display.reload then 43 | display.folders, display.files = recursive(table.concat(display.folder,"/")) 44 | display.height = (#display.folders + #display.files) * display.lineheight 45 | scrollbar.update(display.height) 46 | display.reload = false 47 | else 48 | scrollbar.update() 49 | end 50 | end; 51 | mousepressed = function (x,y,b) 52 | scrollbar.mousepressed(x,y,b) 53 | if b == "l" then 54 | local box = scrollbar.area 55 | if collisions.box(x,y,box.x,box.y,box.width,box.height) then 56 | local y = y - box.y + scrollbar.content.y 57 | index = math.ceil(y / 18) 58 | if index <= (#display.folders + #display.files) then 59 | if index > #display.folders then 60 | run(display.files[index - #display.folders]) 61 | else 62 | open(display.folders[index]) 63 | end 64 | end 65 | elseif collisions.box(x,y,scrollbar.area.x,190,25 + 550 - scrollbar.area.x,20) then 66 | local xb = scrollbar.area.x 67 | local newfolder = {} 68 | for k,v in ipairs(display.folder) do 69 | local width = display.font:getWidth(v) + 14 70 | if k == #display.folder then 71 | return 72 | end 73 | if x < (width + xb) and x > xb then 74 | newfolder[#newfolder + 1] = v 75 | display.folder = newfolder 76 | display.reload = true 77 | return 78 | else 79 | newfolder[#newfolder + 1] = v 80 | xb = xb + width + 5 81 | end 82 | end 83 | end 84 | end 85 | end; 86 | mousereleased = function (x,y,b) 87 | scrollbar.mousereleased(x,y,b) 88 | end; 89 | keypressed = function (k,r) 90 | if k == "backspace" then 91 | if #display.folder > 1 then 92 | display.folder[#display.folder] = nil 93 | display.reload = true 94 | else 95 | display.folder = {"Games"} 96 | display.reload = true 97 | if execution.file then love.filesystem.unmount(execution.file) end 98 | end 99 | elseif k == "up" then 100 | scrollbar.moveup() 101 | elseif k == "pageup" then 102 | for i=0,5 do 103 | scrollbar.moveup() 104 | end 105 | elseif k == "down" then 106 | scrollbar.movedown() 107 | elseif k == "pagedown" then 108 | for i=0,5 do 109 | scrollbar.movedown() 110 | end 111 | elseif k == "escape" then 112 | love.event.quit() 113 | elseif k == "lalt" or k == "ralt" then 114 | scrollbar.step = 1 115 | end 116 | end; 117 | keyreleased = function (k,r) 118 | if k == "lalt" or k == "ralt" then 119 | scrollbar.step = 5 120 | end 121 | end; 122 | draw = function (progress) 123 | local lg = love.graphics 124 | 125 | lg.setFont(display.font) 126 | 127 | lg.setColor(255,255,255,255) 128 | lg.setBackgroundColor(255,255,255) 129 | 130 | lg.draw(cube,0,0) --Title 131 | 132 | --Main square 133 | lg.setColor(220,220,255) 134 | lg.rectangle("fill",25,185,550,280) 135 | lg.setColor(155,155,255) 136 | lg.rectangle("line",25,185,550,280) 137 | --Progress bar 138 | lg.setColor(234,196,196) 139 | lg.rectangle("fill",0,h - 15,600,15) 140 | lg.setColor(186,140,119) 141 | lg.rectangle("line",0,h - 15,600,15) 142 | --Separation Line 143 | lg.setColor(0,0,109) 144 | lg.line(35,215,565,215) 145 | --Folder indicators 146 | lg.setScissor(25,185,550,30) 147 | local x = scrollbar.area.x 148 | for k,v in ipairs(display.folder) do 149 | local width = display.font:getWidth(v) + 14 150 | lg.setColor(240,240,255) 151 | rounded("fill",x,190,width,20,5,5) 152 | lg.setColor(96,103,210) 153 | rounded("line",x,190,width,20,5,5) 154 | lg.setColor(0,0,109) 155 | lg.print(v,x + 7,190) 156 | x = x + width + 5 157 | end 158 | lg.setScissor() 159 | --Scrollbar 160 | scrollbar.draw() 161 | --Progress Indicator 162 | if progress >= 0 then 163 | lg.setColor(255,0,0,128) 164 | lg.rectangle("fill",0,h - 15,w * (progress or 0)/100,15) 165 | end 166 | --Scrolling area (files and folders) 167 | lg.setScissor(scrollbar.area.x,scrollbar.area.y,scrollbar.area.width,scrollbar.area.height) 168 | lg.push() 169 | lg.translate(scrollbar.area.x,scrollbar.area.y - scrollbar.content.y) 170 | lg.setColor(0,0,109) 171 | for k,v in ipairs(display.folders) do 172 | lg.print("- "..v,0,(k-1)*display.lineheight + (k>1 and display.half or 0)) 173 | end 174 | for k,v in ipairs(display.files) do 175 | lg.print(v,0,(#display.folders + k-1)*display.lineheight + display.half) 176 | end 177 | love.graphics.pop() 178 | love.graphics.setScissor() 179 | end; 180 | } 181 | 182 | return interface -------------------------------------------------------------------------------- /interface/roundrect.lua: -------------------------------------------------------------------------------- 1 | return function (mode, x, y, width, height, xround, yround, num) 2 | if not num then bl,br,tr,tl = true, true, true, true else 3 | local s = 0 4 | if num%2 - s == 1 then bl = true; s = s + 1 else bl = false end 5 | if num%4 - s == 2 then br = true; s = s + 2 else br = false end 6 | if num%8 - s == 4 then tr = true; s = s + 4 else tr = false end 7 | if num%16 - s == 8 then tl = true else tl = false end 8 | end 9 | local points, precision = {}, (xround + yround) 10 | local hP, sin, cos = .5*math.pi, math.sin, math.cos 11 | if xround > width*.5 then xround = width*.5 end 12 | if yround > height*.5 then yround = height*.5 end 13 | local X1, Y1, X2, Y2 = x + xround, y + yround, x + width - xround, y + height - yround 14 | if tr then 15 | for i = 0, precision do 16 | local a = (i/precision-1)*hP 17 | points[#points+1] = X2 + xround*cos(a) 18 | points[#points+1] = Y1 + yround*sin(a) 19 | end 20 | else 21 | points[#points+1] = x + width 22 | points[#points+1] = y 23 | end 24 | if br then 25 | for i = 0, precision do 26 | local a = (i/precision)*hP 27 | points[#points+1] = X2 + xround*cos(a) 28 | points[#points+1] = Y2 + yround*sin(a) 29 | end 30 | else 31 | points[#points+1] = x + width 32 | points[#points+1] = y + height 33 | end 34 | if bl then 35 | for i = 0, precision do 36 | local a = (i/precision+1)*hP 37 | points[#points+1] = X1 + xround*cos(a) 38 | points[#points+1] = Y2 + yround*sin(a) 39 | end 40 | else 41 | points[#points+1] = x 42 | points[#points+1] = y + height 43 | end 44 | if tl then 45 | for i = 0, precision do 46 | local a = (i/precision+2)*hP 47 | points[#points+1] = X1 + xround*cos(a) 48 | points[#points+1] = Y1 + yround*sin(a) 49 | end 50 | else 51 | points[#points+1] = x 52 | points[#points+1] = y 53 | end 54 | love.graphics.polygon(mode, unpack(points)) 55 | end 56 | 57 | 58 | -------------------------------------------------------------------------------- /interface/scrollbar.lua: -------------------------------------------------------------------------------- 1 | local collisions = require "interface.collisions" 2 | local rounded = require "interface.roundrect" 3 | local scrollbar = { 4 | step = 5, 5 | color = {0,0,255,128}, 6 | area = { 7 | height = 228, 8 | width = 520, 9 | x = 38, 10 | y = 224, 11 | }; 12 | scroll = { 13 | height = 218, 14 | width = 12, 15 | x = 555, 16 | y = 229, 17 | }; 18 | up = { 19 | height = 8, 20 | width = 12, 21 | x = 555, 22 | y = 221, 23 | polygon = function (self) 24 | return { 25 | self.x, self.y + self.height, 26 | self.x + self.width, self.y + self.height, 27 | self.x + self.width/2, self.y 28 | } 29 | end, 30 | }; 31 | down = { 32 | height = 8, 33 | width = 12, 34 | x = 555, 35 | y = 447, 36 | polygon = function (self) 37 | return { 38 | self.x,self.y, 39 | self.x + self.width, self.y, 40 | self.x + self.width/2, self.y + self.height 41 | } 42 | end, 43 | }; 44 | handle = { 45 | click = false, 46 | realy = 229, 47 | x = 555, 48 | y = 0, 49 | height = 0, 50 | width = 12, 51 | }; 52 | click = { 53 | x = 0, 54 | y = 0 55 | }; 56 | content = { 57 | height = 0, 58 | y = 0, 59 | } 60 | } 61 | scrollbar.moveup = function () 62 | scrollbar.handle.y = math.max(scrollbar.handle.y - scrollbar.step, 0) 63 | end 64 | scrollbar.movedown = function () 65 | scrollbar.handle.y = math.min(scrollbar.handle.y + scrollbar.step, scrollbar.scroll.height - scrollbar.handle.height) 66 | end 67 | scrollbar.update = function (totalheight) 68 | if totalheight then 69 | local max = math.max 70 | scrollbar.content.height = totalheight > scrollbar.area.height and totalheight or scrollbar.area.height 71 | scrollbar.content.y = 0 72 | scrollbar.handle.y = 0 73 | scrollbar.handle.height = max(scrollbar.area.height * scrollbar.scroll.height / scrollbar.content.height, 30) 74 | end 75 | 76 | local mx,my = love.mouse.getPosition() 77 | if scrollbar.handle.click then 78 | local max,min = math.max, math.min 79 | local newy = scrollbar.click.currenty + (my - scrollbar.click.y) 80 | local maxy = scrollbar.scroll.height - scrollbar.handle.height 81 | scrollbar.handle.y = max(min(newy, maxy),0) 82 | elseif scrollbar.up.pressed then 83 | --Here I wanted to implement some kind of acceleration 84 | elseif scrollbar.down.pressed then 85 | --Here I wanted to implement some kind of acceleration 86 | end 87 | 88 | local height = (scrollbar.content.height - scrollbar.area.height) 89 | local contah = (scrollbar.scroll.height - scrollbar.handle.height) 90 | local radio = contah > 0 and height / contah or 0 91 | 92 | scrollbar.content.y = scrollbar.handle.y * radio 93 | 94 | end 95 | scrollbar.mousepressed = function (x,y,b) 96 | if scrollbar.handle.height < scrollbar.scroll.height then 97 | local max,min = math.max,math.min 98 | if b == "l" then 99 | local xb,yb = scrollbar.scroll.x, scrollbar.handle.realy + scrollbar.handle.y 100 | local wb,hb = scrollbar.scroll.width, scrollbar.handle.height 101 | local yc,hc = scrollbar.scroll.y, scrollbar.scroll.height 102 | 103 | local ux, uy = scrollbar.up.x, scrollbar.up.y 104 | local uh, uw = scrollbar.up.height, scrollbar.up.width 105 | local dx, dy = scrollbar.down.x, scrollbar.down.y 106 | local dh, dw = scrollbar.down.height, scrollbar.down.width 107 | if collisions.box(x,y,xb,yb,wb,hb) then 108 | scrollbar.handle.click = true 109 | scrollbar.click = {x = x, y = y, currenty = scrollbar.handle.y} 110 | elseif collisions.box(x,y,xb,yc + 10,wb,hc - 20) then 111 | if y > yb then 112 | scrollbar.handle.y = y - scrollbar.handle.realy - scrollbar.handle.height + 10 113 | else 114 | scrollbar.handle.y = y - scrollbar.handle.realy - 10 115 | end 116 | scrollbar.handle.click = true 117 | scrollbar.click = {x = x, y = y, currenty = scrollbar.handle.y} 118 | elseif collisions.box(x,y,ux,uy,uw,uh) then 119 | scrollbar.handle.y = max(scrollbar.handle.y - scrollbar.step, 0) 120 | scrollbar.up.pressed = true 121 | elseif collisions.box(x,y,dx,dy,dw,dh) then 122 | scrollbar.handle.y = min(scrollbar.handle.y + scrollbar.step, scrollbar.scroll.height - scrollbar.handle.height) 123 | scrollbar.down.pressed = true 124 | end 125 | end 126 | if b == "wu" then 127 | scrollbar.handle.y = max(scrollbar.handle.y - scrollbar.step, 0) 128 | elseif b == "wd" then 129 | scrollbar.handle.y = min(scrollbar.handle.y + scrollbar.step, scrollbar.scroll.height - scrollbar.handle.height) 130 | end 131 | end 132 | end 133 | scrollbar.mousereleased = function (x,y,b) 134 | if b == "l" then 135 | scrollbar.handle.click = false 136 | scrollbar.up.pressed = false 137 | scrollbar.down.pressed = false 138 | end 139 | end 140 | scrollbar.draw = function () 141 | if scrollbar.handle.height < scrollbar.scroll.height then 142 | local lg = love.graphics 143 | lg.setColor(scrollbar.color) 144 | lg.polygon("fill",scrollbar.up.polygon(scrollbar.up)) 145 | lg.polygon("line",scrollbar.up.polygon(scrollbar.up)) 146 | lg.polygon("fill",scrollbar.down.polygon(scrollbar.down)) 147 | lg.polygon("line",scrollbar.down.polygon(scrollbar.down)) 148 | rounded("fill",scrollbar.handle.x,scrollbar.handle.realy + scrollbar.handle.y,scrollbar.handle.width,scrollbar.handle.height,5,5) 149 | rounded("line",scrollbar.handle.x,scrollbar.handle.realy + scrollbar.handle.y,scrollbar.handle.width,scrollbar.handle.height,5,5) 150 | end 151 | end 152 | return scrollbar -------------------------------------------------------------------------------- /utilities/copy.lua: -------------------------------------------------------------------------------- 1 | require "love.filesystem" --We need filesystem 2 | 3 | local folder = ... --We get which folder we are going to save the files in 4 | local prog = love.thread.getChannel("progress") --Channel used to report progress 5 | local cone = love.thread.getChannel("conection") --Channel used to know which files we need to copy 6 | 7 | local function copy (path, directory) 8 | if not path or path == "" then --We dont want empty paths 9 | return false, "The specified path is nil or empty" 10 | end 11 | directory = directory and directory.."/" or "" --we need to save things to a directory so we add the backslash 12 | 13 | if not love.filesystem.exists(directory) then --If the directory doesnt exist 14 | assert(love.filesystem.createDirectory(directory)) --We create it 15 | end 16 | 17 | if path:find(".+%.love$") then --you need to path a .love file or else we wont copy the file 18 | --Supplied a love file so we binary copy it 19 | local file = assert(io.open(path,"rb")) --open file as binary 20 | 21 | local current = file:seek() -- get current position 22 | local size = file:seek("end") -- get file size 23 | file:seek("set", current) -- restore position 24 | current = nil -- delete the current variable 25 | 26 | local name = string.match(path,"[/\\]*([%w,%s]*%.love)$") --we get the name and extension of the file from the path 27 | 28 | local destiny = assert(love.filesystem.newFile(directory..name, "w")) --we create a new file with the same name under the appdata dir 29 | 30 | local chunk = 1024 --we are gonna copy it 1KB at a time 31 | local chunks = math.ceil(size/chunk) --number of repetitions needed to get the whole file 32 | local lastchunk = size%chunk --last chunk doesnt need to be full 33 | 34 | for i = 1, chunks do --until we copy everything 35 | assert(destiny:write(file:read(i == chunks and lastchunk or chunk))) --we read the origin and write in the destiny 36 | prog:push(destiny:getSize()/size*100) 37 | end 38 | 39 | destiny:close() --we close both files 40 | file:close() 41 | return true, directory..name --We return where we placed the final file 42 | else 43 | return false, "Currently copy doesn't support other file types or folders, you can copy them manually" 44 | end 45 | end 46 | 47 | while true do 48 | local msg = cone:demand() 49 | if msg == "break" then 50 | prog:push("finished") 51 | break 52 | else 53 | assert(copy(msg,folder)) 54 | end 55 | end -------------------------------------------------------------------------------- /utilities/recursive.lua: -------------------------------------------------------------------------------- 1 | return function (folder) 2 | local lfs = love.filesystem 3 | local filesTable = lfs.getDirectoryItems(folder) 4 | 5 | local folders = {} 6 | local files = {} 7 | 8 | for i,v in ipairs(filesTable) do 9 | local file = folder.."/"..v 10 | if lfs.isFile(file) then 11 | files[#files + 1] = v 12 | elseif lfs.isDirectory(file) then 13 | folders[#folders + 1] = v 14 | end 15 | end 16 | 17 | table.sort(files) 18 | table.sort(folders) 19 | 20 | return folders, files 21 | end --------------------------------------------------------------------------------