-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Kismet Sequence and BehaviorProviderDefinition Basics
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
- Kismet Sequences
- BehaviorProviderDefinitions (BPDs)
- How Kismets and BPDs Talk To Each Other
- Difference Between RemoteEvent and CustomEvent
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 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:
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.
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.
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.)
RemoteEvent
s and CustomEvent
s, 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:
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.
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.