Skip to content

Kismet Sequence and BehaviorProviderDefinition Basics

CJ Kucera edited this page May 12, 2023 · 14 revisions

Kismet Sequences and BehaviorProviderDefinition (BPD) objects serve some pretty similar purposes. Together, they form the backbone of nearly all dynamic and complex activity in Borderlands. Editing either of them will tend to be a bit more complex than doing other modding type activity, since insead of just changing data values, or lists of data values, you're going to be updating actual logic which the game engine uses to control the game flow. Editing BPDs and Kismets is about as close as you can get in Borderlands 2/TPS modding to doing something like real game code.

Tools

The best tool at the moment for visualizing what both Kismets and BPDs look like is Apocalyptech's BPD/Kismet Grapher (sourcecode at github). In its simplest form, just visit the page, plug in the variable name that you want to investigate, and see what comes up. For browsing through the object data itself, OpenBLCMM's Object Explorer is, of course, the usual first stop. Apocalyptech's FT/BLCMM Explorer Project is pretty useful too, since it provides a simple tree-based view into the data.

Kismet Sequences

Kismet sequences are attached to level definitions themselves, and serve as a backbone for behavior throughout the level as a whole, and will often be involved in mission flow as well. They control things like cutscene playback, elements like the floor masher puzzle in Lair of Infinite Agony, and a variety of other things.

The term "Kismet" won't actually show up much (if at all) when browsing through Borderlands objects - the name comes from the terms that are used inside the Unreal UDK, which Borderlands developers use to create the game in the first place. The Unreal Engine 3 Kismet User Guide is a good read, just so you know the general kinds of things which Kismet Sequences will be used for, and to get a feel for how this all looks to actual developers.

The main Sequence objects which define a whole Kismet Sequence will be found at objects such as Glacial_Dynamic.TheWorld:PersistentLevel.Main_Sequence, which defines the sequences for Windshear Waste. In FT/BLCMM Explorer, the tree starts out looking like this:

Kismet Sequence in FT/BLCMM Explorer

As you can see, there's at least a few subsequences in there as well: ClaptrapIntro, Defend1_LeavingScared, etc. The majority of the objects which you can find underneath the main sequence objects will have some common identifiers in the object name, like SeqAct (Sequence Action), SeqEvent (Sequence Event), and SeqVar (Sequence Variable).

Going into actual Kismet Sequence editing is a topic for another wiki page at a future date, but fortunately editing Kismets isn't too bad so long as you have an idea of the flow of the sequence. The BPD/Kismet Grapher mentioned above is the best resource for that at the moment. Each sequence object inside the sequence (generally SeqAct or SeqEvent) contains an OutputLinks array which defines which sequence objects are called after this one. Sometimes the object in question may choose to do one or the other based on some conditions (or something), but the graphs should hopefully give a pretty good feel for what's going on there. There's also a VariableLinks array to define which variables are being looked at/acted on, and InputLinks and EventLinks arrays which control other aspects of the object.

When graphing a Kismet Sequence through the grapher, you can either start with a specific sequence object (such as Glacial_Dynamic.TheWorld:PersistentLevel.Main_Sequence.ClaptrapIntro.SeqEvent_Console_0), or you can plug in the master sequence object name itself, to get a graph which includes all connected elements. Note that graphing a whole sequence can result in some prodigiously huge graphs, so once you've found what you're looking for, you may want to go back and just graph from the relevant starting point. There will be many unconnected graphs inside the main graph.

BehaviorProviderDefinitions (BPDs)

BPDs, in contrast to Kismet Sequences, are attached to specfic objects within the game, such as containers, enemies, NPCs, gun barrels, projectiles, and are used to define more nebulous behaviors such as your characters' action skills. A BPD Classroom page exists to go into detail on decoding and editing BPDs.

Editing BPDs is more complex than editing Kismet Sequences, because all of the code-like flow happens inside a single object, instead of spread out over dozens (or even hundreds) of separate sequence objects. The data inside a BPD is packed up inside a bunch of different nested arrays, with some fairly nonobvious methods for linking everything together. To make matters worse, there are some elements of BPD objects which are automatically overwritten by the engine, if you try to edit them, so some parts of BPD structures can't even be edited. (Or at least, nobody has figured out a way to prevent the overwriting yet.) The BPD Classroom link does a good job of going through all of those details.

