mirror of
https://github.com/love2d/love.git
synced 2026-08-12 08:30:56 +02:00
Move boot.lua to src/modules/love/ with raw string literal format.
Split it up into 3 files to keep under VS2013's raw string literal character limit. Now boot.lua doesn't need a regeneration step when it's modified.
This commit is contained in:
@@ -1267,7 +1267,6 @@
|
||||
217DFBD41D9F6D490055D849 /* url.lua.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = url.lua.h; sourceTree = "<group>"; };
|
||||
217DFBD51D9F6D490055D849 /* usocket.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = usocket.c; sourceTree = "<group>"; };
|
||||
217DFBD61D9F6D490055D849 /* usocket.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = usocket.h; sourceTree = "<group>"; };
|
||||
503971A86B7167A91B670FBA /* boot.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = boot.lua.h; sourceTree = "<group>"; };
|
||||
FA08F5AE16C7525600F007B5 /* liblove-macosx.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "liblove-macosx.plist"; path = "macosx/liblove-macosx.plist"; sourceTree = "<group>"; };
|
||||
FA0A3A5D23366CE9001C269E /* floattypes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = floattypes.h; sourceTree = "<group>"; };
|
||||
FA0A3A5E23366CE9001C269E /* floattypes.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = floattypes.cpp; sourceTree = "<group>"; };
|
||||
@@ -1777,6 +1776,8 @@
|
||||
FA1E887D1DF363CD00E808AA /* Filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Filter.h; sourceTree = "<group>"; };
|
||||
FA1E88811DF363DB00E808AA /* Filter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Filter.cpp; sourceTree = "<group>"; };
|
||||
FA1E88821DF363DB00E808AA /* Filter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Filter.h; sourceTree = "<group>"; };
|
||||
FA1E95B4271F932B0044CF08 /* arg.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = arg.lua; sourceTree = "<group>"; };
|
||||
FA1E95B5271F932B0044CF08 /* callbacks.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = callbacks.lua; sourceTree = "<group>"; };
|
||||
FA24348021D401CB00B8918A /* pch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pch.cpp; sourceTree = "<group>"; };
|
||||
FA24348121D401CB00B8918A /* attribute.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = attribute.h; sourceTree = "<group>"; };
|
||||
FA24348221D401CB00B8918A /* attribute.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = attribute.cpp; sourceTree = "<group>"; };
|
||||
@@ -2101,8 +2102,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FA577A8C16C71D3600860150 /* auto.lua */,
|
||||
FA577A8D16C71D3600860150 /* boot.lua */,
|
||||
503971A86B7167A91B670FBA /* boot.lua.h */,
|
||||
FA283EDC1B27CFAA00C70067 /* nogame.lua */,
|
||||
FA283EDD1B27CFAA00C70067 /* nogame.lua.h */,
|
||||
);
|
||||
@@ -2964,6 +2963,9 @@
|
||||
FA0B7BFD1A95902C000E1D17 /* love */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
FA1E95B4271F932B0044CF08 /* arg.lua */,
|
||||
FA577A8D16C71D3600860150 /* boot.lua */,
|
||||
FA1E95B5271F932B0044CF08 /* callbacks.lua */,
|
||||
FA0B7BFE1A95902C000E1D17 /* love.cpp */,
|
||||
FA0B7BFF1A95902C000E1D17 /* love.h */,
|
||||
);
|
||||
|
||||
@@ -0,0 +1,186 @@
|
||||
R"luastring"--(
|
||||
-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string.
|
||||
-- There is a matching delimiter at the bottom of the file.
|
||||
|
||||
--[[
|
||||
Copyright (c) 2006-2021 LOVE Development Team
|
||||
|
||||
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, and to 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 love = require("love")
|
||||
|
||||
-- Used for setup:
|
||||
love.path = {}
|
||||
love.arg = {}
|
||||
|
||||
-- Replace any \ with /.
|
||||
function love.path.normalslashes(p)
|
||||
return p:gsub("\\", "/")
|
||||
end
|
||||
|
||||
-- Makes sure there is a slash at the end
|
||||
-- of a path.
|
||||
function love.path.endslash(p)
|
||||
if p:sub(-1) ~= "/" then
|
||||
return p .. "/"
|
||||
else
|
||||
return p
|
||||
end
|
||||
end
|
||||
|
||||
-- Checks whether a path is absolute or not.
|
||||
function love.path.abs(p)
|
||||
|
||||
local tmp = love.path.normalslashes(p)
|
||||
|
||||
-- Path is absolute if it starts with a "/".
|
||||
if tmp:find("/") == 1 then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Path is absolute if it starts with a
|
||||
-- letter followed by a colon.
|
||||
if tmp:find("%a:") == 1 then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Relative.
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
-- Converts any path into a full path.
|
||||
function love.path.getFull(p)
|
||||
|
||||
if love.path.abs(p) then
|
||||
return love.path.normalslashes(p)
|
||||
end
|
||||
|
||||
local cwd = love.filesystem.getWorkingDirectory()
|
||||
cwd = love.path.normalslashes(cwd)
|
||||
cwd = love.path.endslash(cwd)
|
||||
|
||||
-- Construct a full path.
|
||||
local full = cwd .. love.path.normalslashes(p)
|
||||
|
||||
-- Remove trailing /., if applicable
|
||||
return full:match("(.-)/%.$") or full
|
||||
end
|
||||
|
||||
-- Returns the leaf of a full path.
|
||||
function love.path.leaf(p)
|
||||
p = love.path.normalslashes(p)
|
||||
|
||||
local a = 1
|
||||
local last = p
|
||||
|
||||
while a do
|
||||
a = p:find("/", a+1)
|
||||
|
||||
if a then
|
||||
last = p:sub(a+1)
|
||||
end
|
||||
end
|
||||
|
||||
return last
|
||||
end
|
||||
|
||||
-- Finds the key in the table with the lowest integral index. The lowest
|
||||
-- will typically the executable, for instance "lua5.1.exe".
|
||||
function love.arg.getLow(a)
|
||||
local m = math.huge
|
||||
for k,v in pairs(a) do
|
||||
if k < m then
|
||||
m = k
|
||||
end
|
||||
end
|
||||
return a[m], m
|
||||
end
|
||||
|
||||
love.arg.options = {
|
||||
console = { a = 0 },
|
||||
fused = {a = 0 },
|
||||
game = { a = 1 }
|
||||
}
|
||||
|
||||
love.arg.optionIndices = {}
|
||||
|
||||
function love.arg.parseOption(m, i)
|
||||
m.set = true
|
||||
|
||||
if m.a > 0 then
|
||||
m.arg = {}
|
||||
for j=i,i+m.a-1 do
|
||||
love.arg.optionIndices[j] = true
|
||||
table.insert(m.arg, arg[j])
|
||||
end
|
||||
end
|
||||
|
||||
return m.a
|
||||
end
|
||||
|
||||
function love.arg.parseOptions()
|
||||
|
||||
local game
|
||||
local argc = #arg
|
||||
|
||||
local i = 1
|
||||
while i <= argc do
|
||||
-- Look for options.
|
||||
local m = arg[i]:match("^%-%-(.*)")
|
||||
|
||||
if m and m ~= "" and love.arg.options[m] and not love.arg.options[m].set then
|
||||
love.arg.optionIndices[i] = true
|
||||
i = i + love.arg.parseOption(love.arg.options[m], i+1)
|
||||
elseif m == "" then -- handle '--' as an option
|
||||
love.arg.optionIndices[i] = true
|
||||
if not game then -- handle '--' followed by game name
|
||||
game = i + 1
|
||||
end
|
||||
break
|
||||
elseif not game then
|
||||
game = i
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if not love.arg.options.game.set then
|
||||
love.arg.parseOption(love.arg.options.game, game or 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns the arguments that are passed to your game via love.load()
|
||||
-- arguments that were parsed as options are skipped.
|
||||
function love.arg.parseGameArguments(a)
|
||||
local out = {}
|
||||
|
||||
local _, lowindex = love.arg.getLow(a)
|
||||
|
||||
local o = lowindex
|
||||
for i=lowindex, #a do
|
||||
if not love.arg.optionIndices[i] then
|
||||
out[o] = a[i]
|
||||
o = o + 1
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
|
||||
--)luastring"--"
|
||||
@@ -0,0 +1,379 @@
|
||||
R"luastring"--(
|
||||
-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string.
|
||||
-- There is a matching delimiter at the bottom of the file.
|
||||
|
||||
--[[
|
||||
Copyright (c) 2006-2021 LOVE Development Team
|
||||
|
||||
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, and to 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.
|
||||
--]]
|
||||
|
||||
-- Make sure love exists.
|
||||
local love = require("love")
|
||||
|
||||
-- Essential code boot/init.
|
||||
require("love.arg")
|
||||
require("love.callbacks")
|
||||
|
||||
local function uridecode(s)
|
||||
return s:gsub("%%%x%x", function(str)
|
||||
return string.char(tonumber(str:sub(2), 16))
|
||||
end)
|
||||
end
|
||||
|
||||
local no_game_code = false
|
||||
local invalid_game_path = nil
|
||||
|
||||
-- This can't be overridden.
|
||||
function love.boot()
|
||||
|
||||
-- This is absolutely needed.
|
||||
require("love.filesystem")
|
||||
|
||||
local arg0 = love.arg.getLow(arg)
|
||||
love.filesystem.init(arg0)
|
||||
|
||||
local exepath = love.filesystem.getExecutablePath()
|
||||
if #exepath == 0 then
|
||||
-- This shouldn't happen, but just in case we'll fall back to arg0.
|
||||
exepath = arg0
|
||||
end
|
||||
|
||||
no_game_code = false
|
||||
invalid_game_path = nil
|
||||
|
||||
-- Is this one of those fancy "fused" games?
|
||||
local can_has_game = pcall(love.filesystem.setSource, exepath)
|
||||
|
||||
-- It's a fused game, don't parse --game argument
|
||||
if can_has_game then
|
||||
love.arg.options.game.set = true
|
||||
end
|
||||
|
||||
-- Parse options now that we know which options we're looking for.
|
||||
love.arg.parseOptions()
|
||||
|
||||
local o = love.arg.options
|
||||
|
||||
local is_fused_game = can_has_game or love.arg.options.fused.set
|
||||
|
||||
love.filesystem.setFused(is_fused_game)
|
||||
|
||||
love.setDeprecationOutput(not love.filesystem.isFused())
|
||||
|
||||
local identity = ""
|
||||
if not can_has_game and o.game.set and o.game.arg[1] then
|
||||
local nouri = o.game.arg[1]
|
||||
|
||||
if nouri:sub(1, 7) == "file://" then
|
||||
nouri = uridecode(nouri:sub(8))
|
||||
end
|
||||
|
||||
local full_source = love.path.getFull(nouri)
|
||||
can_has_game = pcall(love.filesystem.setSource, full_source)
|
||||
|
||||
if not can_has_game then
|
||||
invalid_game_path = full_source
|
||||
end
|
||||
|
||||
-- Use the name of the source .love as the identity for now.
|
||||
identity = love.path.leaf(full_source)
|
||||
else
|
||||
-- Use the name of the exe as the identity for now.
|
||||
identity = love.path.leaf(exepath)
|
||||
end
|
||||
|
||||
-- Try to use the archive containing main.lua as the identity name. It
|
||||
-- might not be available, in which case the fallbacks above are used.
|
||||
local realdir = love.filesystem.getRealDirectory("main.lua")
|
||||
if realdir then
|
||||
identity = love.path.leaf(realdir)
|
||||
end
|
||||
|
||||
identity = identity:gsub("^([%.]+)", "") -- strip leading "."'s
|
||||
identity = identity:gsub("%.([^%.]+)$", "") -- strip extension
|
||||
identity = identity:gsub("%.", "_") -- replace remaining "."'s with "_"
|
||||
identity = #identity > 0 and identity or "lovegame"
|
||||
|
||||
-- When conf.lua is initially loaded, the main source should be checked
|
||||
-- before the save directory (the identity should be appended.)
|
||||
pcall(love.filesystem.setIdentity, identity, true)
|
||||
|
||||
if can_has_game and not (love.filesystem.getInfo("main.lua") or love.filesystem.getInfo("conf.lua")) then
|
||||
no_game_code = true
|
||||
end
|
||||
|
||||
if not can_has_game then
|
||||
local nogame = require("love.nogame")
|
||||
nogame()
|
||||
end
|
||||
end
|
||||
|
||||
function love.init()
|
||||
|
||||
-- Create default configuration settings.
|
||||
-- NOTE: Adding a new module to the modules list
|
||||
-- will NOT make it load, see below.
|
||||
local c = {
|
||||
title = "Untitled",
|
||||
version = love._version,
|
||||
window = {
|
||||
width = 800,
|
||||
height = 600,
|
||||
x = nil,
|
||||
y = nil,
|
||||
minwidth = 1,
|
||||
minheight = 1,
|
||||
fullscreen = false,
|
||||
fullscreentype = "desktop",
|
||||
display = 1,
|
||||
vsync = 1,
|
||||
msaa = 0,
|
||||
borderless = false,
|
||||
resizable = false,
|
||||
centered = true,
|
||||
highdpi = false,
|
||||
usedpiscale = true,
|
||||
},
|
||||
modules = {
|
||||
data = true,
|
||||
event = true,
|
||||
keyboard = true,
|
||||
mouse = true,
|
||||
timer = true,
|
||||
joystick = true,
|
||||
touch = true,
|
||||
image = true,
|
||||
graphics = true,
|
||||
audio = true,
|
||||
math = true,
|
||||
physics = true,
|
||||
sound = true,
|
||||
system = true,
|
||||
font = true,
|
||||
thread = true,
|
||||
window = true,
|
||||
video = true,
|
||||
},
|
||||
audio = {
|
||||
mixwithsystem = true, -- Only relevant for Android / iOS.
|
||||
mic = false, -- Only relevant for Android.
|
||||
},
|
||||
console = false, -- Only relevant for windows.
|
||||
identity = false,
|
||||
appendidentity = false,
|
||||
externalstorage = false, -- Only relevant for Android.
|
||||
accelerometerjoystick = true, -- Only relevant for Android / iOS.
|
||||
gammacorrect = false,
|
||||
}
|
||||
|
||||
-- Console hack, part 1.
|
||||
local openedconsole = false
|
||||
if love.arg.options.console.set and love._openConsole then
|
||||
love._openConsole()
|
||||
openedconsole = true
|
||||
end
|
||||
|
||||
-- If config file exists, load it and allow it to update config table.
|
||||
local confok, conferr
|
||||
if (not love.conf) and love.filesystem and love.filesystem.getInfo("conf.lua") then
|
||||
confok, conferr = pcall(require, "conf")
|
||||
end
|
||||
|
||||
-- Yes, conf.lua might not exist, but there are other ways of making
|
||||
-- love.conf appear, so we should check for it anyway.
|
||||
if love.conf then
|
||||
confok, conferr = pcall(love.conf, c)
|
||||
-- If love.conf errors, we'll trigger the error after loading modules so
|
||||
-- the error message can be displayed in the window.
|
||||
end
|
||||
|
||||
-- Console hack, part 2.
|
||||
if c.console and love._openConsole and not openedconsole then
|
||||
love._openConsole()
|
||||
end
|
||||
|
||||
-- Hack for disabling accelerometer-as-joystick on Android / iOS.
|
||||
if love._setAccelerometerAsJoystick then
|
||||
love._setAccelerometerAsJoystick(c.accelerometerjoystick)
|
||||
end
|
||||
|
||||
if love._setGammaCorrect then
|
||||
love._setGammaCorrect(c.gammacorrect)
|
||||
end
|
||||
|
||||
if love._setAudioMixWithSystem then
|
||||
if c.audio and c.audio.mixwithsystem ~= nil then
|
||||
love._setAudioMixWithSystem(c.audio.mixwithsystem)
|
||||
end
|
||||
end
|
||||
|
||||
if love._requestRecordingPermission then
|
||||
love._requestRecordingPermission(c.audio and c.audio.mic)
|
||||
end
|
||||
|
||||
-- Gets desired modules.
|
||||
for k,v in ipairs{
|
||||
"data",
|
||||
"thread",
|
||||
"timer",
|
||||
"event",
|
||||
"keyboard",
|
||||
"joystick",
|
||||
"mouse",
|
||||
"touch",
|
||||
"sound",
|
||||
"system",
|
||||
"audio",
|
||||
"image",
|
||||
"video",
|
||||
"font",
|
||||
"window",
|
||||
"graphics",
|
||||
"math",
|
||||
"physics",
|
||||
} do
|
||||
if c.modules[v] then
|
||||
require("love." .. v)
|
||||
end
|
||||
end
|
||||
|
||||
if love.event then
|
||||
love.createhandlers()
|
||||
end
|
||||
|
||||
-- Check the version
|
||||
c.version = tostring(c.version)
|
||||
if not love.isVersionCompatible(c.version) then
|
||||
local major, minor, revision = c.version:match("^(%d+)%.(%d+)%.(%d+)$")
|
||||
if (not major or not minor or not revision) or (major ~= love._version_major and minor ~= love._version_minor) then
|
||||
local msg = ("This game indicates it was made for version '%s' of LOVE.\n"..
|
||||
"It may not be compatible with the running version (%s)."):format(c.version, love._version)
|
||||
|
||||
print(msg)
|
||||
|
||||
if love.window then
|
||||
love.window.showMessageBox("Compatibility Warning", msg, "warning")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not confok and conferr then
|
||||
error(conferr)
|
||||
end
|
||||
|
||||
-- Setup window here.
|
||||
if c.window and c.modules.window then
|
||||
love.window.setTitle(c.window.title or c.title)
|
||||
assert(love.window.setMode(c.window.width, c.window.height,
|
||||
{
|
||||
fullscreen = c.window.fullscreen,
|
||||
fullscreentype = c.window.fullscreentype,
|
||||
vsync = c.window.vsync,
|
||||
msaa = c.window.msaa,
|
||||
stencil = c.window.stencil,
|
||||
depth = c.window.depth,
|
||||
resizable = c.window.resizable,
|
||||
minwidth = c.window.minwidth,
|
||||
minheight = c.window.minheight,
|
||||
borderless = c.window.borderless,
|
||||
centered = c.window.centered,
|
||||
display = c.window.display,
|
||||
highdpi = c.window.highdpi,
|
||||
usedpiscale = c.window.usedpiscale,
|
||||
x = c.window.x,
|
||||
y = c.window.y,
|
||||
}), "Could not set window mode")
|
||||
if c.window.icon then
|
||||
assert(love.image, "If an icon is set in love.conf, love.image must be loaded!")
|
||||
love.window.setIcon(love.image.newImageData(c.window.icon))
|
||||
end
|
||||
end
|
||||
|
||||
-- Our first timestep, because window creation can take some time
|
||||
if love.timer then
|
||||
love.timer.step()
|
||||
end
|
||||
|
||||
if love.filesystem then
|
||||
love.filesystem._setAndroidSaveExternal(c.externalstorage)
|
||||
love.filesystem.setIdentity(c.identity or love.filesystem.getIdentity(), c.appendidentity)
|
||||
if love.filesystem.getInfo("main.lua") then
|
||||
require("main")
|
||||
end
|
||||
end
|
||||
|
||||
if no_game_code then
|
||||
error("No code to run\nYour game might be packaged incorrectly.\nMake sure main.lua is at the top level of the zip.")
|
||||
elseif invalid_game_path then
|
||||
error("Cannot load game at path '" .. invalid_game_path .. "'.\nMake sure a folder exists at the specified path.")
|
||||
end
|
||||
end
|
||||
|
||||
local print, debug, tostring = print, debug, tostring
|
||||
|
||||
local function error_printer(msg, layer)
|
||||
print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", "")))
|
||||
end
|
||||
|
||||
-----------------------------------------------------------
|
||||
-- The root of all calls.
|
||||
-----------------------------------------------------------
|
||||
|
||||
return function()
|
||||
local func
|
||||
local inerror = false
|
||||
|
||||
local function deferErrhand(...)
|
||||
local errhand = love.errorhandler or love.errhand
|
||||
local handler = (not inerror and errhand) or error_printer
|
||||
inerror = true
|
||||
func = handler(...)
|
||||
end
|
||||
|
||||
local function earlyinit()
|
||||
-- If love.boot fails, return 1 and finish immediately
|
||||
local result = xpcall(love.boot, error_printer)
|
||||
if not result then return 1 end
|
||||
|
||||
-- If love.init or love.run fails, don't return a value,
|
||||
-- as we want the error handler to take over
|
||||
result = xpcall(love.init, deferErrhand)
|
||||
if not result then return end
|
||||
|
||||
-- NOTE: We can't assign to func directly, as we'd
|
||||
-- overwrite the result of deferErrhand with nil on error
|
||||
local main
|
||||
result, main = xpcall(love.run, deferErrhand)
|
||||
if result then
|
||||
func = main
|
||||
end
|
||||
end
|
||||
|
||||
func = earlyinit
|
||||
|
||||
while func do
|
||||
local _, retval = xpcall(func, deferErrhand)
|
||||
if retval then return retval end
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
return 1
|
||||
end
|
||||
|
||||
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
|
||||
--)luastring"--"
|
||||
@@ -0,0 +1,316 @@
|
||||
R"luastring"--(
|
||||
-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string.
|
||||
-- There is a matching delimiter at the bottom of the file.
|
||||
|
||||
--[[
|
||||
Copyright (c) 2006-2021 LOVE Development Team
|
||||
|
||||
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, and to 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 love = require("love")
|
||||
|
||||
function love.createhandlers()
|
||||
|
||||
-- Standard callback handlers.
|
||||
love.handlers = setmetatable({
|
||||
keypressed = function (b,s,r)
|
||||
if love.keypressed then return love.keypressed(b,s,r) end
|
||||
end,
|
||||
keyreleased = function (b,s)
|
||||
if love.keyreleased then return love.keyreleased(b,s) end
|
||||
end,
|
||||
textinput = function (t)
|
||||
if love.textinput then return love.textinput(t) end
|
||||
end,
|
||||
textedited = function (t,s,l)
|
||||
if love.textedited then return love.textedited(t,s,l) end
|
||||
end,
|
||||
mousemoved = function (x,y,dx,dy,t)
|
||||
if love.mousemoved then return love.mousemoved(x,y,dx,dy,t) end
|
||||
end,
|
||||
mousepressed = function (x,y,b,t,c)
|
||||
if love.mousepressed then return love.mousepressed(x,y,b,t,c) end
|
||||
end,
|
||||
mousereleased = function (x,y,b,t,c)
|
||||
if love.mousereleased then return love.mousereleased(x,y,b,t,c) end
|
||||
end,
|
||||
wheelmoved = function (x,y)
|
||||
if love.wheelmoved then return love.wheelmoved(x,y) end
|
||||
end,
|
||||
touchpressed = function (id,x,y,dx,dy,p)
|
||||
if love.touchpressed then return love.touchpressed(id,x,y,dx,dy,p) end
|
||||
end,
|
||||
touchreleased = function (id,x,y,dx,dy,p)
|
||||
if love.touchreleased then return love.touchreleased(id,x,y,dx,dy,p) end
|
||||
end,
|
||||
touchmoved = function (id,x,y,dx,dy,p)
|
||||
if love.touchmoved then return love.touchmoved(id,x,y,dx,dy,p) end
|
||||
end,
|
||||
joystickpressed = function (j,b)
|
||||
if love.joystickpressed then return love.joystickpressed(j,b) end
|
||||
end,
|
||||
joystickreleased = function (j,b)
|
||||
if love.joystickreleased then return love.joystickreleased(j,b) end
|
||||
end,
|
||||
joystickaxis = function (j,a,v)
|
||||
if love.joystickaxis then return love.joystickaxis(j,a,v) end
|
||||
end,
|
||||
joystickhat = function (j,h,v)
|
||||
if love.joystickhat then return love.joystickhat(j,h,v) end
|
||||
end,
|
||||
gamepadpressed = function (j,b)
|
||||
if love.gamepadpressed then return love.gamepadpressed(j,b) end
|
||||
end,
|
||||
gamepadreleased = function (j,b)
|
||||
if love.gamepadreleased then return love.gamepadreleased(j,b) end
|
||||
end,
|
||||
gamepadaxis = function (j,a,v)
|
||||
if love.gamepadaxis then return love.gamepadaxis(j,a,v) end
|
||||
end,
|
||||
joystickadded = function (j)
|
||||
if love.joystickadded then return love.joystickadded(j) end
|
||||
end,
|
||||
joystickremoved = function (j)
|
||||
if love.joystickremoved then return love.joystickremoved(j) end
|
||||
end,
|
||||
focus = function (f)
|
||||
if love.focus then return love.focus(f) end
|
||||
end,
|
||||
mousefocus = function (f)
|
||||
if love.mousefocus then return love.mousefocus(f) end
|
||||
end,
|
||||
visible = function (v)
|
||||
if love.visible then return love.visible(v) end
|
||||
end,
|
||||
quit = function ()
|
||||
return
|
||||
end,
|
||||
threaderror = function (t, err)
|
||||
if love.threaderror then return love.threaderror(t, err) end
|
||||
end,
|
||||
resize = function (w, h)
|
||||
if love.resize then return love.resize(w, h) end
|
||||
end,
|
||||
filedropped = function (f)
|
||||
if love.filedropped then return love.filedropped(f) end
|
||||
end,
|
||||
directorydropped = function (dir)
|
||||
if love.directorydropped then return love.directorydropped(dir) end
|
||||
end,
|
||||
lowmemory = function ()
|
||||
if love.lowmemory then love.lowmemory() end
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
end,
|
||||
displayrotated = function (display, orient)
|
||||
if love.displayrotated then return love.displayrotated(display, orient) end
|
||||
end,
|
||||
}, {
|
||||
__index = function(self, name)
|
||||
error("Unknown event: " .. name)
|
||||
end,
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
-----------------------------------------------------------
|
||||
-- Default callbacks.
|
||||
-----------------------------------------------------------
|
||||
|
||||
function love.run()
|
||||
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
|
||||
|
||||
-- We don't want the first frame's dt to include time taken by love.load.
|
||||
if love.timer then love.timer.step() end
|
||||
|
||||
local dt = 0
|
||||
|
||||
-- Main loop time.
|
||||
return function()
|
||||
-- Process events.
|
||||
if love.event then
|
||||
love.event.pump()
|
||||
for name, a,b,c,d,e,f in love.event.poll() do
|
||||
if name == "quit" then
|
||||
if not love.quit or not love.quit() then
|
||||
return a or 0
|
||||
end
|
||||
end
|
||||
love.handlers[name](a,b,c,d,e,f)
|
||||
end
|
||||
end
|
||||
|
||||
-- Update dt, as we'll be passing it to update
|
||||
if love.timer then dt = love.timer.step() end
|
||||
|
||||
-- Call update and draw
|
||||
if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
|
||||
|
||||
if love.graphics and love.graphics.isActive() then
|
||||
love.graphics.origin()
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
|
||||
if love.draw then love.draw() end
|
||||
|
||||
love.graphics.present()
|
||||
end
|
||||
|
||||
if love.timer then love.timer.sleep(0.001) end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local debug, print, tostring, error = debug, print, tostring, error
|
||||
|
||||
function love.threaderror(t, err)
|
||||
error("Thread error ("..tostring(t)..")\n\n"..err, 0)
|
||||
end
|
||||
|
||||
local utf8 = require("utf8")
|
||||
|
||||
local function error_printer(msg, layer)
|
||||
print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", "")))
|
||||
end
|
||||
|
||||
function love.errhand(msg)
|
||||
msg = tostring(msg)
|
||||
|
||||
error_printer(msg, 2)
|
||||
|
||||
if not love.window or not love.graphics or not love.event then
|
||||
return
|
||||
end
|
||||
|
||||
if not love.graphics.isCreated() or not love.window.isOpen() then
|
||||
local success, status = pcall(love.window.setMode, 800, 600)
|
||||
if not success or not status then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Reset state.
|
||||
if love.mouse then
|
||||
love.mouse.setVisible(true)
|
||||
love.mouse.setGrabbed(false)
|
||||
love.mouse.setRelativeMode(false)
|
||||
if love.mouse.isCursorSupported() then
|
||||
love.mouse.setCursor()
|
||||
end
|
||||
end
|
||||
if love.joystick then
|
||||
-- Stop all joystick vibrations.
|
||||
for i,v in ipairs(love.joystick.getJoysticks()) do
|
||||
v:setVibration()
|
||||
end
|
||||
end
|
||||
if love.audio then love.audio.stop() end
|
||||
|
||||
love.graphics.reset()
|
||||
local font = love.graphics.setNewFont(14)
|
||||
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
|
||||
local trace = debug.traceback()
|
||||
|
||||
love.graphics.origin()
|
||||
|
||||
local sanitizedmsg = {}
|
||||
for char in msg:gmatch(utf8.charpattern) do
|
||||
table.insert(sanitizedmsg, char)
|
||||
end
|
||||
sanitizedmsg = table.concat(sanitizedmsg)
|
||||
|
||||
local err = {}
|
||||
|
||||
table.insert(err, "Error\n")
|
||||
table.insert(err, sanitizedmsg)
|
||||
|
||||
if #sanitizedmsg ~= #msg then
|
||||
table.insert(err, "Invalid UTF-8 string in error message.")
|
||||
end
|
||||
|
||||
table.insert(err, "\n")
|
||||
|
||||
for l in trace:gmatch("(.-)\n") do
|
||||
if not l:match("boot.lua") then
|
||||
l = l:gsub("stack traceback:", "Traceback\n")
|
||||
table.insert(err, l)
|
||||
end
|
||||
end
|
||||
|
||||
local p = table.concat(err, "\n")
|
||||
|
||||
p = p:gsub("\t", "")
|
||||
p = p:gsub("%[string \"(.-)\"%]", "%1")
|
||||
|
||||
local function draw()
|
||||
local pos = 70
|
||||
love.graphics.clear(89/255, 157/255, 220/255)
|
||||
love.graphics.printf(p, pos, pos, love.graphics.getWidth() - pos)
|
||||
love.graphics.present()
|
||||
end
|
||||
|
||||
local fullErrorText = p
|
||||
local function copyToClipboard()
|
||||
if not love.system then return end
|
||||
love.system.setClipboardText(fullErrorText)
|
||||
p = p .. "\nCopied to clipboard!"
|
||||
draw()
|
||||
end
|
||||
|
||||
if love.system then
|
||||
p = p .. "\n\nPress Ctrl+C or tap to copy this error"
|
||||
end
|
||||
|
||||
return function()
|
||||
love.event.pump()
|
||||
|
||||
for e, a, b, c in love.event.poll() do
|
||||
if e == "quit" then
|
||||
return 1
|
||||
elseif e == "keypressed" and a == "escape" then
|
||||
return 1
|
||||
elseif e == "keypressed" and a == "c" and love.keyboard.isDown("lctrl", "rctrl") then
|
||||
copyToClipboard()
|
||||
elseif e == "touchpressed" then
|
||||
local name = love.window.getTitle()
|
||||
if #name == 0 or name == "Untitled" then name = "Game" end
|
||||
local buttons = {"OK", "Cancel"}
|
||||
if love.system then
|
||||
buttons[3] = "Copy to clipboard"
|
||||
end
|
||||
local pressed = love.window.showMessageBox("Quit "..name.."?", "", buttons)
|
||||
if pressed == 1 then
|
||||
return 1
|
||||
elseif pressed == 3 then
|
||||
copyToClipboard()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
draw()
|
||||
|
||||
if love.timer then
|
||||
love.timer.sleep(0.1)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
|
||||
--)luastring"--"
|
||||
@@ -81,9 +81,21 @@ extern "C"
|
||||
# include "audio/Audio.h"
|
||||
#endif
|
||||
|
||||
// Scripts
|
||||
// Scripts.
|
||||
#include "scripts/nogame.lua.h"
|
||||
#include "scripts/boot.lua.h"
|
||||
|
||||
// Put the Lua code directly into a raw string literal.
|
||||
static const char arg_lua[] =
|
||||
#include "arg.lua"
|
||||
;
|
||||
|
||||
static const char callbacks_lua[] =
|
||||
#include "callbacks.lua"
|
||||
;
|
||||
|
||||
static const char boot_lua[] =
|
||||
#include "boot.lua"
|
||||
;
|
||||
|
||||
// All modules define a c-accessible luaopen
|
||||
// so let's make use of those, instead
|
||||
@@ -148,6 +160,8 @@ extern "C"
|
||||
extern int luaopen_love_window(lua_State*);
|
||||
#endif
|
||||
extern int luaopen_love_nogame(lua_State*);
|
||||
extern int luaopen_love_arg(lua_State*);
|
||||
extern int luaopen_love_callbacks(lua_State*);
|
||||
extern int luaopen_love_boot(lua_State*);
|
||||
}
|
||||
|
||||
@@ -210,6 +224,8 @@ static const luaL_Reg modules[] = {
|
||||
{ "love.window", luaopen_love_window },
|
||||
#endif
|
||||
{ "love.nogame", luaopen_love_nogame },
|
||||
{ "love.arg", luaopen_love_arg },
|
||||
{ "love.callbacks", luaopen_love_callbacks },
|
||||
{ "love.boot", luaopen_love_boot },
|
||||
{ 0, 0 }
|
||||
};
|
||||
@@ -641,13 +657,26 @@ int luaopen_love_nogame(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int luaopen_love_boot(lua_State *L)
|
||||
int luaopen_love_arg(lua_State *L)
|
||||
{
|
||||
if (luaL_loadbuffer(L, (const char *)love::boot_lua, sizeof(love::boot_lua), "boot.lua") == 0)
|
||||
if (luaL_loadbuffer(L, arg_lua, sizeof(arg_lua), "arg.lua") == 0)
|
||||
lua_call(L, 0, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int luaopen_love_callbacks(lua_State *L)
|
||||
{
|
||||
if (luaL_loadbuffer(L, callbacks_lua, sizeof(callbacks_lua), "callbacks.lua") == 0)
|
||||
lua_call(L, 0, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int luaopen_love_boot(lua_State *L)
|
||||
{
|
||||
if (luaL_loadbuffer(L, boot_lua, sizeof(boot_lua), "boot.lua") == 0)
|
||||
lua_call(L, 0, 1);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,808 +0,0 @@
|
||||
--[[
|
||||
Copyright (c) 2006-2021 LOVE Development Team
|
||||
|
||||
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, and to 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.
|
||||
--]]
|
||||
|
||||
-- Make sure love exists.
|
||||
local love = require("love")
|
||||
|
||||
-- Used for setup:
|
||||
love.path = {}
|
||||
love.arg = {}
|
||||
|
||||
-- Replace any \ with /.
|
||||
function love.path.normalslashes(p)
|
||||
return p:gsub("\\", "/")
|
||||
end
|
||||
|
||||
-- Makes sure there is a slash at the end
|
||||
-- of a path.
|
||||
function love.path.endslash(p)
|
||||
if p:sub(-1) ~= "/" then
|
||||
return p .. "/"
|
||||
else
|
||||
return p
|
||||
end
|
||||
end
|
||||
|
||||
-- Checks whether a path is absolute or not.
|
||||
function love.path.abs(p)
|
||||
|
||||
local tmp = love.path.normalslashes(p)
|
||||
|
||||
-- Path is absolute if it starts with a "/".
|
||||
if tmp:find("/") == 1 then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Path is absolute if it starts with a
|
||||
-- letter followed by a colon.
|
||||
if tmp:find("%a:") == 1 then
|
||||
return true
|
||||
end
|
||||
|
||||
-- Relative.
|
||||
return false
|
||||
|
||||
end
|
||||
|
||||
-- Converts any path into a full path.
|
||||
function love.path.getFull(p)
|
||||
|
||||
if love.path.abs(p) then
|
||||
return love.path.normalslashes(p)
|
||||
end
|
||||
|
||||
local cwd = love.filesystem.getWorkingDirectory()
|
||||
cwd = love.path.normalslashes(cwd)
|
||||
cwd = love.path.endslash(cwd)
|
||||
|
||||
-- Construct a full path.
|
||||
local full = cwd .. love.path.normalslashes(p)
|
||||
|
||||
-- Remove trailing /., if applicable
|
||||
return full:match("(.-)/%.$") or full
|
||||
end
|
||||
|
||||
-- Returns the leaf of a full path.
|
||||
function love.path.leaf(p)
|
||||
p = love.path.normalslashes(p)
|
||||
|
||||
local a = 1
|
||||
local last = p
|
||||
|
||||
while a do
|
||||
a = p:find("/", a+1)
|
||||
|
||||
if a then
|
||||
last = p:sub(a+1)
|
||||
end
|
||||
end
|
||||
|
||||
return last
|
||||
end
|
||||
|
||||
-- Finds the key in the table with the lowest integral index. The lowest
|
||||
-- will typically the executable, for instance "lua5.1.exe".
|
||||
function love.arg.getLow(a)
|
||||
local m = math.huge
|
||||
for k,v in pairs(a) do
|
||||
if k < m then
|
||||
m = k
|
||||
end
|
||||
end
|
||||
return a[m], m
|
||||
end
|
||||
|
||||
love.arg.options = {
|
||||
console = { a = 0 },
|
||||
fused = {a = 0 },
|
||||
game = { a = 1 }
|
||||
}
|
||||
|
||||
love.arg.optionIndices = {}
|
||||
|
||||
function love.arg.parseOption(m, i)
|
||||
m.set = true
|
||||
|
||||
if m.a > 0 then
|
||||
m.arg = {}
|
||||
for j=i,i+m.a-1 do
|
||||
love.arg.optionIndices[j] = true
|
||||
table.insert(m.arg, arg[j])
|
||||
end
|
||||
end
|
||||
|
||||
return m.a
|
||||
end
|
||||
|
||||
function love.arg.parseOptions()
|
||||
|
||||
local game
|
||||
local argc = #arg
|
||||
|
||||
local i = 1
|
||||
while i <= argc do
|
||||
-- Look for options.
|
||||
local m = arg[i]:match("^%-%-(.*)")
|
||||
|
||||
if m and m ~= "" and love.arg.options[m] and not love.arg.options[m].set then
|
||||
love.arg.optionIndices[i] = true
|
||||
i = i + love.arg.parseOption(love.arg.options[m], i+1)
|
||||
elseif m == "" then -- handle '--' as an option
|
||||
love.arg.optionIndices[i] = true
|
||||
if not game then -- handle '--' followed by game name
|
||||
game = i + 1
|
||||
end
|
||||
break
|
||||
elseif not game then
|
||||
game = i
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
|
||||
if not love.arg.options.game.set then
|
||||
love.arg.parseOption(love.arg.options.game, game or 0)
|
||||
end
|
||||
end
|
||||
|
||||
-- Returns the arguments that are passed to your game via love.load()
|
||||
-- arguments that were parsed as options are skipped.
|
||||
function love.arg.parseGameArguments(a)
|
||||
local out = {}
|
||||
|
||||
local _, lowindex = love.arg.getLow(a)
|
||||
|
||||
local o = lowindex
|
||||
for i=lowindex, #a do
|
||||
if not love.arg.optionIndices[i] then
|
||||
out[o] = a[i]
|
||||
o = o + 1
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
function love.createhandlers()
|
||||
|
||||
-- Standard callback handlers.
|
||||
love.handlers = setmetatable({
|
||||
keypressed = function (b,s,r)
|
||||
if love.keypressed then return love.keypressed(b,s,r) end
|
||||
end,
|
||||
keyreleased = function (b,s)
|
||||
if love.keyreleased then return love.keyreleased(b,s) end
|
||||
end,
|
||||
textinput = function (t)
|
||||
if love.textinput then return love.textinput(t) end
|
||||
end,
|
||||
textedited = function (t,s,l)
|
||||
if love.textedited then return love.textedited(t,s,l) end
|
||||
end,
|
||||
mousemoved = function (x,y,dx,dy,t)
|
||||
if love.mousemoved then return love.mousemoved(x,y,dx,dy,t) end
|
||||
end,
|
||||
mousepressed = function (x,y,b,t,c)
|
||||
if love.mousepressed then return love.mousepressed(x,y,b,t,c) end
|
||||
end,
|
||||
mousereleased = function (x,y,b,t,c)
|
||||
if love.mousereleased then return love.mousereleased(x,y,b,t,c) end
|
||||
end,
|
||||
wheelmoved = function (x,y)
|
||||
if love.wheelmoved then return love.wheelmoved(x,y) end
|
||||
end,
|
||||
touchpressed = function (id,x,y,dx,dy,p)
|
||||
if love.touchpressed then return love.touchpressed(id,x,y,dx,dy,p) end
|
||||
end,
|
||||
touchreleased = function (id,x,y,dx,dy,p)
|
||||
if love.touchreleased then return love.touchreleased(id,x,y,dx,dy,p) end
|
||||
end,
|
||||
touchmoved = function (id,x,y,dx,dy,p)
|
||||
if love.touchmoved then return love.touchmoved(id,x,y,dx,dy,p) end
|
||||
end,
|
||||
joystickpressed = function (j,b)
|
||||
if love.joystickpressed then return love.joystickpressed(j,b) end
|
||||
end,
|
||||
joystickreleased = function (j,b)
|
||||
if love.joystickreleased then return love.joystickreleased(j,b) end
|
||||
end,
|
||||
joystickaxis = function (j,a,v)
|
||||
if love.joystickaxis then return love.joystickaxis(j,a,v) end
|
||||
end,
|
||||
joystickhat = function (j,h,v)
|
||||
if love.joystickhat then return love.joystickhat(j,h,v) end
|
||||
end,
|
||||
gamepadpressed = function (j,b)
|
||||
if love.gamepadpressed then return love.gamepadpressed(j,b) end
|
||||
end,
|
||||
gamepadreleased = function (j,b)
|
||||
if love.gamepadreleased then return love.gamepadreleased(j,b) end
|
||||
end,
|
||||
gamepadaxis = function (j,a,v)
|
||||
if love.gamepadaxis then return love.gamepadaxis(j,a,v) end
|
||||
end,
|
||||
joystickadded = function (j)
|
||||
if love.joystickadded then return love.joystickadded(j) end
|
||||
end,
|
||||
joystickremoved = function (j)
|
||||
if love.joystickremoved then return love.joystickremoved(j) end
|
||||
end,
|
||||
focus = function (f)
|
||||
if love.focus then return love.focus(f) end
|
||||
end,
|
||||
mousefocus = function (f)
|
||||
if love.mousefocus then return love.mousefocus(f) end
|
||||
end,
|
||||
visible = function (v)
|
||||
if love.visible then return love.visible(v) end
|
||||
end,
|
||||
quit = function ()
|
||||
return
|
||||
end,
|
||||
threaderror = function (t, err)
|
||||
if love.threaderror then return love.threaderror(t, err) end
|
||||
end,
|
||||
resize = function (w, h)
|
||||
if love.resize then return love.resize(w, h) end
|
||||
end,
|
||||
filedropped = function (f)
|
||||
if love.filedropped then return love.filedropped(f) end
|
||||
end,
|
||||
directorydropped = function (dir)
|
||||
if love.directorydropped then return love.directorydropped(dir) end
|
||||
end,
|
||||
lowmemory = function ()
|
||||
if love.lowmemory then love.lowmemory() end
|
||||
collectgarbage()
|
||||
collectgarbage()
|
||||
end,
|
||||
displayrotated = function (display, orient)
|
||||
if love.displayrotated then return love.displayrotated(display, orient) end
|
||||
end,
|
||||
}, {
|
||||
__index = function(self, name)
|
||||
error("Unknown event: " .. name)
|
||||
end,
|
||||
})
|
||||
|
||||
end
|
||||
|
||||
local function uridecode(s)
|
||||
return s:gsub("%%%x%x", function(str)
|
||||
return string.char(tonumber(str:sub(2), 16))
|
||||
end)
|
||||
end
|
||||
|
||||
local no_game_code = false
|
||||
local invalid_game_path = nil
|
||||
|
||||
-- This can't be overridden.
|
||||
function love.boot()
|
||||
|
||||
-- This is absolutely needed.
|
||||
require("love.filesystem")
|
||||
|
||||
local arg0 = love.arg.getLow(arg)
|
||||
love.filesystem.init(arg0)
|
||||
|
||||
local exepath = love.filesystem.getExecutablePath()
|
||||
if #exepath == 0 then
|
||||
-- This shouldn't happen, but just in case we'll fall back to arg0.
|
||||
exepath = arg0
|
||||
end
|
||||
|
||||
no_game_code = false
|
||||
invalid_game_path = nil
|
||||
|
||||
-- Is this one of those fancy "fused" games?
|
||||
local can_has_game = pcall(love.filesystem.setSource, exepath)
|
||||
|
||||
-- It's a fused game, don't parse --game argument
|
||||
if can_has_game then
|
||||
love.arg.options.game.set = true
|
||||
end
|
||||
|
||||
-- Parse options now that we know which options we're looking for.
|
||||
love.arg.parseOptions()
|
||||
|
||||
local o = love.arg.options
|
||||
|
||||
local is_fused_game = can_has_game or love.arg.options.fused.set
|
||||
|
||||
love.filesystem.setFused(is_fused_game)
|
||||
|
||||
love.setDeprecationOutput(not love.filesystem.isFused())
|
||||
|
||||
local identity = ""
|
||||
if not can_has_game and o.game.set and o.game.arg[1] then
|
||||
local nouri = o.game.arg[1]
|
||||
|
||||
if nouri:sub(1, 7) == "file://" then
|
||||
nouri = uridecode(nouri:sub(8))
|
||||
end
|
||||
|
||||
local full_source = love.path.getFull(nouri)
|
||||
can_has_game = pcall(love.filesystem.setSource, full_source)
|
||||
|
||||
if not can_has_game then
|
||||
invalid_game_path = full_source
|
||||
end
|
||||
|
||||
-- Use the name of the source .love as the identity for now.
|
||||
identity = love.path.leaf(full_source)
|
||||
else
|
||||
-- Use the name of the exe as the identity for now.
|
||||
identity = love.path.leaf(exepath)
|
||||
end
|
||||
|
||||
-- Try to use the archive containing main.lua as the identity name. It
|
||||
-- might not be available, in which case the fallbacks above are used.
|
||||
local realdir = love.filesystem.getRealDirectory("main.lua")
|
||||
if realdir then
|
||||
identity = love.path.leaf(realdir)
|
||||
end
|
||||
|
||||
identity = identity:gsub("^([%.]+)", "") -- strip leading "."'s
|
||||
identity = identity:gsub("%.([^%.]+)$", "") -- strip extension
|
||||
identity = identity:gsub("%.", "_") -- replace remaining "."'s with "_"
|
||||
identity = #identity > 0 and identity or "lovegame"
|
||||
|
||||
-- When conf.lua is initially loaded, the main source should be checked
|
||||
-- before the save directory (the identity should be appended.)
|
||||
pcall(love.filesystem.setIdentity, identity, true)
|
||||
|
||||
if can_has_game and not (love.filesystem.getInfo("main.lua") or love.filesystem.getInfo("conf.lua")) then
|
||||
no_game_code = true
|
||||
end
|
||||
|
||||
if not can_has_game then
|
||||
local nogame = require("love.nogame")
|
||||
nogame()
|
||||
end
|
||||
end
|
||||
|
||||
function love.init()
|
||||
|
||||
-- Create default configuration settings.
|
||||
-- NOTE: Adding a new module to the modules list
|
||||
-- will NOT make it load, see below.
|
||||
local c = {
|
||||
title = "Untitled",
|
||||
version = love._version,
|
||||
window = {
|
||||
width = 800,
|
||||
height = 600,
|
||||
x = nil,
|
||||
y = nil,
|
||||
minwidth = 1,
|
||||
minheight = 1,
|
||||
fullscreen = false,
|
||||
fullscreentype = "desktop",
|
||||
display = 1,
|
||||
vsync = 1,
|
||||
msaa = 0,
|
||||
borderless = false,
|
||||
resizable = false,
|
||||
centered = true,
|
||||
highdpi = false,
|
||||
usedpiscale = true,
|
||||
},
|
||||
modules = {
|
||||
data = true,
|
||||
event = true,
|
||||
keyboard = true,
|
||||
mouse = true,
|
||||
timer = true,
|
||||
joystick = true,
|
||||
touch = true,
|
||||
image = true,
|
||||
graphics = true,
|
||||
audio = true,
|
||||
math = true,
|
||||
physics = true,
|
||||
sound = true,
|
||||
system = true,
|
||||
font = true,
|
||||
thread = true,
|
||||
window = true,
|
||||
video = true,
|
||||
},
|
||||
audio = {
|
||||
mixwithsystem = true, -- Only relevant for Android / iOS.
|
||||
mic = false, -- Only relevant for Android.
|
||||
},
|
||||
console = false, -- Only relevant for windows.
|
||||
identity = false,
|
||||
appendidentity = false,
|
||||
externalstorage = false, -- Only relevant for Android.
|
||||
accelerometerjoystick = true, -- Only relevant for Android / iOS.
|
||||
gammacorrect = false,
|
||||
}
|
||||
|
||||
-- Console hack, part 1.
|
||||
local openedconsole = false
|
||||
if love.arg.options.console.set and love._openConsole then
|
||||
love._openConsole()
|
||||
openedconsole = true
|
||||
end
|
||||
|
||||
-- If config file exists, load it and allow it to update config table.
|
||||
local confok, conferr
|
||||
if (not love.conf) and love.filesystem and love.filesystem.getInfo("conf.lua") then
|
||||
confok, conferr = pcall(require, "conf")
|
||||
end
|
||||
|
||||
-- Yes, conf.lua might not exist, but there are other ways of making
|
||||
-- love.conf appear, so we should check for it anyway.
|
||||
if love.conf then
|
||||
confok, conferr = pcall(love.conf, c)
|
||||
-- If love.conf errors, we'll trigger the error after loading modules so
|
||||
-- the error message can be displayed in the window.
|
||||
end
|
||||
|
||||
-- Console hack, part 2.
|
||||
if c.console and love._openConsole and not openedconsole then
|
||||
love._openConsole()
|
||||
end
|
||||
|
||||
-- Hack for disabling accelerometer-as-joystick on Android / iOS.
|
||||
if love._setAccelerometerAsJoystick then
|
||||
love._setAccelerometerAsJoystick(c.accelerometerjoystick)
|
||||
end
|
||||
|
||||
if love._setGammaCorrect then
|
||||
love._setGammaCorrect(c.gammacorrect)
|
||||
end
|
||||
|
||||
if love._setAudioMixWithSystem then
|
||||
if c.audio and c.audio.mixwithsystem ~= nil then
|
||||
love._setAudioMixWithSystem(c.audio.mixwithsystem)
|
||||
end
|
||||
end
|
||||
|
||||
if love._requestRecordingPermission then
|
||||
love._requestRecordingPermission(c.audio and c.audio.mic)
|
||||
end
|
||||
|
||||
-- Gets desired modules.
|
||||
for k,v in ipairs{
|
||||
"data",
|
||||
"thread",
|
||||
"timer",
|
||||
"event",
|
||||
"keyboard",
|
||||
"joystick",
|
||||
"mouse",
|
||||
"touch",
|
||||
"sound",
|
||||
"system",
|
||||
"audio",
|
||||
"image",
|
||||
"video",
|
||||
"font",
|
||||
"window",
|
||||
"graphics",
|
||||
"math",
|
||||
"physics",
|
||||
} do
|
||||
if c.modules[v] then
|
||||
require("love." .. v)
|
||||
end
|
||||
end
|
||||
|
||||
if love.event then
|
||||
love.createhandlers()
|
||||
end
|
||||
|
||||
-- Check the version
|
||||
c.version = tostring(c.version)
|
||||
if not love.isVersionCompatible(c.version) then
|
||||
local major, minor, revision = c.version:match("^(%d+)%.(%d+)%.(%d+)$")
|
||||
if (not major or not minor or not revision) or (major ~= love._version_major and minor ~= love._version_minor) then
|
||||
local msg = ("This game indicates it was made for version '%s' of LOVE.\n"..
|
||||
"It may not be compatible with the running version (%s)."):format(c.version, love._version)
|
||||
|
||||
print(msg)
|
||||
|
||||
if love.window then
|
||||
love.window.showMessageBox("Compatibility Warning", msg, "warning")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not confok and conferr then
|
||||
error(conferr)
|
||||
end
|
||||
|
||||
-- Setup window here.
|
||||
if c.window and c.modules.window then
|
||||
love.window.setTitle(c.window.title or c.title)
|
||||
assert(love.window.setMode(c.window.width, c.window.height,
|
||||
{
|
||||
fullscreen = c.window.fullscreen,
|
||||
fullscreentype = c.window.fullscreentype,
|
||||
vsync = c.window.vsync,
|
||||
msaa = c.window.msaa,
|
||||
stencil = c.window.stencil,
|
||||
depth = c.window.depth,
|
||||
resizable = c.window.resizable,
|
||||
minwidth = c.window.minwidth,
|
||||
minheight = c.window.minheight,
|
||||
borderless = c.window.borderless,
|
||||
centered = c.window.centered,
|
||||
display = c.window.display,
|
||||
highdpi = c.window.highdpi,
|
||||
usedpiscale = c.window.usedpiscale,
|
||||
x = c.window.x,
|
||||
y = c.window.y,
|
||||
}), "Could not set window mode")
|
||||
if c.window.icon then
|
||||
assert(love.image, "If an icon is set in love.conf, love.image must be loaded!")
|
||||
love.window.setIcon(love.image.newImageData(c.window.icon))
|
||||
end
|
||||
end
|
||||
|
||||
-- Our first timestep, because window creation can take some time
|
||||
if love.timer then
|
||||
love.timer.step()
|
||||
end
|
||||
|
||||
if love.filesystem then
|
||||
love.filesystem._setAndroidSaveExternal(c.externalstorage)
|
||||
love.filesystem.setIdentity(c.identity or love.filesystem.getIdentity(), c.appendidentity)
|
||||
if love.filesystem.getInfo("main.lua") then
|
||||
require("main")
|
||||
end
|
||||
end
|
||||
|
||||
if no_game_code then
|
||||
error("No code to run\nYour game might be packaged incorrectly.\nMake sure main.lua is at the top level of the zip.")
|
||||
elseif invalid_game_path then
|
||||
error("Cannot load game at path '" .. invalid_game_path .. "'.\nMake sure a folder exists at the specified path.")
|
||||
end
|
||||
end
|
||||
|
||||
-----------------------------------------------------------
|
||||
-- Default callbacks.
|
||||
-----------------------------------------------------------
|
||||
|
||||
function love.run()
|
||||
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
|
||||
|
||||
-- We don't want the first frame's dt to include time taken by love.load.
|
||||
if love.timer then love.timer.step() end
|
||||
|
||||
local dt = 0
|
||||
|
||||
-- Main loop time.
|
||||
return function()
|
||||
-- Process events.
|
||||
if love.event then
|
||||
love.event.pump()
|
||||
for name, a,b,c,d,e,f in love.event.poll() do
|
||||
if name == "quit" then
|
||||
if not love.quit or not love.quit() then
|
||||
return a or 0
|
||||
end
|
||||
end
|
||||
love.handlers[name](a,b,c,d,e,f)
|
||||
end
|
||||
end
|
||||
|
||||
-- Update dt, as we'll be passing it to update
|
||||
if love.timer then dt = love.timer.step() end
|
||||
|
||||
-- Call update and draw
|
||||
if love.update then love.update(dt) end -- will pass 0 if love.timer is disabled
|
||||
|
||||
if love.graphics and love.graphics.isActive() then
|
||||
love.graphics.origin()
|
||||
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||
|
||||
if love.draw then love.draw() end
|
||||
|
||||
love.graphics.present()
|
||||
end
|
||||
|
||||
if love.timer then love.timer.sleep(0.001) end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
local debug, print, error = debug, print, error
|
||||
|
||||
function love.threaderror(t, err)
|
||||
error("Thread error ("..tostring(t)..")\n\n"..err, 0)
|
||||
end
|
||||
|
||||
local utf8 = require("utf8")
|
||||
|
||||
local function error_printer(msg, layer)
|
||||
print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", "")))
|
||||
end
|
||||
|
||||
function love.errhand(msg)
|
||||
msg = tostring(msg)
|
||||
|
||||
error_printer(msg, 2)
|
||||
|
||||
if not love.window or not love.graphics or not love.event then
|
||||
return
|
||||
end
|
||||
|
||||
if not love.graphics.isCreated() or not love.window.isOpen() then
|
||||
local success, status = pcall(love.window.setMode, 800, 600)
|
||||
if not success or not status then
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Reset state.
|
||||
if love.mouse then
|
||||
love.mouse.setVisible(true)
|
||||
love.mouse.setGrabbed(false)
|
||||
love.mouse.setRelativeMode(false)
|
||||
if love.mouse.isCursorSupported() then
|
||||
love.mouse.setCursor()
|
||||
end
|
||||
end
|
||||
if love.joystick then
|
||||
-- Stop all joystick vibrations.
|
||||
for i,v in ipairs(love.joystick.getJoysticks()) do
|
||||
v:setVibration()
|
||||
end
|
||||
end
|
||||
if love.audio then love.audio.stop() end
|
||||
|
||||
love.graphics.reset()
|
||||
local font = love.graphics.setNewFont(14)
|
||||
|
||||
love.graphics.setColor(1, 1, 1)
|
||||
|
||||
local trace = debug.traceback()
|
||||
|
||||
love.graphics.origin()
|
||||
|
||||
local sanitizedmsg = {}
|
||||
for char in msg:gmatch(utf8.charpattern) do
|
||||
table.insert(sanitizedmsg, char)
|
||||
end
|
||||
sanitizedmsg = table.concat(sanitizedmsg)
|
||||
|
||||
local err = {}
|
||||
|
||||
table.insert(err, "Error\n")
|
||||
table.insert(err, sanitizedmsg)
|
||||
|
||||
if #sanitizedmsg ~= #msg then
|
||||
table.insert(err, "Invalid UTF-8 string in error message.")
|
||||
end
|
||||
|
||||
table.insert(err, "\n")
|
||||
|
||||
for l in trace:gmatch("(.-)\n") do
|
||||
if not l:match("boot.lua") then
|
||||
l = l:gsub("stack traceback:", "Traceback\n")
|
||||
table.insert(err, l)
|
||||
end
|
||||
end
|
||||
|
||||
local p = table.concat(err, "\n")
|
||||
|
||||
p = p:gsub("\t", "")
|
||||
p = p:gsub("%[string \"(.-)\"%]", "%1")
|
||||
|
||||
local function draw()
|
||||
local pos = 70
|
||||
love.graphics.clear(89/255, 157/255, 220/255)
|
||||
love.graphics.printf(p, pos, pos, love.graphics.getWidth() - pos)
|
||||
love.graphics.present()
|
||||
end
|
||||
|
||||
local fullErrorText = p
|
||||
local function copyToClipboard()
|
||||
if not love.system then return end
|
||||
love.system.setClipboardText(fullErrorText)
|
||||
p = p .. "\nCopied to clipboard!"
|
||||
draw()
|
||||
end
|
||||
|
||||
if love.system then
|
||||
p = p .. "\n\nPress Ctrl+C or tap to copy this error"
|
||||
end
|
||||
|
||||
return function()
|
||||
love.event.pump()
|
||||
|
||||
for e, a, b, c in love.event.poll() do
|
||||
if e == "quit" then
|
||||
return 1
|
||||
elseif e == "keypressed" and a == "escape" then
|
||||
return 1
|
||||
elseif e == "keypressed" and a == "c" and love.keyboard.isDown("lctrl", "rctrl") then
|
||||
copyToClipboard()
|
||||
elseif e == "touchpressed" then
|
||||
local name = love.window.getTitle()
|
||||
if #name == 0 or name == "Untitled" then name = "Game" end
|
||||
local buttons = {"OK", "Cancel"}
|
||||
if love.system then
|
||||
buttons[3] = "Copy to clipboard"
|
||||
end
|
||||
local pressed = love.window.showMessageBox("Quit "..name.."?", "", buttons)
|
||||
if pressed == 1 then
|
||||
return 1
|
||||
elseif pressed == 3 then
|
||||
copyToClipboard()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
draw()
|
||||
|
||||
if love.timer then
|
||||
love.timer.sleep(0.1)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
-----------------------------------------------------------
|
||||
-- The root of all calls.
|
||||
-----------------------------------------------------------
|
||||
|
||||
return function()
|
||||
local func
|
||||
local inerror = false
|
||||
|
||||
local function deferErrhand(...)
|
||||
local errhand = love.errorhandler or love.errhand
|
||||
local handler = (not inerror and errhand) or error_printer
|
||||
inerror = true
|
||||
func = handler(...)
|
||||
end
|
||||
|
||||
local function earlyinit()
|
||||
-- If love.boot fails, return 1 and finish immediately
|
||||
local result = xpcall(love.boot, error_printer)
|
||||
if not result then return 1 end
|
||||
|
||||
-- If love.init or love.run fails, don't return a value,
|
||||
-- as we want the error handler to take over
|
||||
result = xpcall(love.init, deferErrhand)
|
||||
if not result then return end
|
||||
|
||||
-- NOTE: We can't assign to func directly, as we'd
|
||||
-- overwrite the result of deferErrhand with nil on error
|
||||
local main
|
||||
result, main = xpcall(love.run, deferErrhand)
|
||||
if result then
|
||||
func = main
|
||||
end
|
||||
end
|
||||
|
||||
func = earlyinit
|
||||
|
||||
while func do
|
||||
local _, retval = xpcall(func, deferErrhand)
|
||||
if retval then return retval end
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
return 1
|
||||
end
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user