I have nothing visually interesting to show this weekend, so here is a picture of me debug-logging a virtual sound channel module that I’ve been working on.
Work Since Last Devlog
- Fixed the viewport rendering issues related to wraparound map rendering that I’m aware of.
- Scrolling is now per-layer, per-viewport. A scene with three visible layers and two viewports would have six sets of scrolling parameters, on top of positional info for the viewport itself. Each viewport can have totally different scrolling rules on a per-layer basis, and also different tilesets (though I need to do more work to allow tilesets with different dimensions and stuff like that.)
- Eliminated global variable declarations (that is, variables appearing directly in Lua’s ‘_G’ table) from the engine core. I wouldn’t expect projects running on top of the engine to be so strict, but I’m happy I finally did something about all of the ones in the engine.
- Added the ability to draw sprites as parts of widgets. I did most of the work for this earlier (splitting sprite state from actors), but forgot to come back to the widgetDefs to add in sprite drawing.
- Changed the logger so that it targets two files suffixed with “.a” and “.b”, overwriting one, and then the other, after passing an arbitrary file size limit. This will prevent a messed-up game from filling the end user’s hard drive with log files. I also added a pre-init message buffer, which catches messages that were emitted before the logger was fully set up (i.e. the LÖVE Identity hasn’t been set, so we don’t yet know where to save logs), printing them in bulk at the end of init().
- Started work on a config file system, using a simple Windows INI-style format. With Hibernator, it would just read / write entries in a specific sequence, and the file wasn’t really human-readable. (Well, you could read the values, but the keys were absent from the file.) For future projects, I’d like something more robust.
- Use functions to register config files, groups in those files, and items in those groups, with some info on how each item should be validated before it gets passed to whatever part of the engine is requesting the info. With all the data plugged in, it’s capable of constructing a default config file from scratch with no input from the rest of the engine.
- File reading: Read a file line by line, and look for either group declarations (single words enclosed in square brackets) or key = value pairs. My Lua pattern search skills are pretty weak, and I struggled to come up with a string search filter that would parse each line.
- Parsing: Another function takes the table output from above, and checks every [group] and key=value line to confirm that they exist in the model, and that they adhere to the limits set for each item (can or can’t be a string/number/bool, min/max/step for numbers, optional whitelist for strings). Strings are automatically converted to booleans or numbers if Lua is able to interpret them as such.
- File saving: the module iterates through the config model’s groups and items alphabetically and writes them out. In-model descriptions are included as comments.
- Now I’m just missing the final piece of the puzzle, where engine modules query the config system for data.
- I tested out some ideas on a separate, fresh LÖVE project codebase while out of town this week. They need to be integrated into the main engine:
- Log write limiter: if the logger outputs more than a certain number of bytes within a certain timeframe, logging to disk is shut off for the session. I’m thinking that 1MB within 30 minutes is an acceptable threshold — that’s a lot of error messages. The intent is to prevent a bugged game from saturating the end user’s disk access bandwidth. For real debugging scenarios, the limit can be disabled, or terminal output can be redirected to a file.
- Back up config files and save files before overwriting them: When saving these files, a backup of the existing file is written with a .bak extension first. I couldn’t find a file rename command in love.filesystem, so the backup is generated by reading the whole file in memory and then writing it back out, which does not preserve the old file’s timestamp.
- Audio module work: I now have a basic virtual channel system which matches requests to play a sound with arrays of cloned sound sources. It’s lacking a lot of features right now, but it seems to work as expected under testing, and it’s a step up from what was in Hibernator (which was: just make one source for every sound, and play only one instance of a sound at a time.) One thing I didn’t understand earlier is that clones of static sources are much, much lighter on memory and disk usage than making new sources of the same sound over and over.
Oof. The config source file is already the single biggest in the codebase. It can probably be whittled down, but I need to make sure it behaves exactly as expected.
I also did some work on gamepad integration with config files, but have nothing really to show for it right now. Interpreting all numbers as Lua number types means I’ll have to use ‘one’, ‘two’, three’, … instead of the ‘1’, ‘2’, ‘3’, … LÖVE KeyConstants.
Plans For Next Post
- I’m too wiped out to properly fill this out tonight, but I need to integrate the things I made in the test project into the main codebase, sooner rather than later.