This page documents an upcoming feature.
The Item System provides a way to create and store objects within the game world that can be collected by players. The Item System uses the Spec System to design an instantiate Items, Item Containers and Item Appearances. The Item Category and Currency Spec Oracles are used by the Item System for Item spec decorators. However, no nodes are instantiated from them. Items serve a variety of purposes in Massive Multiplayer Games ranging from weapons used to fight enemies, armor to protect, clothing that changes appearance, objects that provide bonuses or are used to craft other Items, objects that are collectable and some things that are just junk. While items in many games share general categories of behavior, each game applies its own special touches. Many game engines provide a rigidly defined item/inventory system, which works perfectly so long as your game design matches the engine's design but can be extremely difficult to modify to suit a design's unique needs. Rather than implement a similar overly restrictive architecture, HeroEngine provides a flexible item/inventory framework that can be extended to have exactly the functionality that your game design requires.
What Issues Does This Address?
- Create objects with the game world that can be collected by players.
- Rudimentary Item Container system to store Items.
- Visualize an Item as an asset in the game world.
What Issues Does This NOT Address?
- GUI implementation of Item Containers.
- Does not provide a system for acquiring Items, such as loot dropped by a defeated enemy.
- Does not provide game specific Item Containers such as vault, bank, chest.
The Item System utilizes the Spec System for its underlying data storage and to take advantage of its efficient storage/transmission mechanisms and ability to act as a factory for complex objects. Item Container Owners and Item Containers were designed to be simplistic but flexible enough to be overridden easily.
Item Container Owner
Item Container Owners are the only type of object that can store Item Containers in order to keep class hierarchy simple. Item Container Owners must also be derived from _PlayerCharacter to take advantage of Player Characters existing as Arbitrary Root Nodes. If the Item System is being used in a game then all characters will also be Item Container Owners. Item Containers are stored on a Item Container Owner by the Item Container's name, therefore an Item Container Owner can only have one Item Container with a given name. Item Container Owners provide the functionality to add and remove Item Containers from themselves.
Item Containers are created by the Item Container Spec Oracle and stored by name on a Item Container Owner. Items are stored on a Item Container in a map where the key is the ID of the Item and the value is a NodeRef to the Item. Item Containers provide the functionality to add and remove Items from themselves. Each Item Container is the primary node in it's own replication group which means Items are Replicated from server to client by that Item's Container.
Items are created by the Item Spec Oracle and are decorated by the spec system to give Items additional data to describe them as well as specialized functionality. An example is the Value Item decorator which gives the Item arbitrary values in various currencies stored in a map. The Currency spec oracle is used to define the currencies. The base Item class provides an interface to send a number of events that Item decorator classes can respond to. Some of the Item events decorators can respond to include Acquired, Lost, Activated, Used, Equipped and Unequipped.
Item Appearances are created by the Item Appearance Spec Oracle. Item appearances are used to visualize an Item in the game world. Items can be visualized with the Single Visualization Item Decorator or Multiple Visualization Item Decorator glommed onto the Item Spec in the glom menu of the Item Spec Oracle Editor. Item Appearances are replicated in the replication group of the Player Account node of the Item Container Owner. There are three ways Items are visualized: dynamic parts swapping, bone tracker node with an attached prop bucket instance and the behave hold command with a prop bucket instance.
In order to allow items the maximal flexibility in how they are visualized, they mimic the data structures/hierarchy used by characters (_PlayerCharacter has 1..N _CharacterAppearance nodes).
Item Categories are stored in the Item Category Spec Oracle. The Item Category Spec Oracle does not create category objects; it only provides the ability to define and store them. Item Categories are used to divide Items into classifications that can be leveraged by a particular game's systems. Some common category examples are: weapon, armor, raw material, consumable, ammunition and quest.
Currencies are defined and stored in the Currency Spec Oracle and like Item Categories, there are no Currency objects created by the Currency Spec Oracle. Currencies are used as the foundation for a game economy. The Value Item Spec Decorator use currencies to describe the value of an Item. To create an Item to act as physical Currency it could have a value of 1 in a single Currency and be a Stackable Item.
Before Items can be created using the Spec System and given to Characters, the Item System must be enabled for the world. All of the Item System Spec Oracles should be added to the Hotspot menu. The Item system provides a basic Item Container system which in most cases will need to be extended to provide game-specific functionality such as a way to acquire Items during gameplay and Item Containers with non-character owners. There is no GUI supplied with the Item System so they will have to be designed and scripted to interact with Items and an Item Container system.
Enabling the Item System for Characters
Item Container Owners are derived from Player Characters because an Item logically belongs to only one character and because Player Characters exist as Arbitrary Root Nodes. This means that Item Containers and Items are loaded into the game when the Player Character logs on. When the Player Character is unloaded from the world, all of their Item Containers and Items are unloaded and saved persistently. When a Character travels to another area, all of their Item Containers and Items move with them.
There are steps that need to be completed in order for Player Characters to have Items.
- 1. Create a new class in the server and client DOM that will be used as the Player Character class.
- 2. Add as parent classes _PlayerCharacter and _ItemContainerOwner.
- 3. Create a prototype from the new Player Character class that was just created.
- 4. Override
HE_CSSUseCharacterPrototypein the class methods script of a new or existing class. It should return (as a reference) a noderef of the prototype that was previously created and return true.
- 5. Using the System Node Configuration GUI add to the server Character Selection System the class which contains the override of
- 6. Log out and return to the character selection screen. Create a new character which will now be able to own Item Containers and Items.
New Item objects are created from Item Spec's which are like blueprints, holding all the immutable data. Defining the functionality of an Item is done by creating and editing Item Specs. Item Specs are created and edited with the Item Spec Oracle Editor. To open the Item Spec Oracle Editor type
/heoracle open _ItemSpecOracle into the chat panel or open the Hotspot Menu and click on the Items option under Spec Oracles on the Tools tab. To create a new Item Spec click on the Add button on the Spec Oracle Editor. To modify how an Item will behave click on the Glom button and select Item Spec Decorators to add. To edit the parameters added by the Item Spec Decorators click on the Edit button.
Item Spec Decorators
- Account Bound Item Spec Decorator has a number of flags corresponding to Item events. The decorator helper responds to these Item events and if the corresponding flag was set on the spec decorator the Item will be bound to the Player Account node of the Item's Item Container Owner
- Character Bound Item Spec Decorator behaves the same way as the Account Bound Item Spec Decorator except that the Item will be bound to the Item's Item Container Owner.
- Activatable Item Spec Decorator responds exclusively to the
- Category Item Spec Decorator gives an Item a category by storing the spec key of a Item Category Spec from the Item Category Spec Oracle.
- Character Bound Item Restriction Spec Decorator gloms a decorator helper on an Item that restricts an Item from being added to an Item Container when the destination Item Container has a different Item Container Owner than the Item. This restricted is only enforced when the Item is bound to a Player Character.
- Multiple Visualization Item Spec Decorator adds functionality to an Item so it can be visualized in the world by creating an Item Appearance node. A list of Item Appearance spec keys are stored on the spec which are the possible Item Appearances the Item can use to visualize. Only one Item Appearance is actively visualizing at a time.
- Single Visualization Item Spec Decorator adds functionality to an item so it can be visualized in the world by creating an item Appearance node. There is an Item Appearance spec key stored on the spec which is used to create the Item Appearance node used to visualize the Item.
- Stackable Item Spec Decorator gives an Item the ability to have multiple of the same type of Item stacked onto each other forming a single Item with a stack size. Items can be added and removed from the stack and the stack can be split to create new Item stacks.
- Value Item Spec Decorator gives an Item a map of the Item's value in various Currencies. Each Currency is referenced by it's spec key in the Currency spec oracle.
Item Appearance nodes determine how Items are visualized in the game world. When they are created they are associated to the relevant Item and the Item's Owner node. Item Appearance nodes are replicated in the Item's Owner's Account replication group. There are 3 Item Appearance Spec' which determine how that Item Appearance Node is visualized:
- Dynamic Part visualizations utilize the Dynamic Characters system to change the character's appearance node on the server. An example of when Dynamic Parts visualization should be used is to visualize a piece of armor on a dynamic character.
- Bone Tracker Attached Instance visualizations create a bone tracker node in a prop bucket and attaches it to a bone on the character's skeleton. Then prop bucket instance of the asset is created and the bone tracker instance is made a its parent. Bone Tracker visualizations can be created as a weapon in the character's hand or anything else that should be tied to a bone.
- Behave Attached Instance visualizations use the Character Behave Commands command behave "hold" to attach a prop bucket instance on a bone of the character's skeleton.
Adding and Removing an Item Container
To add an Item Container to be owned by an Item Container Owner, there must be an instantiated spec derived object which is created by the Item Container Spec. There is a method on the $ITEM system node called
_CreateItemContainerFromSpecKey that does this. After the Item Container node is created, it needs a name before it can be owned. An Item Container's name is set with the method
_SetItemContainerName. It's important to note that an Item Container Owner can only have one Item Container with a given name. Always use the method
_HasItemContainerByName when determining what to name an Item Container. After the Item Container has a name add it to the Item Container Owner with the method
_AddItemContainer. Before removing an Item Container from an Item Container Owner call
_HasItemContainerByName to make sure it's actually owned by that Item Container Owner. The method
_RemoveItemContainerByName will remove the Item Container from the Item Container Owner, the Item Container is not destroyed during this process.
Adding and Removing an Item
In order to add an Item to an Item Container there must be an instantiated spec derived object which is created by the Item Spec. There is a method on the $ITEM system node called
_CreateItemFromSpecKey that already does this. After there is an Item node but before it is added the Item Container method
_CanAddItemToContainer must be called on the destination Item Container to make sure adding the Item is valid. The method
_AddItemToContainer will add the Item to the Item Container and cause it to have a new Item Container Owner. Removing a Item from an Item Container is a similar process. There must be a valid Item node to remove and the method
_CanRemoveItemFromContainer called on the source Item Container to make sure the Item can be removed. The method
_RemoveItemFromContainer will remove the Item from the Item Container. The Item is not destroyed during this process.
On the Client
Most of the client interaction with the Item System takes place on Items and Item Containers. The server is the authoritative source for manipulating Items and sending Item events. The client interfaces for Items and Item Containers have methods that send requests to the server to fire off Item events and add or remove an Item from an Item Container.
Items on the client have a number of request methods that make a remote call to the server and trigger an event on the server copy of the Item. Some examples of these request methods are:
_RequestItemUnequip. Items are replicated from the server to the client in it's owning Item Container's replication group. When an Item is first replicated to the client, it makes an asynchronous call to the Item Spec Oracle on the server requesting the Item's Spec data. When the Item's Spec data is sent to the client, the shared function
_ItemDecoratorOnSpecLoaded is called on Item Spec Decorators that need to request additional Spec data from the server.
Item Containers on the client also have request methods which make a remote call to the server copy of the Item Container. These request methods are
_RequestRemoveItemFromContainer. The rest of the methods on the client Item Container are used to determine what Items are being contained there and handling when an Item node is replicated from the server to the client.
An Item Appearance node on the client is responsible for visualizing an Item in the game. There are two ways an Item is visualized on the client, Bone Tracker Attached Instance and Behave Attached Instance. The Bone Tracker Attached Instance creates a Bone Tracker Node in a Prop Bucket and attaches it to the character on the bone specified in the Item Appearance Spec. Then the asset specified in the Item Appearance Spec is created in a Prop Bucket and the Bone Tracker Node is set at it's parent. The Behave Attached Instance creates an asset in a Prop Bucket and uses the Character Behave Commands hold to attach the asset to the character on the bone specified in the Item Appearance Spec.
New Spec Decorators
A Spec Decorator class is a class that extends the functionality of a spec. Decorator helpers are classes that a spec decorator composites onto a spec-derived object to provide it with the functionality required by the spec decorator. The Spec System Advanced Usage page describes how to add Decorator helper classes to a spec-derived object (an Item).
- Create a new class in the server and client DOM that will be the new Item Decorator.
- Next create and add any fields necessary for the Item Decorator, keeping in mind these will be immutable. If necessary create a Decorator Helper class that will contain mutable data as well as the functionality for the Item Decorator. Even if the decorator and decorator helper only have functionality or fields on the server, each class and the decorator's fields need to exist in the client DOM so they can be viewed and modified by the Spec Oracle Editor.
- Create a new custom Item System class and GLOM it onto the ITEMSYSTEM prototype located in the server DOM. The System Node Configuration GUI is the preferred method to do that because it handles the communication to update any instantiations of a System Node to reflect the changes you have made.
- In the new class's script, implement the method
HE_ItemSystemSpecOracleGetSpecDecoratorClassesand add the new Decorator class's name to the list of valid Spec Decorator classes.
New Item Events
An Item event consists of two methods and one shared function defined in the server Item class methods script or any child Item class methods script. The first method is the one that is called to trigger the event. The second method is responsible for notifying all Item Decorator Helper classes glommed onto the Item by calling the shared function. The shared function is what is implemented in an Item Decorator Helper class methods script that will respond to specific Item events. Each of these has a naming convention which indicates it's behavior. The event trigger method is named
Item<event>, the method that notifies decorator helpers of the event is named
ItemOn<event> and the shared function that receives the event is named
OnItem<event>. For example the Acquired event has these methods and function:
Any new Item event will need to be defined in a new custom Item class with a parent class of
_Item. Item nodes are instantiated by the Item Spec, so in order to create a custom Items there must be a new custom Item Spec class with a parent class of
_ItemSpec. To create custom Item Specs in the Item Spec Oracle Editor, the custom Item Spec class must be added to the list of valid Item Spec Oracle Base Classes. Implementing the method
HE_ItemSystemSpecOracleGetValidBaseClasses on a class glommed onto the Item System Node will enable the custom Item Spec to be created. In the custom Item Spec class methods script, override the method
CreateFromSpec to create custom Item objects.
The following is a method break down of important Item related classes that can be extended via overloading.
unique method _CreateItemFromSpecKey(specKey as ID) as NodeRef of Class _Item
unique method _CreateItemContainerFromSpecKey(specKey as ID) as NodeRef of Class _ItemContainer
unique method _CreateItemApperanceFromSpecKey(specKey as ID) as NodeRef of Class _ItemAppearance
unique method _ItemSystemSpecOracleGetValidBaseClasses(valid references List of String)
unique method _ItemSystemSpecOracleGetSpecDecoratorClasses(valid references List of String)
method _GetItemContainerByName(containerName as String) as ID
method _GetAllItemContainerNames() as List of String
method _HasItemContainerByName(containerName as String) as Boolean
method _AddItemContainer(newContainer as NodeRef of Class _ItemContainer)
method _RemoveItemContainerByName(containerName as String) as NodeRef of Class _ItemContainer
method _GetItemContainerName() as String
method _SetItemContainerName(newContainerName as String)
method _GetItemContainerOwner() as NodeRef of Class _ItemContainerOwner
method _SetItemContainerOwner(newContainerOwner as ID)
method _CanAddItemToContainer(item_to_add as NodeRef of Class _Item) as Boolean
method _AddItemToContainer(item_to_add as NodeRef of Class _Item) as Boolean
untrusted method _RequestedAddItemToContainer(item_to_add as ID)
method _CanRemoveItemFromContainer(item_to_remove as NodeRef of Class _Item) as Boolean
method _RemoveItemFromContainer(item_to_remove as NodeRef of Class _Item) as Boolean
untrusted method _RequestedRemoveItemFromContainer(item_to_remove as ID)
method _GetItemContainerMaxContainedItems() as Integer
method _GetNumberOfContainedItems() as Integer
method _ItemContainerHasSpareSpace() as Boolean
method _HasContainedItemByID(containedItem as ID) as Boolean
method _HasContainedItemBySpecKey(specKey as ID) as Boolean
method _GetAllContainedItemsBySpecKey( spec_key as ID ) as List of NodeRef of Class _Item
method _GetItemContainerID() as ID
method _GetItemOwnerID() as ID
method _SetItemContainer(newContainer as ID)
method _ItemAcquired(itemContainer as ID)
method _ItemCanUse() as Boolean
method _ItemCanAddToContainer(item_container as NodeRef of Class _ItemContainer) as Boolean
method _ItemCanRemoveFromContainer() as Boolean