Borderlands: Music and Level Streaming - Part 3

The Music of Level Streaming


This tutorial assumes a minor-moderate functional use of the editor and tools and does not cover tasks not specifically related to the subject.


What is level streaming and why should I care?
Level streaming is a feature in Unreal Engine 3 that dynamically loads and/or unloads content to increase performance that would otherwise be lowered if said content was always static. Many of the maps in Borderlands are quite large and without level streaming the overall performance would suffer. The process involves one or many different maps being streamed into and/or out of a single persistent map as needed when the player travels across it. Setting up level streaming is not magic. You can't append Audio, Light, or Env to a filename and expect the wizards to make it work. Contrary, you could call it Fartbutt or EnGORGE as the filename is arbitrary but level streaming is a deliberate act that needs to be performed in the editor.

We're going to be using level streaming for music in this example though you may find it useful for other tasks as well. Though it hasn't been tested, it may be possible to setup music in custom maps without using level streaming but this is the way Gearbox has been doing it which seems like a valid enough reason to keep it that way.

I Still Don't Get It

First off we need a persistent level. This is your regular map which needs to be done or at least developed to some degree to be useful. The map or maps you'll be streaming into this one should also be done or at least useful in the same respect. Start off by opening your persistent map. In the Generic Browser click on the Level tab and you should see one group with one map in it (you may have to double-click it first). From the file menu click Level, then Import. You'll be given an Open File prompt, let's navigate to and select the AudioMap that was created in the previous tutorial . Next you'll be given a prompt asking how this map is going to be streamed. Make sure Kismet is selected and click OK. The Level Group should now show two maps, the persistent and the audio. Since the AudioMap contains only audio data and nothing the player needs to see we can uncheck "Visible?".


Now we need to create the Kismet responsible for streaming these maps. Open the Kismet browser for your persistent map, we're going to be pasting in two functions (ctrl+C the text and ctrl+P into Kismet).

Begin Object Class=SequenceFrame Name=SequenceFrame_0
   SizeX=382
   SizeY=246
   bDrawBox=True
   FillColor=(B=0,G=0,R=255,A=20)
   ObjInstanceVersion=1
   ParentSequence=Sequence'Main_Sequence'
   ObjPosX=825
   ObjPosY=178
   ObjComment="Detect Play in Editor"
   DrawWidth=382
   DrawHeight=246
   Name="SequenceFrame_0"
   ObjectArchetype=SequenceFrame'Engine.Default__SequenceFrame'
End Object
Begin Object Class=SeqVar_Named Name=SeqVar_Named_0
   ExpectedType=Class'Engine.SeqVar_Bool'
   FindVarName="PIE"
   ObjInstanceVersion=1
   ParentSequence=Sequence'Main_Sequence'
   ObjPosX=1017
   ObjPosY=346
   ObjColor=(B=0,G=0,R=255,A=255)
   DrawWidth=32
   DrawHeight=32
   Name="SeqVar_Named_0"
   ObjectArchetype=SeqVar_Named'Engine.Default__SeqVar_Named'
End Object
Begin Object Class=SeqVar_Bool Name=SeqVar_Bool_1
   ObjInstanceVersion=1
   ParentSequence=Sequence'Main_Sequence'
   ObjPosX=1121
   ObjPosY=338
   DrawWidth=32
   DrawHeight=32
   Name="SeqVar_Bool_1"
   ObjectArchetype=SeqVar_Bool'Engine.Default__SeqVar_Bool'
End Object
Begin Object Class=SeqAct_SetBool Name=SeqAct_SetBool_0
   InputLinks(0)=(bDisabledPIE=True,DrawY=260)
   OutputLinks(0)=(DrawY=260)
   VariableLinks(0)=(LinkedVariables=(SeqVar_Named'SeqVar_Named_0'),DrawX=1047)
   VariableLinks(1)=(LinkedVariables=(SeqVar_Bool'SeqVar_Bool_1'),DrawX=1103)
   ObjInstanceVersion=1
   ParentSequence=Sequence'Main_Sequence'
   ObjPosX=1009
   ObjPosY=226
   DrawWidth=128
   DrawHeight=61
   Name="SeqAct_SetBool_0"
   ObjectArchetype=SeqAct_SetBool'Engine.Default__SeqAct_SetBool'
End Object
Begin Object Class=SeqEvent_LevelStartup Name=SeqEvent_LevelStartup_0
   MaxWidth=99
   OutputLinks(0)=(Links=((LinkedOp=SeqAct_SetBool'SeqAct_SetBool_0')),DrawY=260)
   ObjInstanceVersion=1
   ParentSequence=Sequence'Main_Sequence'
   ObjPosX=833
   ObjPosY=194
   DrawWidth=69
   DrawHeight=89
   Name="SeqEvent_LevelStartup_0"
   ObjectArchetype=SeqEvent_LevelStartup'Engine.Default__SeqEvent_LevelStartup'
End Object
Begin Object Class=SeqVar_Bool Name=SeqVar_Bool_0
   bValue=1
   VarName="PIE"
   ObjInstanceVersion=1
   ParentSequence=Sequence'Main_Sequence'
   ObjPosX=905
   ObjPosY=322
   DrawWidth=32
   DrawHeight=32
   Name="SeqVar_Bool_0"
   ObjectArchetype=SeqVar_Bool'Engine.Default__SeqVar_Bool'
End Object

This function is for PIE. Not the delicious kind but rather an acronym to detect if the script is being run in the editor; Play In Editor. Personally, I'm not a level designer nor a scriptwriter so I can't elaborate on why this is necessary, just that it's in every single Borderlands map. This function is on it's own little island so there's no need to connect it to any of your own Kismet.

Begin Object Class=SeqVar_Named Name=SeqVar_Named_1
   ExpectedType=Class'Engine.SeqVar_Bool'
   FindVarName="PIE"
   ObjInstanceVersion=1
   ParentSequence=Sequence'Transitions'
   ObjPosX=-2136
   ObjPosY=-2928
   ObjColor=(B=0,G=0,R=255,A=255)
   DrawWidth=32
   DrawHeight=32
   Name="SeqVar_Named_1"
   ObjectArchetype=SeqVar_Named'Engine.Default__SeqVar_Named'
End Object
Begin Object Class=SeqCond_CompareBool Name=SeqCond_CompareBool_0
   InputLinks(0)=(DrawY=-2990)
   OutputLinks(0)=(Links=((LinkedOp=SeqAct_MultiLevelStreaming'SeqAct_MultiLevelStreaming_1')),DrawY=-2990)
   OutputLinks(1)=(DrawY=-3000,bHidden=True)
   VariableLinks(0)=(LinkedVariables=(SeqVar_Named'SeqVar_Named_1'),DrawX=-2111)
   ObjInstanceVersion=1
   ParentSequence=Sequence'Transitions'
   ObjPosX=-2160
   ObjPosY=-3024
   DrawWidth=99
   DrawHeight=61
   Name="SeqCond_CompareBool_0"
   ObjectArchetype=SeqCond_CompareBool'Engine.Default__SeqCond_CompareBool'
End Object
Begin Object Class=SeqAct_MultiLevelStreaming Name=SeqAct_MultiLevelStreaming_1
   Levels(0)=(LevelName="Dry_Env")
   Levels(1)=(LevelName="Dry_Light")
   Levels(2)=(LevelName="Dry_Spawnbox")
   Levels(3)=(LevelName="Dry_Bunker_Entrance")
   Levels(4)=(LevelName="Dry_Audio")
   bShouldBlockOnLoad=True
   InputLinks(0)=(DrawY=-2990)
   InputLinks(1)=(DrawY=525,bHidden=True)
   OutputLinks(0)=(DrawY=-2990)
   ObjInstanceVersion=1
   ParentSequence=Sequence'Transitions'
   ObjPosX=-2016
   ObjPosY=-3024
   DrawWidth=158
   DrawHeight=45
   Name="SeqAct_MultiLevelStreaming_1"
   ObjectArchetype=SeqAct_MultiLevelStreaming'Engine.Default__SeqAct_MultiLevelStreaming'
End Object

The second function is where the level streaming takes place. The "Compare Bool" In should be connected to your main "Level Loaded and Visible" Out. The "Stream Multiple Levels" node contains the array of maps that will be streamed with Kismet. Keep in mind that for this script to register as working (green check), this array must either be empty or only populated with the maps that you have already imported into the Level Group.

Bring up the properties for the "Stream Multiple Levels" node by clicking on it and below you'll see a line titled "Levels". Clicking on that should cause several buttons to appear beside it. Click on the green plus sign to add an empty value to the array. This value stores the name of the map (or maps) that Kismet will stream. It is a simple text field so the name must be entered manually, simply type the file name of the map without the (.umap) extension. Unless there is a typo, your red 'X' should turn into a green check. Save the map, level streaming is complete and if you've been following these tutorials you now have working music.


Further information in level streaming in Unreal Engine 3 can be found on the Unreal Developer Network .

Corrections and hate-mail.

 

Previous