From bf4120623550cb51518ab1cb3369f0822862a7a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=8C=E3=81=BF=E3=82=8D=E3=81=86?= Date: Sun, 9 Jun 2019 14:56:13 +0900 Subject: [PATCH 1/3] =?UTF-8?q?:books:=20README=20=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index b891194..6d97ce9 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,60 @@ # love-life-like -[WIP] :space_invader: Life-like cellular automaton with LÖVE + +:space_invader: Generic Life-like cellular automaton with LÖVE + +![Screenshot](https://user-images.githubusercontent.com/1193542/58362964-6ee44480-7ed8-11e9-9895-05b97cd3d7ba.png) + +## Menu + +- File + - New: Create a new board. + - Open: Open board file. + - Save: Save current board file. + - Save As: Save board file. + +- Window + - Control: Toggle 'Control' window. + - Optional Rule: Toggle 'Optional Rule' window. + +## Controls + +- Draw cell: Main mouse button +- Remove cell: Sub mouse button +- Restart: F5 +- Toggle GUI: F12 +- Capture a screenshot: Print screen + - Save a screenshot to a [save-directory](https://love2d.org/wiki/love.filesystem) + +## Getting Started + +### Quick Start + +1. Download and install [LÖVE](https://love2d.org/) 11.2. +1. Download the latest version of `love-life-like.love` game distribution from release. +1. Open the distribution with LÖVE. + +### Build and Run from Source + +``` +git clone https://github.com/remyroez/love-life-like.git +cd love-life-like/game +love . +``` + +## Requirements + +- [LÖVE](https://love2d.org/) 11.2 + +## Libraries + +- [Slab](https://github.com/coding-jackalope/Slab) v0.3.0 (customized) +- [binser](https://github.com/bakpakin/binser) 0.0-8 +- [FBlove](https://love2d.org/forums/viewtopic.php?f=5&t=85013) for love11.1 +- [lume](https://github.com/rxi/lume/tree/d8c2eddc10af994ad4956cf0b7ae7188e86db47e) 2.3.0 +- [lurker](https://github.com/rxi/lurker/tree/4e34f47f9ed95477407425c5b25a779fac3eb9a7) 1.0.1 +- [middleclass](https://github.com/kikito/middleclass) v4.1.1 +- [Stateful](https://github.com/kikito/stateful.lua) 1.0.5 (2017-08) + +## License + +MIT License From 390f6d1c3a26f2131b2298b5cd625248cf7a86c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=8C=E3=81=BF=E3=82=8D=E3=81=86?= Date: Sun, 9 Jun 2019 15:00:14 +0900 Subject: [PATCH 2/3] =?UTF-8?q?:books:=20=E3=82=B9=E3=82=AF=E3=83=AA?= =?UTF-8?q?=E3=83=BC=E3=83=B3=E3=82=B7=E3=83=A7=E3=83=83=E3=83=88=E5=B7=AE?= =?UTF-8?q?=E3=81=97=E6=9B=BF=E3=81=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6d97ce9..c163595 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# love-life-like +# LIFE-LIKE :space_invader: Generic Life-like cellular automaton with LÖVE -![Screenshot](https://user-images.githubusercontent.com/1193542/58362964-6ee44480-7ed8-11e9-9895-05b97cd3d7ba.png) +![Screenshot](https://user-images.githubusercontent.com/1193542/59155571-1e1f3f00-8ac7-11e9-91bf-3011930f4422.png) ## Menu From 85592209624de7a9932b8c3b2f839d0354878b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=82=8C=E3=81=BF=E3=82=8D=E3=81=86?= Date: Sun, 9 Jun 2019 15:03:05 +0900 Subject: [PATCH 3/3] =?UTF-8?q?:heavy=5Fminus=5Fsign:=20=E4=B8=8D=E8=A6=81?= =?UTF-8?q?=E3=81=AA=E3=83=A9=E3=82=A4=E3=83=96=E3=83=A9=E3=83=AA=E3=81=AE?= =?UTF-8?q?=E5=89=8A=E9=99=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 - game/lib/lume.lua | 780 ------------------------------------------ game/lib/lurker.lua | 265 -------------- game/lib/stateful.lua | 224 ------------ game/main.lua | 13 - 5 files changed, 1285 deletions(-) delete mode 100644 game/lib/lume.lua delete mode 100644 game/lib/lurker.lua delete mode 100644 game/lib/stateful.lua diff --git a/README.md b/README.md index c163595..c178e8b 100644 --- a/README.md +++ b/README.md @@ -50,10 +50,7 @@ love . - [Slab](https://github.com/coding-jackalope/Slab) v0.3.0 (customized) - [binser](https://github.com/bakpakin/binser) 0.0-8 - [FBlove](https://love2d.org/forums/viewtopic.php?f=5&t=85013) for love11.1 -- [lume](https://github.com/rxi/lume/tree/d8c2eddc10af994ad4956cf0b7ae7188e86db47e) 2.3.0 -- [lurker](https://github.com/rxi/lurker/tree/4e34f47f9ed95477407425c5b25a779fac3eb9a7) 1.0.1 - [middleclass](https://github.com/kikito/middleclass) v4.1.1 -- [Stateful](https://github.com/kikito/stateful.lua) 1.0.5 (2017-08) ## License diff --git a/game/lib/lume.lua b/game/lib/lume.lua deleted file mode 100644 index 83650e0..0000000 --- a/game/lib/lume.lua +++ /dev/null @@ -1,780 +0,0 @@ --- --- lume --- --- Copyright (c) 2018 rxi --- --- 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, sublicense, 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 lume = { _version = "2.3.0" } - -local pairs, ipairs = pairs, ipairs -local type, assert, unpack = type, assert, unpack or table.unpack -local tostring, tonumber = tostring, tonumber -local math_floor = math.floor -local math_ceil = math.ceil -local math_atan2 = math.atan2 or math.atan -local math_sqrt = math.sqrt -local math_abs = math.abs - -local noop = function() -end - -local identity = function(x) - return x -end - -local patternescape = function(str) - return str:gsub("[%(%)%.%%%+%-%*%?%[%]%^%$]", "%%%1") -end - -local absindex = function(len, i) - return i < 0 and (len + i + 1) or i -end - -local iscallable = function(x) - if type(x) == "function" then return true end - local mt = getmetatable(x) - return mt and mt.__call ~= nil -end - -local getiter = function(x) - if lume.isarray(x) then - return ipairs - elseif type(x) == "table" then - return pairs - end - error("expected table", 3) -end - -local iteratee = function(x) - if x == nil then return identity end - if iscallable(x) then return x end - if type(x) == "table" then - return function(z) - for k, v in pairs(x) do - if z[k] ~= v then return false end - end - return true - end - end - return function(z) return z[x] end -end - - - -function lume.clamp(x, min, max) - return x < min and min or (x > max and max or x) -end - - -function lume.round(x, increment) - if increment then return lume.round(x / increment) * increment end - return x >= 0 and math_floor(x + .5) or math_ceil(x - .5) -end - - -function lume.sign(x) - return x < 0 and -1 or 1 -end - - -function lume.lerp(a, b, amount) - return a + (b - a) * lume.clamp(amount, 0, 1) -end - - -function lume.smooth(a, b, amount) - local t = lume.clamp(amount, 0, 1) - local m = t * t * (3 - 2 * t) - return a + (b - a) * m -end - - -function lume.pingpong(x) - return 1 - math_abs(1 - x % 2) -end - - -function lume.distance(x1, y1, x2, y2, squared) - local dx = x1 - x2 - local dy = y1 - y2 - local s = dx * dx + dy * dy - return squared and s or math_sqrt(s) -end - - -function lume.angle(x1, y1, x2, y2) - return math_atan2(y2 - y1, x2 - x1) -end - - -function lume.vector(angle, magnitude) - return math.cos(angle) * magnitude, math.sin(angle) * magnitude -end - - -function lume.random(a, b) - if not a then a, b = 0, 1 end - if not b then b = 0 end - return a + math.random() * (b - a) -end - - -function lume.randomchoice(t) - return t[math.random(#t)] -end - - -function lume.weightedchoice(t) - local sum = 0 - for _, v in pairs(t) do - assert(v >= 0, "weight value less than zero") - sum = sum + v - end - assert(sum ~= 0, "all weights are zero") - local rnd = lume.random(sum) - for k, v in pairs(t) do - if rnd < v then return k end - rnd = rnd - v - end -end - - -function lume.isarray(x) - return type(x) == "table" and x[1] ~= nil -end - - -function lume.push(t, ...) - local n = select("#", ...) - for i = 1, n do - t[#t + 1] = select(i, ...) - end - return ... -end - - -function lume.remove(t, x) - local iter = getiter(t) - for i, v in iter(t) do - if v == x then - if lume.isarray(t) then - table.remove(t, i) - break - else - t[i] = nil - break - end - end - end - return x -end - - -function lume.clear(t) - local iter = getiter(t) - for k in iter(t) do - t[k] = nil - end - return t -end - - -function lume.extend(t, ...) - for i = 1, select("#", ...) do - local x = select(i, ...) - if x then - for k, v in pairs(x) do - t[k] = v - end - end - end - return t -end - - -function lume.shuffle(t) - local rtn = {} - for i = 1, #t do - local r = math.random(i) - if r ~= i then - rtn[i] = rtn[r] - end - rtn[r] = t[i] - end - return rtn -end - - -function lume.sort(t, comp) - local rtn = lume.clone(t) - if comp then - if type(comp) == "string" then - table.sort(rtn, function(a, b) return a[comp] < b[comp] end) - else - table.sort(rtn, comp) - end - else - table.sort(rtn) - end - return rtn -end - - -function lume.array(...) - local t = {} - for x in ... do t[#t + 1] = x end - return t -end - - -function lume.each(t, fn, ...) - local iter = getiter(t) - if type(fn) == "string" then - for _, v in iter(t) do v[fn](v, ...) end - else - for _, v in iter(t) do fn(v, ...) end - end - return t -end - - -function lume.map(t, fn) - fn = iteratee(fn) - local iter = getiter(t) - local rtn = {} - for k, v in iter(t) do rtn[k] = fn(v) end - return rtn -end - - -function lume.all(t, fn) - fn = iteratee(fn) - local iter = getiter(t) - for _, v in iter(t) do - if not fn(v) then return false end - end - return true -end - - -function lume.any(t, fn) - fn = iteratee(fn) - local iter = getiter(t) - for _, v in iter(t) do - if fn(v) then return true end - end - return false -end - - -function lume.reduce(t, fn, first) - local acc = first - local started = first and true or false - local iter = getiter(t) - for _, v in iter(t) do - if started then - acc = fn(acc, v) - else - acc = v - started = true - end - end - assert(started, "reduce of an empty table with no first value") - return acc -end - - -function lume.unique(t) - local rtn = {} - for k in pairs(lume.invert(t)) do - rtn[#rtn + 1] = k - end - return rtn -end - - -function lume.filter(t, fn, retainkeys) - fn = iteratee(fn) - local iter = getiter(t) - local rtn = {} - if retainkeys then - for k, v in iter(t) do - if fn(v) then rtn[k] = v end - end - else - for _, v in iter(t) do - if fn(v) then rtn[#rtn + 1] = v end - end - end - return rtn -end - - -function lume.reject(t, fn, retainkeys) - fn = iteratee(fn) - local iter = getiter(t) - local rtn = {} - if retainkeys then - for k, v in iter(t) do - if not fn(v) then rtn[k] = v end - end - else - for _, v in iter(t) do - if not fn(v) then rtn[#rtn + 1] = v end - end - end - return rtn -end - - -function lume.merge(...) - local rtn = {} - for i = 1, select("#", ...) do - local t = select(i, ...) - local iter = getiter(t) - for k, v in iter(t) do - rtn[k] = v - end - end - return rtn -end - - -function lume.concat(...) - local rtn = {} - for i = 1, select("#", ...) do - local t = select(i, ...) - if t ~= nil then - local iter = getiter(t) - for _, v in iter(t) do - rtn[#rtn + 1] = v - end - end - end - return rtn -end - - -function lume.find(t, value) - local iter = getiter(t) - for k, v in iter(t) do - if v == value then return k end - end - return nil -end - - -function lume.match(t, fn) - fn = iteratee(fn) - local iter = getiter(t) - for k, v in iter(t) do - if fn(v) then return v, k end - end - return nil -end - - -function lume.count(t, fn) - local count = 0 - local iter = getiter(t) - if fn then - fn = iteratee(fn) - for _, v in iter(t) do - if fn(v) then count = count + 1 end - end - else - if lume.isarray(t) then - return #t - end - for _ in iter(t) do count = count + 1 end - end - return count -end - - -function lume.slice(t, i, j) - i = i and absindex(#t, i) or 1 - j = j and absindex(#t, j) or #t - local rtn = {} - for x = i < 1 and 1 or i, j > #t and #t or j do - rtn[#rtn + 1] = t[x] - end - return rtn -end - - -function lume.first(t, n) - if not n then return t[1] end - return lume.slice(t, 1, n) -end - - -function lume.last(t, n) - if not n then return t[#t] end - return lume.slice(t, -n, -1) -end - - -function lume.invert(t) - local rtn = {} - for k, v in pairs(t) do rtn[v] = k end - return rtn -end - - -function lume.pick(t, ...) - local rtn = {} - for i = 1, select("#", ...) do - local k = select(i, ...) - rtn[k] = t[k] - end - return rtn -end - - -function lume.keys(t) - local rtn = {} - local iter = getiter(t) - for k in iter(t) do rtn[#rtn + 1] = k end - return rtn -end - - -function lume.clone(t) - local rtn = {} - for k, v in pairs(t) do rtn[k] = v end - return rtn -end - - -function lume.fn(fn, ...) - assert(iscallable(fn), "expected a function as the first argument") - local args = { ... } - return function(...) - local a = lume.concat(args, { ... }) - return fn(unpack(a)) - end -end - - -function lume.once(fn, ...) - local f = lume.fn(fn, ...) - local done = false - return function(...) - if done then return end - done = true - return f(...) - end -end - - -local memoize_fnkey = {} -local memoize_nil = {} - -function lume.memoize(fn) - local cache = {} - return function(...) - local c = cache - for i = 1, select("#", ...) do - local a = select(i, ...) or memoize_nil - c[a] = c[a] or {} - c = c[a] - end - c[memoize_fnkey] = c[memoize_fnkey] or {fn(...)} - return unpack(c[memoize_fnkey]) - end -end - - -function lume.combine(...) - local n = select('#', ...) - if n == 0 then return noop end - if n == 1 then - local fn = select(1, ...) - if not fn then return noop end - assert(iscallable(fn), "expected a function or nil") - return fn - end - local funcs = {} - for i = 1, n do - local fn = select(i, ...) - if fn ~= nil then - assert(iscallable(fn), "expected a function or nil") - funcs[#funcs + 1] = fn - end - end - return function(...) - for _, f in ipairs(funcs) do f(...) end - end -end - - -function lume.call(fn, ...) - if fn then - return fn(...) - end -end - - -function lume.time(fn, ...) - local start = os.clock() - local rtn = {fn(...)} - return (os.clock() - start), unpack(rtn) -end - - -local lambda_cache = {} - -function lume.lambda(str) - if not lambda_cache[str] then - local args, body = str:match([[^([%w,_ ]-)%->(.-)$]]) - assert(args and body, "bad string lambda") - local s = "return function(" .. args .. ")\nreturn " .. body .. "\nend" - lambda_cache[str] = lume.dostring(s) - end - return lambda_cache[str] -end - - -local serialize - -local serialize_map = { - [ "boolean" ] = tostring, - [ "nil" ] = tostring, - [ "string" ] = function(v) return string.format("%q", v) end, - [ "number" ] = function(v) - if v ~= v then return "0/0" -- nan - elseif v == 1 / 0 then return "1/0" -- inf - elseif v == -1 / 0 then return "-1/0" end -- -inf - return tostring(v) - end, - [ "table" ] = function(t, stk) - stk = stk or {} - if stk[t] then error("circular reference") end - local rtn = {} - stk[t] = true - for k, v in pairs(t) do - rtn[#rtn + 1] = "[" .. serialize(k, stk) .. "]=" .. serialize(v, stk) - end - stk[t] = nil - return "{" .. table.concat(rtn, ",") .. "}" - end -} - -setmetatable(serialize_map, { - __index = function(_, k) error("unsupported serialize type: " .. k) end -}) - -serialize = function(x, stk) - return serialize_map[type(x)](x, stk) -end - -function lume.serialize(x) - return serialize(x) -end - - -function lume.deserialize(str) - return lume.dostring("return " .. str) -end - - -function lume.split(str, sep) - if not sep then - return lume.array(str:gmatch("([%S]+)")) - else - assert(sep ~= "", "empty separator") - local psep = patternescape(sep) - return lume.array((str..sep):gmatch("(.-)("..psep..")")) - end -end - - -function lume.trim(str, chars) - if not chars then return str:match("^[%s]*(.-)[%s]*$") end - chars = patternescape(chars) - return str:match("^[" .. chars .. "]*(.-)[" .. chars .. "]*$") -end - - -function lume.wordwrap(str, limit) - limit = limit or 72 - local check - if type(limit) == "number" then - check = function(s) return #s >= limit end - else - check = limit - end - local rtn = {} - local line = "" - for word, spaces in str:gmatch("(%S+)(%s*)") do - local s = line .. word - if check(s) then - table.insert(rtn, line .. "\n") - line = word - else - line = s - end - for c in spaces:gmatch(".") do - if c == "\n" then - table.insert(rtn, line .. "\n") - line = "" - else - line = line .. c - end - end - end - table.insert(rtn, line) - return table.concat(rtn) -end - - -function lume.format(str, vars) - if not vars then return str end - local f = function(x) - return tostring(vars[x] or vars[tonumber(x)] or "{" .. x .. "}") - end - return (str:gsub("{(.-)}", f)) -end - - -function lume.trace(...) - local info = debug.getinfo(2, "Sl") - local t = { info.short_src .. ":" .. info.currentline .. ":" } - for i = 1, select("#", ...) do - local x = select(i, ...) - if type(x) == "number" then - x = string.format("%g", lume.round(x, .01)) - end - t[#t + 1] = tostring(x) - end - print(table.concat(t, " ")) -end - - -function lume.dostring(str) - return assert((loadstring or load)(str))() -end - - -function lume.uuid() - local fn = function(x) - local r = math.random(16) - 1 - r = (x == "x") and (r + 1) or (r % 4) + 9 - return ("0123456789abcdef"):sub(r, r) - end - return (("xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"):gsub("[xy]", fn)) -end - - -function lume.hotswap(modname) - local oldglobal = lume.clone(_G) - local updated = {} - local function update(old, new) - if updated[old] then return end - updated[old] = true - local oldmt, newmt = getmetatable(old), getmetatable(new) - if oldmt and newmt then update(oldmt, newmt) end - for k, v in pairs(new) do - if type(v) == "table" then update(old[k], v) else old[k] = v end - end - end - local err = nil - local function onerror(e) - for k in pairs(_G) do _G[k] = oldglobal[k] end - err = lume.trim(e) - end - local ok, oldmod = pcall(require, modname) - oldmod = ok and oldmod or nil - xpcall(function() - package.loaded[modname] = nil - local newmod = require(modname) - if type(oldmod) == "table" then update(oldmod, newmod) end - for k, v in pairs(oldglobal) do - if v ~= _G[k] and type(v) == "table" then - update(v, _G[k]) - _G[k] = v - end - end - end, onerror) - package.loaded[modname] = oldmod - if err then return nil, err end - return oldmod -end - - -local ripairs_iter = function(t, i) - i = i - 1 - local v = t[i] - if v ~= nil then - return i, v - end -end - -function lume.ripairs(t) - return ripairs_iter, t, (#t + 1) -end - - -function lume.color(str, mul) - mul = mul or 1 - local r, g, b, a - r, g, b = str:match("#(%x%x)(%x%x)(%x%x)") - if r then - r = tonumber(r, 16) / 0xff - g = tonumber(g, 16) / 0xff - b = tonumber(b, 16) / 0xff - a = 1 - elseif str:match("rgba?%s*%([%d%s%.,]+%)") then - local f = str:gmatch("[%d.]+") - r = (f() or 0) / 0xff - g = (f() or 0) / 0xff - b = (f() or 0) / 0xff - a = f() or 1 - else - error(("bad color string '%s'"):format(str)) - end - return r * mul, g * mul, b * mul, a * mul -end - - -local chain_mt = {} -chain_mt.__index = lume.map(lume.filter(lume, iscallable, true), - function(fn) - return function(self, ...) - self._value = fn(self._value, ...) - return self - end - end) -chain_mt.__index.result = function(x) return x._value end - -function lume.chain(value) - return setmetatable({ _value = value }, chain_mt) -end - -setmetatable(lume, { - __call = function(_, ...) - return lume.chain(...) - end -}) - - -return lume diff --git a/game/lib/lurker.lua b/game/lib/lurker.lua deleted file mode 100644 index 7458786..0000000 --- a/game/lib/lurker.lua +++ /dev/null @@ -1,265 +0,0 @@ --- --- lurker --- --- Copyright (c) 2018 rxi --- --- This library is free software; you can redistribute it and/or modify it --- under the terms of the MIT license. See LICENSE for details. --- - --- Assumes lume is in the same directory as this file if it does not exist --- as a global -local lume = rawget(_G, "lume") or require((...):gsub("[^/.\\]+$", "lume")) - -local lurker = { _version = "1.0.1" } - - -local dir = love.filesystem.enumerate or love.filesystem.getDirectoryItems -local isdir = love.filesystem.getInfo and function (path) return (love.filesystem.getInfo(path) or {}).type == 'directory' end or love.filesystem.isDirectory -local time = love.timer.getTime or os.time -local lastmodified = love.filesystem.getInfo and function (path) return (love.filesystem.getInfo(path) or {}).modtime end or love.filesystem.getLastModified - -local lovecallbacknames = { - "update", - "load", - "draw", - "mousepressed", - "mousereleased", - "keypressed", - "keyreleased", - "focus", - "quit", -} - - -function lurker.init() - lurker.print("Initing lurker") - lurker.path = "." - lurker.preswap = function() end - lurker.postswap = function() end - lurker.interval = .5 - lurker.protected = true - lurker.quiet = false - lurker.lastscan = 0 - lurker.lasterrorfile = nil - lurker.files = {} - lurker.funcwrappers = {} - lurker.lovefuncs = {} - lurker.state = "init" - lume.each(lurker.getchanged(), lurker.resetfile) - return lurker -end - - -function lurker.print(...) - print("[lurker] " .. lume.format(...)) -end - - -function lurker.listdir(path, recursive, skipdotfiles) - path = (path == ".") and "" or path - local function fullpath(x) return path .. "/" .. x end - local t = {} - for _, f in pairs(lume.map(dir(path), fullpath)) do - if not skipdotfiles or not f:match("/%.[^/]*$") then - if recursive and isdir(f) then - t = lume.concat(t, lurker.listdir(f, true, true)) - else - table.insert(t, lume.trim(f, "/")) - end - end - end - return t -end - - -function lurker.initwrappers() - for _, v in pairs(lovecallbacknames) do - lurker.funcwrappers[v] = function(...) - local args = {...} - xpcall(function() - return lurker.lovefuncs[v] and lurker.lovefuncs[v](unpack(args)) - end, lurker.onerror) - end - lurker.lovefuncs[v] = love[v] - end - lurker.updatewrappers() -end - - -function lurker.updatewrappers() - for _, v in pairs(lovecallbacknames) do - if love[v] ~= lurker.funcwrappers[v] then - lurker.lovefuncs[v] = love[v] - love[v] = lurker.funcwrappers[v] - end - end -end - - -function lurker.onerror(e, nostacktrace) - lurker.print("An error occurred; switching to error state") - lurker.state = "error" - - -- Release mouse - local setgrab = love.mouse.setGrab or love.mouse.setGrabbed - setgrab(false) - - -- Set up callbacks - for _, v in pairs(lovecallbacknames) do - love[v] = function() end - end - - love.update = lurker.update - - love.keypressed = function(k) - if k == "escape" then - lurker.print("Exiting...") - love.event.quit() - elseif k == "f5" then - lurker.print("Restarting...") - love.event.quit('restart') - end - end - - local stacktrace = nostacktrace and "" or - lume.trim((debug.traceback("", 2):gsub("\t", ""))) - local msg = lume.format("{1}\n\n{2}", {e, stacktrace}) - local colors = { - { lume.color("#1e1e2c", 256) }, - { lume.color("#f0a3a3", 256) }, - { lume.color("#92b5b0", 256) }, - { lume.color("#66666a", 256) }, - { lume.color("#cdcdcd", 256) }, - } - love.graphics.reset() - love.graphics.setFont(love.graphics.newFont(12)) - - love.draw = function() - local pad = 25 - local width = love.graphics.getWidth() - - local function drawhr(pos, color1, color2) - local animpos = lume.smooth(pad, width - pad - 8, lume.pingpong(time())) - if color1 then love.graphics.setColor(color1) end - love.graphics.rectangle("fill", pad, pos, width - pad*2, 1) - if color2 then love.graphics.setColor(color2) end - love.graphics.rectangle("fill", animpos, pos, 8, 1) - end - - local function drawtext(str, x, y, color, limit) - love.graphics.setColor(color) - love.graphics[limit and "printf" or "print"](str, x, y, limit) - end - - love.graphics.setBackgroundColor(colors[1]) - love.graphics.clear() - - drawtext("An error has occurred", pad, pad, colors[2]) - drawtext("lurker", width - love.graphics.getFont():getWidth("lurker") - - pad, pad, colors[4]) - drawhr(pad + 32, colors[4], colors[5]) - drawtext("If you fix the problem and update the file the program will " .. - "resume", pad, pad + 46, colors[3]) - drawhr(pad + 72, colors[4], colors[5]) - drawtext(msg, pad, pad + 90, colors[5], width - pad * 2) - - love.graphics.reset() - end -end - - -function lurker.exitinitstate() - lurker.state = "normal" - if lurker.protected then - lurker.initwrappers() - end -end - - -function lurker.exiterrorstate() - lurker.state = "normal" - for _, v in pairs(lovecallbacknames) do - love[v] = lurker.funcwrappers[v] - end -end - - -function lurker.update() - if lurker.state == "init" then - lurker.exitinitstate() - end - local diff = time() - lurker.lastscan - if diff > lurker.interval then - lurker.lastscan = lurker.lastscan + diff - local changed = lurker.scan() - if #changed > 0 and lurker.lasterrorfile then - local f = lurker.lasterrorfile - lurker.lasterrorfile = nil - lurker.hotswapfile(f) - end - end -end - - -function lurker.getchanged() - local function fn(f) - return f:match("%.lua$") and lurker.files[f] ~= lastmodified(f) - end - return lume.filter(lurker.listdir(lurker.path, true, true), fn) -end - - -function lurker.modname(f) - return (f:gsub("%.lua$", ""):gsub("[/\\]", "."):gsub('^src.', ''):gsub('^lib.', '')) - --return (f:gsub("%.lua$", ""):gsub("[/\\]", ".")) -end - - -function lurker.resetfile(f) - lurker.files[f] = lastmodified(f) -end - - -function lurker.hotswapfile(f) - lurker.print("Hotswapping '{1}'...", {f}) - if lurker.state == "error" then - lurker.exiterrorstate() - end - if lurker.preswap(f) then - lurker.print("Hotswap of '{1}' aborted by preswap", {f}) - lurker.resetfile(f) - return - end - local modname = lurker.modname(f) - local t, ok, err = lume.time(lume.hotswap, modname) - if ok then - lurker.print("Swapped '{1}' in {2} secs", {f, t}) - else - lurker.print("Failed to swap '{1}' : {2}", {f, err}) - if not lurker.quiet and lurker.protected then - lurker.lasterrorfile = f - lurker.onerror(err, true) - lurker.resetfile(f) - return - end - end - lurker.resetfile(f) - lurker.postswap(f) - if lurker.protected then - lurker.updatewrappers() - end -end - - -function lurker.scan() - if lurker.state == "init" then - lurker.exitinitstate() - end - local changed = lurker.getchanged() - lume.each(changed, lurker.hotswapfile) - return changed -end - - -return lurker.init() diff --git a/game/lib/stateful.lua b/game/lib/stateful.lua deleted file mode 100644 index 89b2afa..0000000 --- a/game/lib/stateful.lua +++ /dev/null @@ -1,224 +0,0 @@ -local Stateful = { - _VERSION = 'Stateful 1.0.5 (2017-08)', - _DESCRIPTION = 'Stateful classes for middleclass', - _URL = 'https://github.com/kikito/stateful.lua', - _LICENSE = [[ - MIT LICENSE - - Copyright (c) 2017 Enrique García Cota - - 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, sublicense, 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. - ]] -} - --- requires middleclass >2.0 -Stateful.static = {} - -local _callbacks = { - enteredState = 1, - exitedState = 1, - pushedState = 1, - poppedState = 1, - pausedState = 1, - continuedState = 1 -} - -local _BaseState = {} - -local function _addStatesToClass(klass, superStates) - klass.static.states = {} - for stateName, state in pairs(superStates or {}) do - klass:addState(stateName,state) - end -end - -local function _getStatefulMethod(instance, name) - if not _callbacks[name] then - local stack = rawget(instance, '__stateStack') - if not stack then return end - for i = #stack, 1, -1 do - if stack[i][name] then return stack[i][name] end - end - end -end - -local function _getNewInstanceIndex(prevIndex) - if type(prevIndex) == 'function' then - return function(instance, name) return _getStatefulMethod(instance, name) or prevIndex(instance, name) end - end - return function(instance, name) return _getStatefulMethod(instance, name) or prevIndex[name] end -end - -local function _getNewAllocateMethod(oldAllocateMethod) - return function(klass, ...) - local instance = oldAllocateMethod(klass, ...) - instance.__stateStack = {} - return instance - end -end - -local function _modifyInstanceIndex(klass) - klass.__instanceDict.__index = _getNewInstanceIndex(klass.__instanceDict.__index) -end - -local function _getNewSubclassMethod(prevSubclass) - return function(klass, name) - local subclass = prevSubclass(klass, name) - _addStatesToClass(subclass, klass.states) - _modifyInstanceIndex(subclass) - return subclass - end -end - -local function _modifySubclassMethod(klass) - klass.static.subclass = _getNewSubclassMethod(klass.static.subclass) -end - -local function _modifyAllocateMethod(klass) - klass.static.allocate = _getNewAllocateMethod(klass.static.allocate) -end - -local function _assertType(val, name, expected_type, type_to_s) - if type(val) ~= expected_type then - error("Expected " .. name .. " to be of type " .. - (type_to_s or expected_type) .. ". Was " .. - tostring(val) .. "(" .. type(val) .. ")") - end -end - -local function _assertInexistingState(klass, stateName) - if klass.states[stateName] ~= nil then - error("State " .. tostring(stateName) .. " already exists on " .. tostring(klass) ) - end -end - -local function _assertExistingState(self, state, stateName) - if not state then - error("The state " .. stateName .. " was not found in " .. tostring(self.class)) - end -end - -local function _invokeCallback(self, state, callbackName, ...) - if state and state[callbackName] then state[callbackName](self, ...) end -end - -local function _getCurrentState(self) - return self.__stateStack[#self.__stateStack] -end - -local function _getStateFromClassByName(self, stateName) - local state = self.class.static.states[stateName] - _assertExistingState(self, state, stateName) - return state -end - -local function _getStateIndexFromStackByName(self, stateName) - if stateName == nil then return #self.__stateStack end - local target = _getStateFromClassByName(self, stateName) - for i = #self.__stateStack, 1, -1 do - if self.__stateStack[i] == target then return i end - end -end - -local function _getStateName(self, target) - for name,state in pairs(self.class.static.states) do - if state == target then return name end - end - return '*error*' -end - -function Stateful:included(klass) - _addStatesToClass(klass) - _modifyInstanceIndex(klass) - _modifySubclassMethod(klass) - _modifyAllocateMethod(klass) -end - -function Stateful.static:addState(stateName, superState) - superState = superState or _BaseState - _assertType(stateName, 'stateName', 'string') - _assertInexistingState(self, stateName) - self.static.states[stateName] = setmetatable({}, { __index = superState }) - return self.static.states[stateName] -end - -function Stateful:gotoState(stateName, ...) - - self:popAllStates(...) - - if stateName == nil then - self.__stateStack = { } - else - _assertType(stateName, 'stateName', 'string', 'string or nil') - - local newState = _getStateFromClassByName(self, stateName) - self.__stateStack = { newState } - _invokeCallback(self, newState, 'enteredState', ...) - end - -end - -function Stateful:pushState(stateName,...) - local oldState = _getCurrentState(self) - _invokeCallback(self, oldState, 'pausedState') - - local newState = _getStateFromClassByName(self, stateName) - table.insert(self.__stateStack, newState) - - _invokeCallback(self, newState, 'pushedState',...) - _invokeCallback(self, newState, 'enteredState',...) -end - -function Stateful:popState(stateName, ...) - - local oldStateIndex = _getStateIndexFromStackByName(self, stateName) - local oldState - if oldStateIndex then - oldState = self.__stateStack[oldStateIndex] - - _invokeCallback(self, oldState, 'poppedState', ...) - _invokeCallback(self, oldState, 'exitedState', ...) - - table.remove(self.__stateStack, oldStateIndex) - end - - local newState = _getCurrentState(self) - - if oldState ~= newState then - _invokeCallback(self, newState, 'continuedState', ...) - end -end - -function Stateful:popAllStates(...) - local size = #self.__stateStack - for _=1,size do self:popState(nil, ...) end -end - -function Stateful:getStateStackDebugInfo() - local info = {} - local state - for i=#self.__stateStack,1,-1 do - state = self.__stateStack[i] - table.insert(info, _getStateName(self, state)) - end - return info -end - -return Stateful diff --git a/game/main.lua b/game/main.lua index 564f5ee..979242d 100644 --- a/game/main.lua +++ b/game/main.lua @@ -2,10 +2,6 @@ -- デバッグモード local debugMode = true --- ライブラリ -local lume = require 'lume' -local lurker = require 'lurker' - -- フォーカス local focused = true local screenshot @@ -14,12 +10,6 @@ local screenshot local game = (require 'Game')() game:setDebugMode(debugMode) --- ホットスワップ後の対応 -if lurker then - lurker.postswap = function (f) - end -end - -- 読み込み function love.load() love.math.setRandomSeed(love.timer.getTime()) @@ -54,9 +44,6 @@ function love.keypressed(key, scancode, isrepeat) elseif key == 'printscreen' then -- スクリーンショット love.graphics.captureScreenshot('screenshot/' .. os.time() .. '.png') - elseif key == 'f1' and debugMode and lurker then - -- スキャン - lurker.scan() elseif key == 'f5' then -- リスタート love.event.quit('restart')