Early bios / startup hook | custom bios
OldStarchy opened this issue ยท 6 comments
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 theload
function.
How the feature/change should work
There are two feasible options that I can think of right now;
- Much like the way the shell checks for
startup
orstartup.lua
, the computer could check for a custombios.lua
and load that instead of the built-inbios.lua
- The same thing as option 1. but put the check as the first thing in the built-in
bios.lua
(before it loads theexpect
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
.
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.
@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.
... 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?
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.
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
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.