Open jahodfra opened 6 years ago
It could be implemented like a plugin system. The plugins would look like usual .lua
scripts with system events access (clipboard, history changes...)
You can assign these scripts in the config
, maybe just a list with plugins to load and also, you can define a pixel icon in the script to show it on the main toolbar...
How would custom editors have their own graphic resources (sprites, etc) if the only memory they had access to was all from the currently loaded user cartridge?
I wonder if you could overload the bankswitching system for this...
Added a few external tools to the wiki https://github.com/nesbox/TIC-80/wiki/tools
Don't know atm, we'll invent something :)
Maybe TIC-80 needs a notion of RAM as in "memory for data of running program"? So far there is none and TIC-80 "magicly" uses host RAM (allowing funny things like retro games having gigs of data on heap). Conveniently there is ~12k of unmapped address space at the end of RAM layout right now 🤔
So custom editors could store their sprites in current sprites location and have user edited data in that RAM area. Custom editors will need to implement their rendering tho.
Maybe TIC-80 needs a notion of RAM as in "memory for data of running program"? So
It already has 96kb of RAM. But variables inside the language runtime and such things aren't the problem here... it's the RAM that's the problem - the fact that the game being edited has sprites AND the editor likely ALSO has sprites. so now spr(12)
becomes ambiguous.
Is it sprite 12 of the editor or sprite 12 of the user program being edited?
Custom editors will need to implement their rendering tho.
Well it'd be very nice if that could be avoided... Optimally you'd want to be able to use the full existing API for drawing or else editors instantly become crippled.
Just adding another 8 banks and saying banks 0-7 are user cartridge and banks 8-15 are editor could work, but I'm not sure how annoying (or not) that would be in practice to have to switch banks constantly.
It already has 96kb of RAM
Erm, no. It has 96kb of address space, ~84kb of which is memory mapped for audio\video\input "hardware". There is no region in that adress space that holds program code, it's variables, callstack, data, etc - it's all in (unbounded) memory of interpreter outside of TIC-80 "hardware".
My point is that in real hardware you will have RAM/ROM with program data mapped somewhere to adress space, so you can store however much sprites (while it fits the memory) you want and copy that data to video memory before you can draw it.
So in case of current TIC-80 implementation it would be something like holding sprites of editor and user-edited sprites somewhere in memory of interpreter and copying it back and forth between interpreter memory and SPRITES in RAM (btw, why isn't it in VRAM?). I.e. during SCR, SPRITES contain sprites of editor and you draw editor interface without drawing area of user edited sprites, then during OVR you copy user-edited sprites to SPRITES region, draw them and restore editor sprites back. This way spr
stays unambiguous. Or, alternatively, bank switching like you proposed - instead of copying sprites back-forth you just switch banks of SPRITES memory.
Erm, no. It has 96kb of address space,
We're arguing over semantics. I understand there is the "fantasy device" RAM and then there is the JS/Lua/etc runtime memory. I understand the "code" can't be found in the RAM of the fantasy device at any address. Many parts of the cartridge "ROM" are indeed loaded into fixed addresses though, just not the code.
My point is that in real hardware you will have RAM/ROM with program data mapped somewhere to adress space, so you can store however much sprites (while it fits the memory) you want and copy that data to video memory before you can draw it.
I understand this. Worth noting: You can still persist sprites anywhere in RAM and then copy them in and out of the SPRITES/TILES area as needed... or even render directly them from other areas (with custom functions). You can also treat the "code" as program data with via arrays or some type of encoding (that then feed RAM - there is at least 12kb entirely unused), etc... or use extra music/sfx area for additional tiles, etc... you sort of mention this with the idea of copying large segments of RAM in and out of the scripting runtime on the fly.
something like holding sprites of editor and user-edited sprites somewhere in memory of interpreter and copying it back and forth between interpreter memory ... Or, alternatively, bank switching like you proposed
As far as I can see you really need new "hardware" support to allow either. At this point I'm thinking perhaps a separate bit somewhere you flip to address "editor" 96kb RAM vs "cartridge" RAM/ROM. (it's worth noting that addressing cartridge RAM/ROM outside of what is persistent to the cartridge makes little sense). Expanding the address space to allow both the editor RAM and cartridge "ROM" to exist in "memory" simultaneously might also be an idea... though I feel like that pollutes the device concept somewhat - so it seems easier to believe this might be done internally but exposed to the user via banking.
and SPRITES in RAM (btw, why isn't it in VRAM?).
I think this is just how things were originally setup and if you tried to enlarge VRAM now VRAM also has a bunch of other random things in it (input state, etc), etc. Really you could argue perhaps FONT
should also be in VRAM. But I don't see these things changing since it would break compatibility with like everything.
I.e. during SCR, SPRITES contain sprites of editor and you draw editor interface without drawing area of user edited sprites, then during OVR you copy user-edited sprites to SPRITES region, draw them and restore editor sprites back. This way spr stays unambiguous.
I don't think it's "ambiguous" if it allowed banked access... as long as it's well defined and documented it's not ambiguous. We already have BLIT Segment after-all.
Pixel Vision 8 allows custom tool development. So it would be good to learn from that.
As of now, in TIC80 (and Pico8) if you edit a sprite and then hop over to the map editor without saving, the sprite retains your edits. At least when I tried PV8 a little while ago, if you use one tool and then exit it to load another tool without saving, your work is lost. There are probably good technical reasons for this, allowing tools to be completely decoupled from one another or something, but as a user experience, it's definitely an unpleasant surprise.
If people want to support custom tools, my hope would be that they would be consistent with the user expectations set by the existing TIC80 tools, where it is not necessary to save your cart before switching to another tool.
Generally I think the TIC needs to: Capture special characters and upon pressing e.g. F4 load editor cartridge. For the sprite editor it needs to load sprites and tiles into the editor cartridge. As there is limited space the editor: a) wouldn't be able to use it's own sprites (this is quite serious limitation) b) it would have to store it's own sprites outside (e.g. in code or sound data) and replace it with the user sprites each frame. c) it can store tileset in a own bank. But that needs possibility to change a bank at least 2 per frame or it would produce blinking. d) As extra e.g. 9th bank e) Instead of the existing bank e.g 8th f) The user can specify edited bank in overlay UI specified by TIC-80 engine. So only one bank would be put inside the editor.
After finishing of the editor the TIC-80 needs to unload editor cartridge parts - e.g. code.
I think there is no sense of having code editor - as the TIC doesn't pass keyboard events to cartridge. I see space for music, sound, custom graphic editors. (e.g. editor for trees, 3d images, animations etc..).
as the TIC doesn't pass keyboard events to cartridge.
Sure it does. key
and keyp
. Funny I'm more interested in a code editor than the others.
I've been trying to think about how to even start/approach this (forgetting the more mundane concerns like data access)... currently the idea is we have a single currentVM
... a single cart
... I feel like if people write editors they should be real cartridges (or that should be a possibility)...
So if I'm editing my Lua game using my Lua editor cartridge... every time I switch does the Lua env get destroyed and a new one created? What about the cartridge
? We literally can't do that because we might have unsaved data... so it seems we'd need the ability for TIC-80 to now juggle multiple cartridges... so at a minimum we now have two carts in ram... the user cartridge and the 'editor' cartridge. We actually probably need two full VMs too - unless we want to force it on the user to store state in PMEM or something... Switching between the editor -> game -> editor should not lose your cursor position - which is likely stored in the Lua VM as just a normal variable...
So right away that's a pretty large change... making TIC-80 more of an "OS" that runs multiple cartridge "programs" all at a single time... :-) Sounds cool though.
We actually probably need two full VMs too
Actually this is a given/requirement (unless we plan to reinit the VM every time we context switch) I think... you shouldn't have the SAME exact runtime servicing game code and "OS" level code... that's a security nightmare. IE, we have to keep track of which runtime is allowed to call api_save_to_disk
and which isn't... and that shouldn't be buried inside Lua - where perhaps a malicious game could break out of it - it should be at our C level.
IE, perhaps there is a privileged Lua VM and an unprivileged one or privileged and unprivileged cartridges... perhaps you "gain" privileges by being installed/configured inside someone's TIC_80 config file... so cartridges spawned from config (as editors) have increased API access levels. I still think file system access should be very restricted - ie opening a cartridge is probably still an "OS"/console only function... but once is was open a user editor could request that it be saved (but not renamed, etc).
Related: #1749
I don't think the path forward here is easy (I think it'll require a bit of effort and willpower). But I think I'm starting to imagine how the entire architecture would fit together after a deep dive into the Studio code. One problem is studio is trying to do way too many things... it's acting as shell, task switcher, I/O handler... there isn't really even a deep concept of whether TIC-80 is running your game or the studio... it's always the studio and your studio just runs your game "inside itself". In fact the studio is even processing shell arguments like --vsync
...
So right now our "process" hierarchy is really 3 layers:
So:
kernel
is the device specific layer, SDL, Sokol, retroarch, N3DS etc...game
is your Lua, Wren, etc code and it's tick
wrapper...studio
kind of does EVERYTHING else, serving not only as app but really OS alsoI think another layers needs to be added so that that it looks like this:
So:
kernel
is the device specific layer, SDL, Sokol, retroarch, N3DS etc...studio
is the studio app... with the various editors you know and love. gamemenu
would be a simple UI layer we provide for small devices or when BUILD_EDITORS is false.game
would be whatever user game cartridge is currently loadedcustom editor
would be a custom editor, just a tic
or project file with extended API accessAnd OS is the big change here... a layer to hold the pieces that are part of TIC-80 but exist outside of any app. For example you could record a video of the studio, or your game, or your custom editor... so that's not part of studio
, it's part of the OS. Same for taking a screenshot, etc. Switching between apps is an OS concern.
There is no reason you couldn't switch out of your game, edit some sprites, and switch right back into the game - all without restarting the game. Restarts would only be necessary for code edits. The studio wouldn't orchestrate switching from studio to game and back, the OS would. So the studio then only need concern itself with it's own RAM. (not making copies, etc)
I think this would simplify a lot of things... many of the current responsibilities of studio.c would move into other files. A lot of the conditional compilation defines could be simplified/removed since we'd separate the idea of "gamemenu" and "studio".
Of course this isn't an all or nothing proposal or anything that would have to be implemented all at once... you could start modestly with:
IE, start with one hard-wired task, the studio... start moving some fo the simpler functionality (video, screen shots, etc) up a layer to the OS... then once you have some basic keyboard stuff working at that level you could add a second hard-wired task, the game
... so that instead of studio running it - it's not managed by the OS. And that would be a beginning.
Thoughts?
Thoughts?
Everything you say sounds reasonable, but what the TIC80 architecture looks like now is the result of the evolution of the project, of course, if I knew right away where we would end up, I designed many things differently. Well, let's move forward with baby steps to your ideal architecture :) Not sure about the current version, maybe in the next...
but what the TIC80 architecture looks like now is the result of the evolution of the project
Sure, don't take any of this as a critique of your amazing progress so far. :-) It was really just more of a before/after not a "before sucks" or anything like that.
Can you help me out with understanding what is happening here:
and here:
Why are they only "restored" in modes other than RUN?
The same problem we fixed earlier with the keyboard registers, the user can break the system mapping from the game, perhaps we could fix it the same way as we did with the keyboard/gamepad registers.
Ah, this is re/setting which types of input are accepted for which modes, yes?
yes, tic->input.data = -1;
means enable all the inputs.
The same problem we fixed earlier with the keyboard registers, the user can break the system mapping from the game, perhaps we could fix it the same way as we did with the keyboard/gamepad registers.
What is someone mapping exactly? Does it not matter during gameplay if they break it - or is that a feature?
Mockup just for fun.
How one would task switch is an open question though. I presume some might want to ADD editors, not just replace the existing ones, so you'd have a world where you might be running 1 or 2 custom editors, your game, AND the studio...
@nesbox Out of curiosity is there a reason you've never explored using Lua for the built-in editors? It would make them a lot more accessible (for contributors)... We already use Lua for the config file... or are you just super comfortable with C yourself so it's not worth the bother? :-)
I had such thoughts and it can be done if we extend API for editors (file IO and etc)
I don't think the editors need any file IO to work... they only need the ability to read/write data from/to the users game cartridge... saving and loading would still be handled by privileged studio code.
What about an "is_editor" boolean somewhere and based on that I'd simply extend the sync
API for studio code:
So a sprite editor would need to:
The trick (without first completing this task) would be how do you develop that cartridge in "unprivileged" mode... though I don't think it would be terrible if you could only edit your own cartridge while developing the editor TIC itself. Once we had such an editor I imagine we'd keep a project file of it and then build it into the binary the same way we currently do the demo carts...
I know there are mixed feelings about file I/O, but a neat "editor" approach for PICO-8 is described in a Lazy Devs video. He wanted a way to edit a big table of enemy positions/types/etc for his game.
His solution was to put his editor in a separate cart, but have both carts load the same data using #include
.
Then, the editor cart registers a menu-item "EXPORT" which calls printh(...)
to overwrite the #included
file. That's a full editing workflow. Moreover, the editor loads sprite data with the reload
function (just reading the sprite section of the game cart's ROM).
It'd be sick if something like that would work in TIC-80, but I understand there are security concerns with I/O.
EDIT: and something like printh
could be made safe with a confirmation dialogue. E.g. "the cart is trying to overwrite BLAH.DAT with 198 bytes. [allow] [deny]"
Extending editors requires knowledge of C. It is much more error prone to write in C then in Lua (due to the necessity to manage memory).
Users cannot use their own editor without recompiling TIC. I think it is possible to have editors implemented as specific cartridges. Every time an editor would be triggered the part of tic memory would be copied to the editor. The part of memory would be copied back upon exit from the editor.
Editor cartridges could be referenced in settings so the users would get seamless switching between editors as in TIC.
E.g. for Map editor the sprite backrounds and maps would be copied into an editor cartridge and upon the exit the maps would be copied back.
I see only problem with specific functionality bound to C libraries - e.g. ability to copy / paste from clipboard or recording music. This part would need an interface in TIC.
This is just suggestion for implementation and should be break down into smaller issues before implementation.