February 2, 2025

a detour into file handling

With texture acquisition maybe kind of solved, the next hurdle comes from file handling. In my early experiments, I couldn’t figure out a way to get my module in Rack to load new patches without crashing Rack itself. I eventually gave up, and awkwardly handled loading by signaling to Rack to shut down, waiting, and opening it back up with the patch path as an argument. Besides being awkward, loading patches this way is problematic for two reasons. One, it ties Unreal and Rack too closely together, risking violating the Unreal EULA clause about open source licenses. Two, it means Rack and Unreal need to be running on the same machine.

I decided to take another look. I’ve gotten a little better at using debugging tools in a compiled code context, but I still could not figure out why it was crashing or how to get around it. Stack traces were mysterious or somehow nonexistent. On top of that, behavior was inconsistent. Maybe once every 20 tries, it would actually work, but with no indication as to why that I could determine.

The reason I was getting hard to debug crashes seemed obvious: the UI in Rack is mostly just nested subclasses of rack::widget::Widget all the way down. I’m running my logic in a ModuleWidget, and all the ModuleWidgets live inside a RackWidget. Loading a patch clears the RackWidget of all ModuleWidgets, so my module is effectively deleting itself. It’s only an intuition, but I imagine all sorts of things can go sideways when that happens.

What I needed was a way to run some arbitrary code at a higher level than the RackWidget, so that clearing out its children doesn’t destroy the requester. Pondering this as I went out to do some grocery shopping, inspiration struck: I’d just use another widget.

There’s one more level of widget above the RackWidget, and that’s the SceneWidget. What I can do is add a child widget to the SceneWidget, like a widgety little trojan horse. What I eventually come up with looks something like this:

https://gist.github.com/gotno/35dcbd38fb338b48d587e989dedc65a5

My SceneAction widget gets created and added as a child of the SceneWidget (APP->scene). On the next frame, its step method is called, running some arbitrary action and immediately requesting to be deleted. The frame after that, it’ll be deleted before step is called again.

And it works flawlessly. Easy.