OPAT

From Crash Bandicoot Hacking Wiki
Jump to navigation Jump to search

OPAT is the 10th subsystem in Crash 1. It concerns the allocation and initialization (and releasing) of all game objects. For this reason, a proposed name for its expansion is Object/Process Allocation Table.

Initialization routine

The OPAT initialization routine is located at the following addresses in each of the Crash games:

  • Crash 1 NTSC-U: 0x1AAD8
  • Crash 2 NTSC-U: 0x1EE64

Crash 1

Object Allocation

This routine begins by allocating a block of memory for 96 objects with the malloc function (96 objects * 604 bytes/object = 57984 bytes). A pointer to the newly allocated memory is stored in objects of the GOOL subsystem namespace. objects now refers to a dynamically allocated array of 96 objects.

The routine then allocates a separate section of memory for the 97th object-the player object. An extra 256 bytes in addition to the standard 608 byte structure size (608+256 = 860) is allocated for the player object. This is to account for the higher number of activation records created and local 'registers' used by its lengthier, more complex code. A pointer to the newly allocated memory is stored in player of the GOOL subsystem namespace.

If either the memory for the objects or for the player object could not be allocated, the routine returns error code 0xFFFFFFF1.

Free List/Free Object Pool Initialization

At this point, all the necessary memory for objects has been allocated. The routine now initializes the freelist [list handle] object, marking it as a list handle by setting its header field to 2. Note that a list handle object is not an actual object and only refers to a 'category' of objects, composed of its children.

Next the routine initializes and constructs a linked list of the 96 objects, marking each as a free object and assigning the first object as children of the freelist handle. This establishes a pool of free objects, initially consisting of all 96 objects. In detail, this is done by iterating through the first 95 objects, and for each object:

  • setting its header field to 0. This marks the object a free object.
  • storing a pointer to the object that follows it [in the array] in its sibling field. (objects[n].sibling = &objects[n+1];) This establishes the link between objects. The 96th object does not have a following object so its sibling field is set to 0.
  • setting its parent field to point to the freelist handle. Each object in the free list is a child of the freelist handle, and the left-child right-sibling representation requires that an object always points to its parent object.
  • setting its children field to 0. Presence of a children and sibling field allow objects to have a left-child right-sibling k-ary tree of descendants, however this is irrelevant for free objects. Free objects do not have children and thus initialize their children field to 0.

The freelist handle now refers to the category of free objects, and each of its children are an object in the pool.

Used Object List Initialization

Now the routine initializes 8 the used object list handles: usedlists (array). When the game eventually creates or spawns an object, a free object is adopted from the pool to one of the 8 used object list handles; the game then marks that object as an existing object (i.e. 'in use') and continues to perform its remaining instantiation. Initially, however, no object is in use-all 96 objects are free objects. Consequently, none of the used object list handles should have children. Initializing the 8 handles is then accomplished by iterating through them, and for each handle:

  • setting its header field to 2. This marks the handle [object] a list handle.
  • setting its children field to 0. The handle does not yet have children.

Eventually, the usedlists are used not only to 'contain' spawned or created objects, but also to categorize them into 8 distinct categories.

Player Object Initialization

Finally the routine initializes the player object. This is done by

  • setting its header field to 0. This marks the object a free object (**or rather, not in use)
  • setting its parent field to 0. The player object is treated separately from normal objects. Spawning the player does not require or involve adopting a free object from the pool; the player never belongs to and is never an object among the pool of free objects. Its data will always exist in the 860 byte region allocated for it, **in use or not. Thus it is not necessary for the player object to belong to any particular category and therefore have a parent at initialization.
  • setting its sibling field to 0. The player does not belong to a category and therefore does not have any sibling that could belong to a same category.
  • setting its children field to 0. The player object, though separate from the pool, is a free object and does not have children.

Return Success Code

At this point, the routine returns a success code (0xFFFFFF01).

Summary

  1. For the freelist handle:
    • set type field to 2 (the object is a list handle)
    • set children field to point to objects[0]
  2. For the 96 allocated objects:
    • set type field to 0 (the object is free/unused)
    • set sibling field to point to the following object if not the last object:
    objects[n].process.sibling = &objects[n+1];, else set sibling field to 0
    • set parent field to point to the freelist handle
    • set children field to 0
  3. For the 8 usedlists handles:
    • set type field to 2 (the object is a list handle)
    • set children field to 0 (no objects belong to it at init)
  4. For the player object:
    • set type field to 0 (the object is free/unused)
    • set parent field to 0 (not part of a category)
    • set sibling field to 0 (no sibling in its non-existent category)
    • set children field to 0

