CC: Tweaked

CC: Tweaked

42M Downloads

Early bios / startup hook | custom bios

OldStarchy opened this issue ยท 6 comments

commented

From what I've read, even with resource packs, changing the bios.lua is only possible by modifying the mod .jar file.

I'd really like to roll my own bios / os, and in the original CC I was "kinda" able to do so by overwriting the os.shutdown function that gets run at the end of bios.lua however its kinda hacky and it annoyed me a little bit knowing that bios.lua:883 would always be the last stack frame in my stack traces. So much so that I checked for and hid that frame from my stack trace function.

There's also the issue of bios.lua irreversibly hiding some native functions.

And as a side note, I noticed that neither the original nor the tweaked versions of CC make us of the 'mode' parameter in the load function.

How the feature/change should work

There are two feasible options that I can think of right now;

  1. Much like the way the shell checks for startup or startup.lua, the computer could check for a custom bios.lua and load that instead of the built-in bios.lua
  2. The same thing as option 1. but put the check as the first thing in the built-in bios.lua (before it loads the expect module).

The second option would end up similar to my hack of overwriting os.shutdown but it wouldn't overwrite the built-in types like load and its variants.

Rationale

I'd like to implement my own top-level coroutine handler and operating system. Admittedly, much of what I'd like to do is already possible, however, something like this would make it a bit nicer and easier, as my previous implementation requires that you don't touch the normal "startup" file and instead use a mystartup.lua.

commented

I implemented this before back in CCTweaks due to popular demand, and pretty quickly found that while people wanted custom bioses, absolutely nobody wanted to put in the effort of writing their own.

My stance here is that if someone can write a bios.lua override via a resource pack which does something which can't already be done with existing hooks, then it might be worth adding to CC. But until then, it's just not worth it.

There's also the issue of bios.lua irreversibly hiding some native functions

I guess we could probably get rid of load now TBH. The compatibility code has been moved into our Lua runtime, so I don't think this does anything different.

commented

@Wojbie I am aware of that and I did think about mentioning it in my post, however doing so doesn't get around my primary problem of it being quite hacky. as the lua docs say

Unlike the other libraries, you should use the debug library with parsimony. First, some of its functionality is not exactly famous for performance. Second, it breaks some sacred truths of the language, such as that you cannot access a local variable from outside the function that created it.

If having bios.lua:883 hidden in my stack trace bothers me you can be sure using the debug library to pull apart the runtime will too. Though I am aware that it's very much a me problem, so I don't blame you for not considering it as a valid argument.

@SquidDev

... nobody wanted to put in the effort of writing their own.

that's up to them. I've already got most of mine written and would like it to sit a more neatly on an official api rather than using undocumented hacks that could (and did) break between versions.

Regarding your comment about the resource packs, sorry I don't quite understand what you mean. I'm not keen on writing any custom resource packs, if I was going to go down that path I may as well just edit the jar file and modify the builtin bios.lua directly. That has obvious portability issues as I can't expect every server to run my special copy of CC or install my resource pack just so I can run my lua code.

I am more than happy to submit a pull request, as I know you have other things to do than cater to everyone who raises a GitHub issue. Is there a scenario in which you'd be willing to accept one?

commented

Regarding your comment about the resource packs, sorry I don't quite understand what you mean.

Basically I'm looking for a good proof-of-concept overwrite of bios.lua (which can be done using resource packs, or modifying the base jar file) which does something (hopefully something useful) which can't be achieved with the pre-existing hooks. It's not meant to be practical, but at least demonstrate that a) this feature would be used and b) highlight the deficiencies in the current system.

commented

There's also the issue of bios.lua irreversibly hiding some native functions.

As a note i would like to point out that it is not irreversible as you have access to debug library in CC:T and using that allows you to get up values and recover original functions.

Here is example of code that does it https://gist.github.com/MCJack123/42bc69d3757226c966da752df80437dc

commented

If you mean to say "What would a custom bios do that the current one can't?", my answer would have to be "Allow me to write my own bios (without hacks aka overwriting the os.shutdown and restoring loadstring (etc.) by pulling upvalues)".

I'd like to write my own OS; right now the best I can do is by starting with a bunch of hacks that rely on the undocumented (aka. subject to change) structure of the existing bios, startup, and shell.

startup.lua
local osrun = os.run
local osshutdown = os.shutdown

os.run = function()
end
os.shutdown = function()
    os.run = osrun
    os.shutdown = osshutdown
    local ups = {}

    function ripUpvalues(func)
        local index = 1
        repeat
            local name, value = debug.getupvalue(func, index)
            index = index + 1

            if (name ~= nil) then
                ups[name] = value
            end
        until (name == nil)
    end

    ripUpvalues(load)
    ripUpvalues(loadfile)
    -- ripUpvalues(os.sleep)
    -- ripUpvalues(os.shutdown)
    -- ripUpvalues(os.reboot)

    -- for i, v in pairs(ups) do
    --     print(i)
    -- end

    load = ups.nativeload
    loadstring = ups.nativeloadstring
    -- setfenv = ups.nativesetfenv
    -- os.shutdown = ups.nativeShutdown
    -- os.reboot = ups.nativeReboot

    term = term.native()
    term.clear()

    if (fs.exists('os/_main.lua')) then
        local osf = fs.open('os/_main.lua', 'r')
        local os, err = loadstring(osf.readAll(), 'bt')
        osf.close()

        if (os == nil) then
            term.setCursorPos(1, 2)
            term.write('Failed to load os: ' .. err)
        else
            os()
        end
    end

    coroutine.yield('key')

    os.shutdown()
end

shell.exit()

Not to mention all the other libraries that I'd want to unload and restore the "native" API for (eg. turtle). If I could get a custom bios I wouldn't need nearly any of the above code and I could just get on with writing the new bios.

term.setCursorPos(1, 1)
term.write("Starting Custom OS...")

...

os.shutdown()
while (true) do coroutine.yield() end

The point is I'd like a clean slate, which I can't do unless I can get my code running first on boot.

commented

What about making the bios kinda like a startup file. So on startup, a computer will look for bios.lua in its root drive and then will fall back on the one in the ROM?

Edit; I should have reread the OP earlier.