From e46bc230a6ecef40329d64bcb32ac1c73557f8f9 Mon Sep 17 00:00:00 2001 From: Er2 Date: Thu, 7 Jul 2022 19:37:27 +0300 Subject: [PATCH] Love Loader v2.1 Bugfixes. Removed cross-engine support, only Love2D. Added filesystem and keyboard modules in LibLL. Remade input handling in skins. Files and broken folders are not shows in game list. Add MOBILE variable and auto-fullscreen on mobile phones. --- .gitignore | 2 ++ lib/chroot.lua | 33 ++++++++++++------ lib/fs.lua | 20 +++++++++++ lib/keyb.lua | 81 +++++++++++++++++++++++++++++++++++++++++++++ lib/load.lua | 42 +++++++++++++++++++++++ lib/love/chroot.lua | 33 ------------------ lib/love/load.lua | 28 ---------------- lib/main.lua | 18 +++++----- ll-min.lua | 11 +++++- luapack.lua | 1 + readme.md | 32 +++++++++++++++--- skins/gui.lua | 46 +++++++------------------ skins/psp.lua | 48 +++++++++------------------ 13 files changed, 242 insertions(+), 153 deletions(-) create mode 100644 lib/fs.lua create mode 100644 lib/keyb.lua delete mode 100644 lib/love/chroot.lua delete mode 100644 lib/love/load.lua diff --git a/.gitignore b/.gitignore index 05ba253..81b0c56 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ dev build/ games/* +!games/.gitkeep + diff --git a/lib/chroot.lua b/lib/chroot.lua index 4d09f14..f0abb42 100644 --- a/lib/chroot.lua +++ b/lib/chroot.lua @@ -3,23 +3,34 @@ return function(ll) ll.mdir = nil ll.mgme = nil +local ffi = require 'ffi' +ffi.cdef [[ + int PHYSFS_mount(const char *, const char *, int); + int PHYSFS_unmount(const char *); +]] + +local baseReq = '?.lua;?/init.lua;' function ll.mount(gme) - --[[ - ll.mdir = gme.base .. gme.dir - ll.mgme = gme - --[=[ - if gme.main then - print('Load', ll.mdir ..'/'.. gme.main) - end - --]=] - --]] - error 'unimplemented' + local mdir = gme.base .. gme.dir + ll.mgme = gme + + love.filesystem.setRequirePath('' + .. mdir .. '/?.lua;' + .. mdir .. '/?/init.lua;' + .. baseReq + ) + -- FIXME: Bug may appear in Linux. Recompile Love2D or use official PPA. + if ffi.C.PHYSFS_mount(mdir, '/', 0) == 0 + then error('Cannot mount '..mdir) + love.filesystem.setRequirePath(baseReq) + else ll.mdir = mdir + end end function ll.umount() if ll.mdir ~= nil then + ffi.C.PHYSFS_unmount(ll.mdir) ll.mdir = nil - error 'unimplemented' end end diff --git a/lib/fs.lua b/lib/fs.lua new file mode 100644 index 0000000..e6088c3 --- /dev/null +++ b/lib/fs.lua @@ -0,0 +1,20 @@ +return function(ll) + +function ll.fsIsAbs(f) + f = f:sub(1, 1) + return f == '/' or f == '\\' +end + +function ll.fsIsRel(f) + return not ll.fsIsAbs(f) +end + +function ll.fsFile(f) + return f:match '([^/\\]*)[/\\]*$' +end + +function ll.fsDir(f) + return f:match '^(.*)[/\\]+[^/\\]*[/\\]*$' +end + +end diff --git a/lib/keyb.lua b/lib/keyb.lua new file mode 100644 index 0000000..e3c0719 --- /dev/null +++ b/lib/keyb.lua @@ -0,0 +1,81 @@ +return function(ll) + +local mx, my, mb, mpb +local dir, sc1, sc2, sclm + +-- d - direction (h, v, x, y, *) +-- c1 - coordinate before card (mouse) (be left or top) +-- c2 - coordinate after card (mouse) (be right or bottom) +-- clm - other coordinate limit (mouse) (set -1 to disable) +function ll.kbInit(d, c1, c2, clim) + if d == 'h' or d == 'v' or d == '*' + then dir = d + elseif d == 'y' + then dir = 'v' + elseif d == 'x' + then dir = 'h' + else error 'Direction must be *, h (x) or v (y)' + end + + c1, c2 = + tonumber(c1) or 0, + tonumber(c2) or 0 + sc1, sc2, sclm = + math.min(c1, c2), + math.max(c1, c2), + tonumber(clim) or -1 +end + +-- returns: <, >, o, m, nil +-- ^ and v if dir is * +function ll.kbGet() + assert(dir, 'Call ll.kbInit(dir, coord1, coord2, coordlimit) before') + mx, my = love.mouse.getPosition() + mpb = mb + if love.mouse.isDown(1) then mb = 1 + else mb = 0 + end + + if love.keyboard.isScancodeDown('up', 'w') + then return dir == '*' and '^' or '<' + + elseif love.keyboard.isScancodeDown('left', 'a') + then return '<' + + elseif love.keyboard.isScancodeDown('down', 's') + then return dir == '*' and 'v' or '>' + + elseif love.keyboard.isScancodeDown('right', 'd') + then return '>' + + elseif love.keyboard.isScancodeDown('return', 'space') + then return 'o' + + elseif love.keyboard.isDown 'menu' + then return 'm' + + elseif mb == 0 and mpb == 1 then -- unpressed + if dir == 'h' then + if sclm < 0 or my <= sclm then + if mx <= sc1 + then return '<' + elseif mx >= sc2 + then return '>' + else return 'o' + end + end + else + if sclm < 0 or mx <= sclm then + if my <= sc1 + then return '<' + elseif my >= sc2 + then return '>' + else return 'o' + end + end + end + + end +end + +end diff --git a/lib/load.lua b/lib/load.lua index acc60dd..04a40e1 100644 --- a/lib/load.lua +++ b/lib/load.lua @@ -1,9 +1,51 @@ return function(ll) +function ll.addGame(file, cont) + local dir = ll.fsDir(file) + file = ll.fsFile(file) + local ext = file:match '%.(%w+)$' + print(file, ext, dir) + return 'NO!', nil +end + function ll.gameAdd(conf, file, base, dir) local gme = ll.gameNew(conf, file, base, dir) + gme.dat = {} + + if gme.screens and gme.screens[1] then + gme.dat.scr = {} + for i = 1, #gme.screens do + table.insert(gme.dat.scr, love.graphics.newImage(ll.cfg.root .. gme.dir ..'/'.. gme.screens[i])) + end + end + table.insert(ll.games, gme) return gme end +local lfs = love.filesystem +local info = lfs.getInfo + +for _, dir in pairs(love.filesystem.getDirectoryItems(ll.cfg.root)) do + local isDir + if info + then isDir = info(ll.cfg.root .. dir).type == 'directory' + else isDir = lfs.isDirectory(ll.cfg.root .. dir) + end + + if isDir then + local file = ll.cfg.root .. dir..'/'.. 'info.ll' + local realDir = love.filesystem.getRealDirectory(file) + or love.filesystem.getRealDirectory(ll.cfg.root .. dir..'/main.lua') + if realDir + then ll.gameAdd( + love.filesystem.read(file), + file, + realDir ..'/'.. ll.cfg.root, + dir + ) + end + end +end + end diff --git a/lib/love/chroot.lua b/lib/love/chroot.lua deleted file mode 100644 index 24d9cb5..0000000 --- a/lib/love/chroot.lua +++ /dev/null @@ -1,33 +0,0 @@ -return function(ll) - -local ffi = require 'ffi' -ffi.cdef [[ - int PHYSFS_mount(const char *, const char *, int); - int PHYSFS_unmount(const char *); -]] - -function ll.mount(gme) - local mdir = gme.base .. gme.dir - - love.filesystem.setRequirePath('' - .. mdir .. '/?.lua;' - .. mdir .. '/?/init.lua;' - .. '?.lua;?/init.lua;' - ) - -- FIXME: Bug may appear in Linux. Recompile Love2D or use official PPA. - if ffi.C.PHYSFS_mount(mdir, '/', 0) == 0 - then error 'Cannot mount' - else - ll.mdir = mdir - ll.mgme = gme - end -end - -function ll.umount() - if ll.mdir ~= nil then - ffi.C.PHYSFS_unmount(ll.mdir) - ll.mdir = nil - end -end - -end diff --git a/lib/love/load.lua b/lib/love/load.lua deleted file mode 100644 index 787d1d7..0000000 --- a/lib/love/load.lua +++ /dev/null @@ -1,28 +0,0 @@ -return function(ll) - - function ll.gameAdd(conf, file, base, dir) - local gme = ll.gameNew(conf, file, base, dir) - gme.dat = {} - - if gme.screens and gme.screens[1] then - gme.dat.scr = {} - for i = 1, #gme.screens do - table.insert(gme.dat.scr, love.graphics.newImage(ll.cfg.root .. gme.dir ..'/'.. gme.screens[i])) - end - end - - table.insert(ll.games, gme) - return gme - end - -for _, dir in pairs(love.filesystem.getDirectoryItems(ll.cfg.root)) do - local file = ll.cfg.root .. dir..'/'.. 'info.ll' - ll.gameAdd( - love.filesystem.read(file), - file, - love.filesystem.getSource():match '(.*)[\\/]*' ..'/'.. ll.cfg.root, -- TODO: AppData folders support - dir - ) -end - -end diff --git a/lib/main.lua b/lib/main.lua index 86d4169..dee7506 100644 --- a/lib/main.lua +++ b/lib/main.lua @@ -4,24 +4,24 @@ ll.cfg = { root = 'games/', } +require 'lib.fs' (ll) require 'lib.game' (ll) require 'lib.chroot' (ll) require 'lib.load' (ll) +require 'lib.keyb' (ll) function ll.home() ll.umount() - error 'go to home' + love.event.push('quit', 'restart') end -if love then - require 'lib.love.chroot' (ll) - require 'lib.love.load' (ll) - - function ll.home() - ll.umount() - love.event.push('quit', 'restart') +ll.dt = false +function ll.devtools() + if not ll.dt then + ll.dt = true + __LL = ll + pcall(function() require 'dev.tools' end) end - llHome = ll.home end return ll diff --git a/ll-min.lua b/ll-min.lua index 37edda9..eafd105 100644 --- a/ll-min.lua +++ b/ll-min.lua @@ -1,8 +1,17 @@ --- minimal Love Loader API +-- Minimal Love Loader API +-- Version 2.1 +-- (c) Er2 2022 +-- Zlib License if not llUsed then COLDIV = love.getVersion() == 0 and 1 or 255 +MOBILE = love.system.getOS() == 'Android' + or love.system.getOS() == 'iOS' + +if MOBILE +then love.window.setFullscreen(true) +end function love.resize(x, y) W, H = x, y diff --git a/luapack.lua b/luapack.lua index f4ab5ff..ab4dec7 100644 --- a/luapack.lua +++ b/luapack.lua @@ -9,6 +9,7 @@ return { 'llHome', 'resize', 'COLDIV', + 'MOBILE', 'W', 'H', } }, diff --git a/readme.md b/readme.md index b14a9b3..f0871b3 100644 --- a/readme.md +++ b/readme.md @@ -15,8 +15,7 @@ with custom event handling and redrawing. # LibLL -Love Loader from v2.0 includes library to simplify creating custom interfaces. -It is like a backend for Love Loader. +Love Loader from 2.0 includes backend API to simplify creating custom skins. It have not so many functions and fields: @@ -43,7 +42,9 @@ It have not so many functions and fields: Creates game object (defined above) and returns it. -- `ll.gameAdd(conf, file, base, dir)` - same as `ll.gameNew`, but inserts game into `ll.games`. +- `ll.gameAdd(conf, file, base, dir)` - same as `ll.gameNew` with insertion into `ll.games`. + +- `ll.addGame(fileName, fileContent)` - function for file dropping, reserved for v3.0. - `ll.mount(game)` - mounts game. @@ -57,11 +58,29 @@ It have not so many functions and fields: - `ll.home()` - calls `llHome` +- `ll.dt` - is developer tools enabled? + +- `__LL` - global variable of Love Loader instance when developer tools enabled. + +- `ll.devtools()` - enable developer tools. + +- `ll.fsIsAbs(file)` - is file absolute (/file)? + +- `ll.fsIsRel(file)` - is file relative, inverted result of ll.fsIsAbs (./file). + +- `ll.fsDir(path)` - get directory name (2 from /1/2/3.file). + +- `ll.fsFile(path)` - get file (including dividers after) (2 from /1/2/). + +- `ll.kbInit(direction --[[string: *, h, v, x, y]], c1 --[[number, coordinate before card for mouse (left/top)]], c2 --[[number, coordinate after card for mouse (right/bottom)]], clim --[[other coordinate limit for mouse or -1 to disable]])` - initialize keyboard module for skins. + +- `ll.kbGet() --[[nil, string: <, >, o, m, ^ anv v if direction is *]]` - get key pressed. + # API -To simplify task to the game developers, this loader creates some global variables to use. +To reduce things to do for game developers, this loader creates some global variables to use. -You can also use it without Love Loader by including `ll-min.lua` file. +You can also use it without Love Loader (or if your game can distribute without loader) by including `ll-min.lua` file. `W` and `H`: width and height of the screen which controls by custom love.resize function. @@ -75,6 +94,8 @@ You can also use it without Love Loader by including `ll-min.lua` file. `COLDIV`: color divider (1 or 255) to `love.graphics.setColor` function. +`MOBILE`: is this device runs Android or iOS? + # Fill game information To fill game information in game folder need to create `info.ll` file. @@ -89,3 +110,4 @@ desc = Some descripion about the game. pic = screen.png pics = [ screen.png; screen2.png ] # wow arrays ``` + diff --git a/skins/gui.lua b/skins/gui.lua index 10f6c67..fdb2708 100644 --- a/skins/gui.lua +++ b/skins/gui.lua @@ -1,7 +1,5 @@ return function(ll) --- Classic UI from Love Loader v1 - ll.cfg.pcht = ll.cfg.pcht or 60 * 5 local pikchv, pikcha = 0, 0 @@ -10,8 +8,8 @@ local pikchao = math.floor(1 / ll.cfg.pcht * 2 * 255 + 0.5) local cx, cy, cw, ch local f, bf -local mx, mb, mpb = 0, 0, 0 -local cdir, sel = 0, 1 +local sel = 1 +local cdir function resize() cw = W / 1.25 @@ -23,40 +21,25 @@ function resize() f = love.graphics.newFont(th / 3) bf = love.graphics.newFont(th / 2) + + ll.kbInit('h', cx, cx + cw) end local function update() - mx = love.mouse.getX() - mpb = mb - if love.mouse.isDown(1) then mb = 1 - else mb = 0 end - - local sdi = 0 - if mpb == 1 and mb == 0 then - if mx <= cx - then sdi = 1 - elseif mx >= cx + cw - then sdi = 2 - else sdi = 3 - end - end - - if love.keyboard.isScancodeDown('left', 'a') - then sdi = 1 - elseif love.keyboard.isScancodeDown('right', 'd') - then sdi = 2 - elseif love.keyboard.isScancodeDown('return', 'space') - then sdi = 3 - end + local sdi = ll.kbGet() if cdir ~= sdi then cdir = sdi - if sdi == 1 + if sdi == '<' then sel = sel - 1 - elseif sdi == 2 + elseif sdi == '>' then sel = sel + 1 - elseif sdi == 3 and ll.games[sel] + elseif sdi == 'o' and ll.games[sel] then ll.mount(ll.games[sel]) + + elseif sdi == 'm' + and love.mouse.getX() >= W - 8 + then ll.devtools() end if sel < 1 then sel = #ll.games end @@ -78,11 +61,6 @@ local function update() end else pikcha = math.min(255, pikcha + pikchao) end - - if love.keyboard.isDown 'menu' - and mx >= W - 8 - then pcall(select(2, pcall(require, 'dev.devtools')), ll) - end end local tm = 0 diff --git a/skins/psp.lua b/skins/psp.lua index fc4a34e..2427148 100644 --- a/skins/psp.lua +++ b/skins/psp.lua @@ -15,6 +15,9 @@ ll.cfg.pcht = ll.cfg.pcht or 60 * 5 local pikchv, pikcha = 0, 0 local pikchao = math.floor(1 / ll.cfg.pcht * 2 * 255 + 0.5) +local logger = '' +local chc = '<>><' + function resize() r = math.min(W, H) / 30 @@ -26,57 +29,38 @@ function resize() f = love.graphics.setNewFont(math.min(W, H) / 30) bf = love.graphics.newFont(math.min(W, H) / 20) + + ll.kbInit('v', H / 2 - ch, H / 2 + ch + cg, cx + cw * 2) end love.window.setMode(800, 600, {resizable = true}) -local my, mb, mpb - -local sdir = 0 +local sdir local function update() local ty = H / 2 - (ch + cg) * sel cy = cy + (ty - cy) * 0.1 css = css + (2 - css) * 0.2 rcss = 2 - css + 1 - local sdi - - my = love.mouse.getY() - mpb = mb - if love.mouse.isDown(1) then mb = 1 - else mb = 0 - end - if mb == 0 and mpb == 1 then - if my <= H / 2 - ch - then sdi = 1 - elseif my >= H / 2 + ch + cg - then sdi = 2 - else sdi = 3 - end - elseif love.keyboard.isScancodeDown('up', 'w') - then sdi = 1 - elseif love.keyboard.isScancodeDown('down', 's') - then sdi = 2 - elseif love.keyboard.isScancodeDown('return', 'space') - then sdi = 3 - else sdi = 0 - end + local sdi = ll.kbGet() if sdi ~= sdir then - if sdi ~= 0 + if sdi then rcss = css css = 1 - if sdi == 3 - then css = 1.5 - end psel = sel + logger = logger .. sdi + if logger == chc then + resize() + ll.devtools() + end end sdir = sdi - if sdi == 1 + if sdi == '<' then sel = sel - 1 - elseif sdi == 2 + elseif sdi == '>' then sel = sel + 1 - elseif sdi == 3 and ll.games[sel] + elseif sdi == 'o' and ll.games[sel] then ll.mount(ll.games[sel]) end