Crash 2

Object Allocation

This routine begins by allocating a block of memory for 96 objects with the malloc function (96 objects * 572 bytes/object = 54912 bytes). A pointer to the newly allocated memory is stored in objects of the GOOL subsystem namespace. objects now refers to a dynamically allocated array of 96 objects.

The routine then allocates a separate section of memory for the 97th object-the player object. An extra 256 bytes in addition to the standard 572 byte structure size (572+256 = 828) is allocated for the player object. This is to account for the higher number of activation records created and local 'registers' used by its lengthier, more complex code. A pointer to the newly allocated memory is stored in player of the GOOL subsystem namespace.

If either the memory for the objects or for the player object could not be allocated, the routine returns error code 0xFFFFFFF1.

Free List/Free Object Pool Initialization

At this point, all the necessary memory for objects has been allocated. The routine now initializes the freelist [list handle] object, marking it as a list handle by setting its header field to 2. Note that a list handle object is not an actual object and only refers to a 'category' of objects, composed of its children.

Next the routine initializes and constructs a linked list of the 96 objects, marking each as a free object and assigning the first object as children of the freelist handle. This establishes a pool of free objects, initially consisting of all 96 objects. In detail, this is done by iterating through the first 95 objects, and for each object:

  • setting its header field to 0. This marks the object a free object.
  • setting its parent field to point to the freelist handle. Each object in the free list is a child of the freelist handle, and the left-child right-sibling representation requires that an object always points to its parent object.
  • setting its children field to 0. Presence of a children and sibling field allow objects to have a left-child right-sibling k-ary tree of descendants, however this is irrelevant for free objects. Free objects do not have children and thus initialize their children field to 0.
  • storing a pointer to the object that follows it [in the array] in its sibling field. (objects[n].sibling = &objects[n+1];) This establishes the link between objects. The 96th object does not have a following object so its sibling field is set to 0 (NULL).

The freelist handle now refers to the category of free objects, and each of its children are an object in the pool.

Used Object List Initialization

Now the routine initializes 8 used object list handles: usedlists (array). When the game eventually creates or spawns an object, a free object is adopted from the pool to one of the 8 used object list handles; the game then marks that object as an existing object (i.e. 'in use') and continues to perform its remaining instantiation. Initially, however, no object is in use-all 96 objects are free objects. Consequently, none of the used object list handles should have children. Initializing the 8 handles is then accomplished by iterating through them, and for each handle:

  • setting its header field to 2. This marks the handle [object] a list handle.
  • setting its children field to 0. The handle does not yet have children.

Eventually, the usedlists are used not only to 'contain' spawned or created objects, but also to categorize them into 8 distinct categories.

Player Object Initialization

Finally the routine initializes the player object. This is done by

  • setting its header field to 0. This marks the object a free object (**or rather, not in use)
  • setting its parent field to 0. The player object is treated separately from normal objects. Spawning the player does not require or involve adopting a free object from the pool; the player never belongs to and is never an object among the pool of free objects. Its data will always exist in the 828 byte region allocated for it, **in use or not. Thus it is not necessary for the player object to belong to any particular category and therefore have a parent at initialization.
  • setting its children field to 0. The player object, though separate from the pool, is a free object and does not have children.
  • setting its sibling field to 0. The player does not belong to a category and therefore does not have any sibling that could belong to a same category.

Return Success Code

At this point, the routine returns a success code (0xFFFFFF01).

Summary

  1. For the freelist handle:
    • set type field to 2 (the object is a list handle)
    • set children field to point to objects[0]
  2. For the 96 allocated objects:
    • set type field to 0 (the object is free/unused)
    • set sibling field to point to the following object if not the last object:
    objects[n].process.sibling = &objects[n+1];, else set sibling field to 0
    • set parent field to point to the freelist handle
    • set children field to 0
  3. For the 8 usedlists handles:
    • set type field to 2 (the object is a list handle)
    • set children field to 0 (no objects belong to it at init)
  4. For the player object:
    • set type field to 0 (the object is free/unused)
    • set parent field to 0 (not part of a category)
    • set sibling field to 0 (no sibling in its non-existent category)
    • set children field to 0

Deinitialization routine

This routine simply releases the object memory allocated by the initialization routine:

  • free(objects);
  • free(player);