In the end, though, BPD graphs ends up looking a lot like a Kismet Sequence would. The BPD/Kismet Grapher linked above is the best way to get a feel for how a particular BPD is working. The grapher includes a lot more seemingly-cryptic information in each of the nodes, because modders looking to edit BPDs will need to know a lot of internal indexes and the like in order to successfully make edits.

How Kismets and BPDs Talk To Each Other

BPDs have the ability to "call out" to Kismets (and to other BPDs), and Kismet Sequences have the ability to "call out" to BPDs (and to other Kismets). The terminology for this may be different for Borderlands developers working inside the official tools, but in the objects themselves, they're called Events. As you look through objects, you'll see three different kinds of calls out to events: RemoteEvent, CustomEvent, and RemoteCustomEvent.

RemoteCustomEvent objects appear to be the most straightforward, or at least the most obvious in terms of what they do. For instance, a RemoteCustomEvent object might look like this:

=== Behavior_RemoteCustomEvent properties ===
  SequenceProvider=None
  ProviderDefinitionPathName=( 
        PathComponentNames[0]=, 
        PathComponentNames[1]=, 
        PathComponentNames[2]="GD_CaraVan", 
        PathComponentNames[3]="Vehicle", 
        PathComponentNames[4]="Class_CaraVan", 
        PathComponentNames[5]="BehaviorProviderDefinition_0", 
        IsSubobjectMask=16 
    )
  CustomEventName=Go

So in that case, the event being called is the "Go" event described by GD_CaraVan.Vehicle.Class_CaraVan:BehaviorProviderDefinition_0. (So, this is presumably the singal sent to the Caravan in The Dust to start its rounds.)

RemoteEvents and CustomEvents, in contrast, only define an event name, rather than specifying anything specific. In general, it appears that what happens in both cases is that any BPD or Kismet event which matches the event name, and which is loaded, will end up getting triggered. So, in order to know what's actually being called by a RemoteEvent or CustomEvent call, you need to know what event names are actually available, and what objects handle them.

The BPD/Kismet Grapher makes an attempt to do at least a bit of this. It knows what Kismet event names are available on a per-level basis, so when graphing, if you specify a level, the grapher will be able to match up any RemoteEvent or CustomEvent call with Kismet Sequences from that level. In addition, if you started the graph from a BPD object itself, it'll know which event names are available from that BPD, and link those in appropriately.

One place to see this would be graphing GD_Aster_CriticalFailData.IO.CriticalFailJumpingWeapon:BehaviorProviderDefinition_2 while having the level Immortal Woods (Dead_Forest_P) selected. (It will be clearer if you opt to turn off Kismet variables, as well.) You'll end up with one section of the graph which looks like this:

BPD-to-Kismet-to-BPD Graph

The Behavior_RemoteEvent_5 behavior in the top-left is calling the event name RE_CF_StartSpinOne. Because Immortal Woods was selected as the level, the grapher knows that that event name exists inside the Critical_Fail kismet sequence, and it reports on the kismet name. The intermediate steps we can just gloss over, but in the bottom right hand corner, the Kismet Sequence itself calls out to the event name CE_CF_GunToss. Because we started out graphing the BPD, the grapher knows that that event name is in the BPD itself, so the execution flow hops back into the BPD.

If the grapher does not know where the event lives, it'll report as such, which you can also see in that graph. The grapher doesn't know what provides the CE_CF_UnHide2ndWeapon event (though it's probably another BPD which is loaded in the area, since it is pretty sure it knows what all the Kismet event names are, in the level). As of August 20, 2018, at least, the grapher does not have a list of BPD-based events which might be loaded in a particular level, so in this case there's no other information to go on.

Difference Between RemoteEvent and CustomEvent

It's not immediately obvious just from looking at the objects what the difference is between CustomEvent calls and RemoteEvent calls, since they both just seem to specify an event name. One user answer at the unrealengine.com forums does explain what the difference probably is, though it's using UE4 developer terminology (Borderlands 2/TPS is UE3) which doesn't really apply to the objects that we can see as modders, but it's potentially informative anyway:

Custom Events are basically functions, so on yourself you can fire a Custom Event
just like you call any other function. We are currently working on an improvement
that will let you call Custom Events on other Blueprints as well (this is currently
disallowed). As you say Remote Event is sort of special in that it finds an event
by name, and will search all other levels.

So it sounds like RemoteEvent calls might be able to affect changes in other levels, once they're loaded in? Perhaps?

In the end, it's probably not especially important for modders, really, but it's interesting at the very least.

Clone this wiki locally