bw logo

Chapter 2. Entity.prerequisites()

Assets may also be loaded from specific requests issued by the scripted logic. For instance, when the player equips a special item for the first time, that item's model and texture will have to be in memory before it can be displayed. In these cases, if that resource is not already resident, then the main thread will pause, waiting for the load request to complete.

Note

To prevent this kind of problems from creeping into the game, the BigWorld Client issues a warning in the debug output whenever an access to disk is requested from the main thread while the 3D scene is visible[1]. Programmers are encouraged to fix these warnings as soon as they start to pop-up.

The prerequisites() method is the recommended method of pre-loading the resources that may be required by the scripts in order to avoid pauses in the gameplay. It allows gameplay programmers to specify which assets can potentially be used by an entity instance. It will guarantee that the entity will not enter the world until all required resources have been loaded from disk, and are ready to be used by the main thread .

Note

In a truly dynamic game environment it is not possible to anticipate which resources will be requested by the scripts. In these cases, BigWorld.loadResourceListBG() can be used to load further resources.

Note

Although the entity entry into the world may be delayed, that usually is not noticeable, since most entities enter the player AoI at a great distance. Even when that is not the case (after teleporting to a location close to the player, for instance), that is still better than pausing the game or having avatars swing invisible swords

The function differs from Preloads by working on a per-entity instance basis, instead of globally. That allows a much more rational management of resources, since only assets with real potential of being used are stored in memory at any one time. Entity preloads on the other hand, are kept in memory for the whole life of the client application.

The fact that prerequisites work on a per-entity instance basis, as opposed to per-entity type, allows programmers to customise the prerequisites list depending on the state of the entity, further adding to the efficiency of the system. When a non-player entity enters the player AoI, for instance, only those items that the entity is currently carrying would be required to load. The Entity Manager system guarantees that the entity's properties are up-to-date before the prerequisites list is requested.

Note

For details on this function, see the Client Python API's entry Class List Entity, section Callback Method Documentation.

2.1. Using Entity.prerequisites()

The Entity.prerequisites() method is, in fact, very straightforward to use. After an entity is initialised, alongside its properties, but before the onEnterWorld() method is called, the EntityManager class calls the prerequisites() method on the entity. The method must return a list of all assets that must be loaded before the entity enters the world.

A simple example is illustrated below:

class TradeKiosk( BigWorld.Entity ):
  MODEL = 'models\kiosk.model'

  def prerequisites( self ):
    # return list even if it is just a single file
    return [ TradeKiosk.MODEL ]

  def onEnterWorld( self, prerequisites ):
    self.model = prerequisites[ TradeKiosk.MODEL ]

Simple example of loading prerequisite assets

A more realistic scenario is when the required resources vary according to the entity state. In this case, a single entity type is used to model all types of pickable flowers. The type property is used to differentiate each instance. Since type is guaranteed to be initialised when the prerequisites method is called, the script can customise which resources are loaded. In this case, the type property will not change over the lifetime of this particular entity, so we only need to load resource once.

class PickableFlower( BigWorld.Entity ):
  ASSETS = {
    'lili' : ('models\lili.model', 'effects\sparkles.xml')
    'daisy' : ('models\daisy.model', 'effects\spirits.xml')
    'orchid' : ('models\orchid.model', 'effects\petals.xml')
  }

  PICK_SOUND = 'sounds\pick_flower.wav'

  def prerequisites( self ):
    prereq = []
    prereq.append(PickableFlower.ASSETS[self.type][0])
    prereq.append(PickableFlower.ASSETS[self.type][1])
    prereq.append(PickableFlower.PICK_SOUND)
    return prereq

  def onEnterWorld( self, prerequisites ):
    # model varies according to the type of flower.
    # prerequisites can be accessed like a map, and returns python objects.
    # in this case, we know that .model files become PyModels.
    self.model = prerequisites[ PickableFlower.ASSETS[self.type][0] ]
    
    # it is up to us whether or not to hold onto the PyResourceRefs instance
    # passed into onEnterWorld.  In this case, we will be using the particle
    # system at a later date, so we'll simply hold onto the object until it
    # is needed.
    self.prerequisites = prerequisites

  def onPickEvent( self ):
    # picking sound effect is constant between types
    self.model.playSound( PickableFlower.PICK_SOUND )

    # particle effect varies according to the type of flower
    particles = self.prerequisites[ PickableFlower.ASSETS[self.type][1] ]
    self.model.root.attach( particles )
    particles.force(1)

Another example of load prerequisite assets



[1] For details, see the Client Python API's entry Modules BigWorld, section Member Functions, function BigWorld.worldDrawEnabled.