Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Would adding dummy functions be worth it? #111

Open
Ferk opened this issue Mar 12, 2017 · 4 comments
Open

Would adding dummy functions be worth it? #111

Ferk opened this issue Mar 12, 2017 · 4 comments

Comments

@Ferk
Copy link

Ferk commented Mar 12, 2017

I was trying to make several Löve games work in Lutro but I always stumble with problems.

I was thinking that maybe for Löve compatibility the missing functions could be filled with dummies that just reported the function as not supported but that would not cause an instant crash.

Something like the equivalent to this:

lutro.mouse.isVisible = function()
    print("WARNING: unsupported function 'lutro.mouse.isVisible'")
    return false
end

Maybe the games won't really work 100% as intended when doing this, but perhaps more games would at least be playable.

It'll also make it easier to see what functions need to be implemented/replaced for the game to run. Bonus points if the warning message could also show the file and line number of the call, or something like that.

What do you think? is it worth it?

@kivutar
Copy link
Member

kivutar commented Mar 12, 2017

We've been doing this for a few functions if I remember well.

@Ferk
Copy link
Author

Ferk commented Mar 12, 2017

I've made this snippet that can be used in the header of the main.lua for Löve games to try and use lutro for available functions, or otherwise display a message & stacktrace without crashing.

if not love then
	love = {}
	love_compat = {
		__call = function(self)
			print("WARNING: unsupported method: " .. love_compat[self])
			print(debug.traceback())
		end,
		__index = function(self, key)
			local key_stack = love_compat[self] .. "." .. key
			local success, lutro_value = pcall(loadstring("return " .. key_stack))
			if success and lutro_value ~= nil and type(lutro_value) ~= "table" then
				print("love_compat: Using " .. key_stack)
				return lutro_value
			else
				local new = {}
				setmetatable(new, love_compat)
				love_compat[new] = key_stack
				self[key] = new
				print("love_compat: indexed " .. key_stack)
				return new
			end
	    end
	}
	love_compat[love] = "lutro"
	setmetatable(love, love_compat)
end

So far I haven't been successful running the games, but at least it helps seeing the functions that are missing for the game to run.

I forced lutro-roguelike to go through this compatibility layer and it worked. So that means that this should work as long as the game uses compatible functions.
It was spewing a lot of "love_compat: Using lutro.graphics.draw" which is something I did not see in the Löve games I tested it with, though.
They were simply showing a black screen and then the log was totally silent, with no attempt to draw, so something else must be missing.. hmm..

I tried it with your love-vespa and it almost works. It showcases what I meant, the game runs while spewing errors wherever incompatibilities arise, without completely crashing.

@RobLoach
Copy link
Member

RobLoach commented Mar 12, 2017

Made a few stub functions for common things, but there could be more. Which functions do you run into often?

Some functions would work as warnings. Others, not so much.... window.setFullscreen could be ignored, while lutro.joystick.getJoysticks couldn't be.

@Ferk
Copy link
Author

Ferk commented Mar 12, 2017

Well, I was thinking just making it generalized, instead of going one by one, any index accessed that is not known would display an error or warning in the terminal (even if you do lutro.asdasdf, it would just return a function that gives nil when executed and shows the warning). I sort of did it already in Lua with my wrapper, though it ended up being more complex than I expected.

if not love then
    love = {}
    love_compat = {
        __call = function(self)
            print("WARNING: Unsupported method: " .. love_compat[self])
            print(debug.traceback())
        end,
        __index = function(self, key)
            local key_stack = love_compat[self] .. "." .. key
            if love_compat[key_stack] then
                return love_compat[key_stack]
            end
            
            local success, lutro_value = pcall(loadstring("return " .. key_stack))
            if success and lutro_value ~= nil and type(lutro_value) ~= "table" then
                print("love_compat: Using " .. key_stack)
                love_compat[key_stack] = lutro_value
                return lutro_value
            else
                local new = {}
                setmetatable(new, love_compat)
                print("love_compat: Indexed " .. key_stack)
                love_compat[new] = key_stack
                love_compat[key_stack] = new
                return new
            end
        end,
        __newindex = function(self, key, value)
            local selfkey = love_compat[self]
            print("love_compat: Assigning " .. selfkey .. "." .. key)

            local success, lutro_self = pcall(loadstring("return " .. selfkey))
            if success and lutro_self ~= nil then
                lutro_self[key] = value
            end
        end
    }
    love_compat[love] = "lutro"
    love_compat["lutro"] = lutro
    setmetatable(love, love_compat)

    
    -- Compatibility 
    local DimensionX = 640
    local DimensionY = 480
    getTitle = function() return "TITLE" end
    getVersion = function() return 0, 0, 0, 0 end
    lutro.graphics.getDimensions = function() return DimensionX, DimensionY end

    lutro.graphics.newShader = function() return love.graphics.ShaderObject end
        
    -- newCanvas should support no arguments (default to screen dimensions)
    lutro.graphics.newCanvas_old = lutro.graphics.newCanvas
    lutro.graphics.newCanvas = function(a,b)
        return lutro.graphics.newCanvas_old(a or DimensionX, b or DimensionY)
    end

    -- filesystem.load should return nil on wrong/missing path
    lutro.filesystem.load_old = lutro.filesystem.load
    lutro.filesystem.load = function(path)
        if lutro.filesystem.exists(path) then
            return lutro.filesystem.load_old(path)
        end
    end
end

Wrapping in Lua cannot really cover unimplemented methods in userdata objects, though (e.g. the ones returned by lutro.audio.newSource or lutro.graphics.newCanvas) as it'll fail when given as parameter to C functions that expect the userdata objects.

But after writing this and seeing the games running with all this boilerplate I'm realizing that it's not worth it, while it runs and can be helpful as base for modifying the Löve code and porting the game, in Lutro current state this is not really gonna be able to make most Löve games playable without additional work that would have to be put on each individual game.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants