There is no spoon
Legacy:Chain Of Events At Level Startup
This page describes what happens right after a level was loaded. It lists the startup engine events and the UnrealScript functions subsequently called by those events and gives a short description how these events and functions could be used.
Actors that were created because they are listed in the ServerActors list of a server's INI file also use the chain of events described on this page. Other actors spawned during this chain of events (e.g. Mutators or GameRules) use the chain of events when spawning actors and are not included here (unless UnrealEngine1 is used) except for the last event in this list.
This whole page is based on a snippet of native UT2004 code posted on the UT2003Mods mailing list. Most parts will be similar in older engine versions, but there might be important differences in the functions called by these events.
Contents
Chain Of Events
These are the events directly called from native code. See the sections below for more details about functions called by these events.
Here "all actors" means all actors that were placed in the map by the mapper or were created as ServerActors. Actors that have been created with the Spawn() function or that have received a Destroy() call are excluded from this chain of events.
- the GameInfo's InitGame() event is called
- the GameInfo's SetGrammar() event is called (UT2004)
- all Actors' PreBeginPlay() events are called
- all Actors' BeginPlay() events are called
- all Actors' zones are set
- all Actors' volumes are set
- all Actors' PostBeginPlay() events are called
- all Actors' PostNetBeginPlay() events are called
- all Actors' SetInitialState() events are called
- all Actors either with bShouldBaseAtStartup=True and Physics set to PHYS_None or PHYS_Rotating or with an AttachTag get their base set
After all this players can start joining. This is especially also true for single player/instant action mode and means that the chain of events when a player logs in is only executed after these events.
GameInfo.InitGame()
This initializes the GameInfo. At this point all the mapper-placed actors already exist, they just didn't get any of their initialization functions called yet.
- The GameProfile class specified in the "SaveGame" parameter is loaded and initialized. (if specified)
- The GameSpeed is set according to the "GameSpeed" parameter. (SetGameSpeed(), if specified)
- The base mutator is added via AddMutator().
Note: Any actors spawned before this or during the base mutator's initialization (see Chain Of Events When Spawning Actors) must have bGameRelevant=True set or they will cause an Accessed None when trying to call the base mutator's CheckRelevance() function and as a result of this destroy themselves. - The BroadcastHandlerClass is spawned.
- The AccessControl class is spawned. Either the class specified in the "AccessControl" parameter will be used or the AccessControlClass. If neither of those are set, Engine.AccessControl is used.
- All GameRules specified in the "GameRules" parameter will be spawned.
- All Mutators specified in the "Mutator" parameter will be added via AddMutator().
AddMutator() only adds a mutator if its GroupName is an empty string or is not the same as the GroupName of any other mutator (including the base mutator) already added. The mutator's bUserAdded variable is set to False for the base mutator and to True for all mutators added via the "Mutator" parameter.
For subclasses of DeathMatch InitGame() looks for a LevelGameRules actor before going though the things described above. The first LevelGameRules actor found will receive an UpdateGame() call.
InitGame() also reads some other parameters specified in the level URL, but these mostly don't call any important functions.
GameInfo.SetGrammar() (UT2004)
This loads the appropriate speech recognition grammar file.
(no additional information about this so far)
Actor.PreBeginPlay()
...in UT2003
If the actor has bGameRelevant == False and this event is not executed on a client, the game's base mutator's CheckRelevance() function is called.
CheckRelevance() first calls the base mutator's AlwaysRelevant() function which recursively calls the other mutators' AlwaysRelevant() functions. If this function returns True the actor is considered game relevant and CheckRelevance() returns True resulting in the Actor continuing to exist.
If AlwaysRelevant() returns False, the base mutator's IsRelevant() function is called. This function calls the mutator's CheckReplacement() function and returns its result if it's False. Otherwise IsRelevant() returns the result of the next mutator's IsRelevant() function.
Finally the result of the base mutator's IsRelevant() function is returned by CheckRelevance() and again, if that result is True the actor will continue to exist, otherwise it will destroy itself.
...in UT
If the actor has bGameRelevant == False and this event is not executed on a client, the GameInfo's IsRelevant() function is called.
IsRelevant() first calls the base mutator's AlwaysRelevant() function which recursively calls the other mutators' AlwaysRelevant() functions. If this function returns True the actor is concidered game relevant and GameInfo.IsRelevant() returns True resulting in the Actor continuing to exist.
If AlwaysRelevant() returns False, the base mutator's IsRelevant() function is called. This function calls the mutator's CheckReplacement() function and returns its result if it's False. Otherwise IsRelevant() returns the result of the next mutator's IsRelevant() function.
If the base mutator's IsRelevant() function returns False the GameInfo's IsRelevant() function also returns False and the actor destroys itself. Otherwise if the bSuperRelevant property is set to 1 GameInfo.IsRelevant() returns True resulting in the Actor continuing to exist.
If the base mutator's IsRelevant() function returns True but the bSuperRelevant property is not set to 1 the GameInfo's IsRelevant() function checks whether the actor may appear in the current difficulty level, if it's a "monster" (a non-player Pawn (UT)) and if there's a random chance for the actor to not appear in the game (OddsOfAppearing). The GameInfo.IsRelevant() function will also update the number of secret goals, item goals and kill goals before returning True and allowing the actor to exist.
Actor.BeginPlay()
This event is called after an Actor is considered "relevant" for this game, i.e. no Mutator wanted to get rid of it.
Most actors don't use this event, but if you're looking for an event that is called before the actor is initialized, but after the mutator checks are done, then this is the place for you.
Actor Zones
At this point the Actor.Region.Zone value becomes valid. This event also causes the ZoneChange() event to be called.
Actor Volumes
At this point the Actor.PhysicsVolume value becomes valid. This event also causes the PhysicsVolumeChange() event to be called.
Actor.PostBeginPlay()
Most actors use PostBeginPlay() to initialize their UnrealScript values. The actor's PhysicsVolume and Zone are valid but the actor is not yet in any state.
Actor.PostNetBeginPlay()
PostNetBeginPlay() is called directly after PostBeginPlay() on the server. On clients it will be called when the initial replication is completed.
Actor.SetInitialState()
At this point the actor is concidered "initialized" by the engine (bScriptInitialized is set to True in this event) and the actor's initial state is set. If the InitialState property is set, it will be used, otherwise the actor goes to its auto state. Since SetInitialState() is a simulated function by default this happens on server and clients.
This event uses GotoState to change the state, so during its executing the initial state's BeginState() event is called. The state's state code will however not yet start executing at this point. This will happen after all the events described on this page have finished doing their work.
Actor Bases
Actors with an AttachTag other than None are attached to the first actor with a matching Tag or name via SetBase(theMatchingActor)
. Actors with bCollideWorld = true and bShouldBaseAtStartup = true which use either PHYS_None or PHYS_Rotating try to find a suiting base as well. The AttachTag is evaluated first and if set bShouldBaseAtStartup is ignored, whether or not the AttachTag matches anything.
In both cases when a base is set the actor's BaseChange() event will be called. Note that this final step of startup initialization also includes actors that were Spawn()
ed during any of the previous initialization steps.