348 20.PointerPatchingAssets
asset. This can lead to a powerful, optimized tools pipeline with minimal
load times and great flexibility.
■ Symbolic pointers with delayed bindings. Rather than all pointers having
physical memory addresses, some studios use named addresses that can be
patched at run time after loading is complete. This way you can have pointers
that point to the player’s object or some other level-specific data without
needing to write custom support for each case.
■ Generic run-time asset caches. Once loading is handled largely through
pointer-patched blocks with named assets, it is fairly simple to build a
generic asset caching system on top of this, even allowing dynamic reloading
of assets at run time with minimal effort.
■ Simple tools interface that handles byte swapping and recursion. Writing out
data should be painless and natural, allowing for recursive traversals of live
data structures and minimal intrusion.
■ Special pointer patching consideration for virtual tables. A method for
virtual table patching may be necessary to refresh class instances that have
virtual functions. Or choose ways to represent your data without using virtual
functions.
■ Offline introspection tools. Not only is it very useful for debugging the asset
pipeline, but a generic set of introspection tools can help perform vital
analyses about the game’s memory consumption based on asset type,
globally, and without even loading the game on the final platform!
■ Propagate memory alignment requirements. Careful attention to data
alignment allows hardware to receive data in the fastest possible way. Design
your writing interface and linking tools to preserve and propagate alignments
so that all the thinking is done in tools, even if it means inserting some
wasted space to keep structures starting on the right address. All the run-time
code should need to know is the alignment of the block as a whole.
While all the above properties have their merits, a complete and full-featured
system is an investment for studios to undertake on their own. A very basic
system is provided on the website. It supports byte swapping of atomic types,
pointer patching, and a clean and simple interface for recursion.
20.3ABriefExample
Here is a small example of a simple tree structure. Trees are traditionally very
slow because they require many memory allocations and are somewhat
challenging to serialize due to the amount of pointer work required to reconstruct