If the prototypes are loaded on demand, are they available synchronously? Does access to an unloaded prototype cause a blocking read on the DB?
Yes, it is synchronous.
The features of the Spec System that make it ideal for MMO data storage:
- Prototypes are loaded on demand and will eventually also age out so they can be unloaded if not recently used.
- The only time using a spec results in a hit on the database in a live game is when you need to load it, after that it is cached in the local GOM.
- For Specs that are used only on the client, the client reads those from the repository and creates its own local cache never touching the server. (Bandwidth friendly)
- Capable of writing out a subset of information to the repository for client-side access to limit the player access to data you wish only known to the server.
- Supports light-weight instantiations of objects containing only mutable data
- Specs may optionally function as factories for their light-weight instantiations (if any are needed)
- Overhead for a prototype is approximately the same as any other node (C++ guys can chime in here to give exact values perhaps)
For Hero's Journey, the spec system is used for definitions of all kinds; creatures, FXs, AI States, abilities, items, stateful objects, combat effects, shop inventories, treasure tables and so on. It allows designers to create everything for the game parametrically, only requiring new code when we need to introduce a capability that is totally new. Like everything else we do, we make tools to make building stuff easy.
We feel very confident that thousands of specs will be acceptable (and expected) usage for the system and even significantly greater numbers will not be an issue as we add additional optimizations to age out specs that haven't been referenced recently to unload them from memory. As you reach extremely large numbers of specs in the same Spec System, it is possible some features of the system will require tweaking to handle that many records (specifically the generic spec selector GUI).
Now, your game's designers can do things that would negate some of the advantages of using specs; such as loading all specs potentially needed by a character preemptively when they log into an area instead of only when you actually need them and so on.
What triggers the load of a prototype from the database?
The node for a prototype is loaded when getNode() is called on the HeroPrototype (at the C++ level) and the prototype node hasn't already been loaded. The external functions GetPrototypeByID() and GetPrototype() both cause a prototype to load.
At the C++ level, calling setNODEREF on a HeroVariable where the ID is a prototype ID will cause a load on demand.
In HSL code, setting a NodeRef variable to a literal value, even if the literal value is the ID of a prototype, will not cause the prototype to load. Irrespective of the prototype load status, setting a NodeRef to a literal which is not a regular node ID will result in the NodeRef being set to None. Assigning a NodeRef which points to a prototype node to another NodeRef will point the assignee to the prototype's node.
Calling GOM::queryPrototypes() (at the C++ level) will return all prototypes if no class ID filter is specified. If a class ID is specified, it will actually load all prototype nodes in order to determine if they have that class. Calling the Command Line Interface command QP will actually load the prototype nodes because it does a describe on the prototype, which returns things like classes, which needs the prototype node loaded. Calling the client-side external function queryPrototypes() will also cause them to load.