What are some ways to implement scripted events without using the level blueprint?

I want to reduce my usage of the level blueprint as much as possible since my project is getting bigger and bigger. I’m currently mostly using it for all kinds of trigger events, e.g. triggering a dialogue, starting a quest, starting a level sequence,… All things specific to that level and often referencing other actors (such as a level sequence actor). What are some ways to keep that logic out of the level blueprint?

My current idea is to create a UObject class “GameplayAction” with lots of subclasses like “GameplayAction_StartQuest”, “GameplayAction_PlaySequence”,… and then just have an array in my trigger class going through that list sequentially. To make it easily manageable in the editor, I created a struct with the action subclass and basic variables (Actor, Object, String, float) that the different subclasses can use. That’s just so I can create those actions directly in the Actions array dropdown of the trigger in the editor. But before I fully implement that system, which probably comes with its own problems, I wanted to ask what some other best practices for this might be.

There’s plugins like FlowGraph as well that solve this issue, but before I make my whole project dependent on a 3rd party plugin, I wanted to try if I can implement something simple myself.

The main reason for me to do this is because I’m using world partition and don’t want to have hundreds of triggers not spatially loaded with hard references in the level bp. My first approach was using level instances for everything around a specific trigger, but that results in errors in packaging. Looks like logic in level blueprints isn’t really that reliable yet.