Mary X.
How can I find job-related messages?
To help me find the messages, please tell me what you are looking for. Are you looking for a specific section, the text itself, or a summary?
Lumberyard is a powerful game engine used for developing games on multiple platforms. This guide will help you understand the core concepts and features of Lumberyard.
Advertisement
Advertisement
Lumberyard Developer Guide
Copyright
©
2017 Amazon Web Services, Inc. and/or its affiliates. All rights reserved.
Amazon's trademarks and trade dress may not be used in connection with any product or service that is not Amazon's, in any manner that is likely to cause confusion among customers, or in any manner that disparages or discredits Amazon. All other trademarks not owned by Amazon are the property of their respective owners, who may or may not be affiliated with, connected to, or sponsored by
Amazon.
Lumberyard Developer Guide
Version 1.10
iii
Lumberyard Developer Guide
Version 1.10
iv
Lumberyard Developer Guide
Version 1.10
v
Lumberyard Developer Guide
Version 1.10
vi
Lumberyard Developer Guide
Version 1.10
vii
Lumberyard Developer Guide
Version 1.10
viii
Lumberyard Developer Guide
Version 1.10
ix
Lumberyard Developer Guide
GameplayNotificationBus<float>) ................................... 658
Vector3GameplayNotificationBus (
AZ::GameplayNotificationBus<AZ::Vector3>
StringGameplayNotificationBus (
GameplayNotificationBus<const AZStd
Version 1.10
x
Lumberyard Developer Guide
Version 1.10
xi
Lumberyard Developer Guide
Version 1.10
xii
Lumberyard Developer Guide
Version 1.10
xiii
Lumberyard Developer Guide
Version 1.10
xiv
Lumberyard Developer Guide
Version 1.10
xv
Lumberyard Developer Guide
The Lumberyard Developer Guide is intended for programmers or anyone working directly
with the Lumberyard code. For a conceptual orientation, see Core Concepts of Lumberyard for
.
This guide includes the following sections:
•
Describes a variety of AI features that process navigation and individual and group behaviors, and describes convenient tools such as a Visual AI debugger, behavior tree visual editor, and a visual flow graph editor.
•
Contains tools to create both linear (video) and interactive animation. Interactive animation conveys AI and avatar (player) behavior, with sequences dependent on player choices in gameplay.
•
Use the asset builder API to develop a custom asset builder that can process any number of asset types, generate outputs, and return the results to the asset processor for further processing. A custom builder can be especially useful in a large project that has custom asset types.
•
AZ Code Generator is a command line utility that generates source code (or any data or text) from specially tagged source code. You can use it when the structure of the intended code is known in advance.
•
AZ modules are new, Amazon-created code libraries that plug into Lumberyard games and tools. These
AZ modules implement specific initialization functions. When a Lumberyard application starts, it loads each AZ module and calls the corresponding
•
Cloud Canvas is Lumberyard's technology for connecting your game to Amazon Web Services. With
Cloud Canvas, you can use AWS to implement cloud-hosted features and create asynchronous multiplayer games. Using AWS means you no longer have to acquire, configure, or operate host servers to implement connected gameplay.
•
Component Entity System (p. 455)
Version 1.10
1
Lumberyard Developer Guide
The component entity system is a new Amazon-created way of creating components that is superior to
(and that will eventually replace) the legacy Entity System (p. 551)
.
•
Controller Devices and Game Input (p. 496)
Describes Lumberyard's support for input devices such as keyboards, mice, and joysticks, and shows how to set up controls and action maps.
•
Describes game engine interfaces, including CryExtension, which you can use to refactor Lumberyard features into extensions for ease of use; CryString, which is a custom reference-counted string class; and a serialization library, which separates user serialization code from actual storage format and makes it easy to change formats.
•
Demo and Video Capture (p. 545)
Describes how to use Lumberyard Editor or the Lumberyard standalone Launcher to record benchmarking videos and capture audio.
•
Describes the creation and management of entities, which are objects placed inside a level that players can interact with. This section contains topics such as creating a new entity class, entity pools, and entity scripting.
•
Event buses are Lumberyard's general purpose system for dispatching messages. EBuses minimize hard dependencies between systems, are event-driven (which eliminates polling), handle concurrency well, and enable predictability by providing support for the ordering of handlers on a given bus.
•
Describes how to compress game content files and how to track invalid file reads that can potentially stall the performance of a game.
•
Graphics and Rendering (p. 606)
Lumberyard's shading core uses the same physical parameters that are used in high end film rendering pipelines. This section covers render nodes, true type font rendering, and the star data used in sky rendering. It also describes how to control anti-aliasing so that you can produce graphics from very sharp images to softer blurred images.
•
Lua is Lumberyard's scripting language. This section contains a guide to writing Lua scripts for
Lumberyard's component entity system, a tutorial on Lumberyard's Lua Editor, and Lua API references.
•
Describes GridMate, Lumberyard's networking subsystem, and contains topics on multiplayer setup, the session service, controlling bandwidth usage, and synchronizing game state using the GridMate replica framework.
•
Describes the Lumberyard physics system and how to interact with the physics engine. This section shows you how to create a physical world object, fill the world with geometries and physical entities, and control the entities with the functions described.
•
Profiler is a Lumberyard tool that can capture, save, and analyze network, CPU, and VRAM usage statistics. You can used the saved data to analyze network usage frame by frame, fix problems in the use of network bandwidth, and optimize the performance of your game.
Version 1.10
2
Lumberyard Developer Guide
Core Concepts
•
Contains topics on memory handling, streaming, localization, logging, and console tools.
Before you start programming in Lumberyard, it is important to understand its key concepts: entities and components, EBuses, gems, modules, and slices.
Lumberyard uses a lightweight entity/component model called the component entity system for both game objects and systems. Lumberyard entities are simply an ID and a container of components. They have no functionality associated with them. Lumberyard's component model is granular: It expects each component to provide independent functionality. It expects game objects to be made up of one or more entities with many components attached to each entity. Lumberyard components communicate with each other using a messaging system called EBuses (explained later). Lumberyard expects you to use
EBuses instead of holding references to other entities or their components.
Lumberyard’s components have a simple lifecycle. When an entity is activated, it calls
Activate()
on all of its components. When the entity is deactivated, it calls
Deactivate()
on all of its components.
In the
Activate()
function a component sets itself up, connects to EBuses, and allocates resources or requests assets. In the
Deactivate()
function, a component should release all resources and disconnect from all EBuses. Components should be completely dormant after deactivation, and they should be in more or less the same state that they are in after
Init()
is called. The
Init()
function is only called once and allows a component to initialize its internal state. Note that a component can be activated and deactivated many times before it is deleted. For example, it might be deactivated temporarily while it is being streamed out.
The remaining API operations of a component should be established by the EBus that it implements.
Components can depend on services. Such services usually have a one-to-one relationship with EBuses.
If a component declares that it depends on (requires) a service, any entity that uses the component must also contain a component that provides the required services.
Components are always activated in order of their dependency. For this reason, a component can always assume that the services that it requires are available when the component is activated.
Entities are never allowed to be in a state in which one of their component dependencies is missing, even during authoring. In Lumberyard's editing tools, this means that components whose dependencies are missing are actually removed from the entity and stored in a temporary list. When all of the component's dependencies become available, the component is restored to the entity.
For more information about entities and components, see Programmer's Guide to Entities and
.
EBuses are Lumberyard's general-purpose messaging system. They dispatch notifications and receive requests.
Components commonly use EBuses in two ways: to dispatch events from a notification
bus or to handle requests using a request
bus. Some components provide one type of bus, and some components provide both types. You use the EBus class for both EBus types. Some components do not provide an
EBus at all.
Version 1.10
3
Lumberyard Developer Guide
Gems and AZ Modules
To interact with the engine or other components in Lumberyard, include the component or system's
EBus or API header in your code. Then make calls to the exposed EBuses. With this approach you can replace enginelevel system APIs with implementations that you define in a gem. For example, you could replace Lumberyard's audio system with your own EBus handler. This would give you complete control over audio without having to recompile the engine.
For information about EBuses, see
.
Lumberyard is designed to create applications that are small executables. A Lumberyard application has a simple application class (
AZ::ComponentApplication
). The application class reads a manifest (a gems.json
file) and loads modules that provide functionality for your game. Lumberyard calls these modules gems
. Lumberyard includes a variety of prebuilt gems that add functionality to the game engine, such as VR, cloud connectivity, and a new EmotionFX animation system.
are gems that add AWS cloud-connected functionality to your game. Lumberyard's goal is to have you pick a set of gems that match the requirements of your game and only compile what you need.
When you create a game, your game code and assets go into one or more gems. Each code gem contains
(p. 161) . An AZ module is a collection of C++ code built as a static or dynamic library
(.lib or .dll file) that implements specific initialization functions. The AZ module is the interface that
Lumberyard uses to extract the contents of your gem into the global environment. Each application has a single entity associated with it that is referred to as the
. AZ modules can add components to this entity before it is activated. Components that are added to the system entity are called system components. System components are often singleton/manager-type objects that aggregate or provide resources to game components or other systems. Like other entities, a system entity must have its dependencies present. You can assume that any systems that you depend on are booted and available when your system component is activated.
For more information, see Gems in the Amazon Lumberyard User Guide .
Slices are practical and powerful way to create units of content in Lumberyard and manage them. A slice is a collection of one or more entities. You can instantiate a slice as many times as you require. Many game engines use levels and/or sublevels for their content, but Lumberyard loads content into its engine in the form of slices. Because slices can inherit from each other and be nested, they are powerful tools for managing content.
Like most systems that use prefabs or archetypes, you can use inheritance to override properties in
Lumberyard. However, you can use Lumberyard's slices to add or remove components or even entire entity hierarchies.
For more information, see
Slices and Dynamic Slices (p. 488)
.
Version 1.10
4
Lumberyard Developer Guide
AI System Concepts
This section describes the AI system. It includes a general overview of key concepts, describes system components, and provides an AI scripting manual.
This section includes the following topics:
•
•
•
AI Tactical Point System (p. 22)
•
•
•
•
•
Key features of the AI system include the following:
Navigation
• Navigation with little or no assistance from the designers
• Multi-layer navigation (flying, swimming, zero-gravity) or simple 2D navigation
• Smart objects for special navigation and interactions
Individual AI
• Easy-to-use static and dynamic covers (such as behind movable vehicles)
• Dynamic tactical points (such as cover points, ambush points, patrol waypoints)
• Behavior trees, to select behaviors based on values of Boolean variables
• Customizable perception (such as vision, sound, memory, sixth sense)
Group and Global AI
• Group behavior trees, to define group tactics
Version 1.10
5
Lumberyard Developer Guide
AI System Overview
• Formations, to move AI characters in some orderly fashion
• Factions (such as friends, neutrals, enemies)
• Visual flow graphs of game logic, with macro-nodes for reused sub-flow graphs
MMO-ready
• Support for streaming big maps
User-friendly
• Visual AI debugger to log signals, behavior changes, goal changes, user comments
• Behavior tree visual editor
• Visual flow graph editor and debugger (with visual flow propagation and break points)
This section includes the following topics:
•
•
•
•
•
AI C++ Class Hierarchy (p. 18)
•
AI System Concept Examples (p. 18)
This section outlines basic concepts related to the AI system.
• Default navigation system
• Triangulation
• 2D terrain-based navigation
• Uses cylindrical objects (such as trees) and forbidden areas
• Navigation modifiers
• Human waypoints – Need to be place manually but connections can be generated automatically
• Flight – Information about navigable volumes for flying entities
• Volume – General volume navigation, such as for oceans
• Multi-layer navigation system
• Smart object system: allows AI agents to move in special ways
• AI territories & waves
• Control number of active AI agents (through flow graph logic)
• Activate, deactivate, and spawn all AI agents assigned to a territory using a single FG node
• AI waves can be attached to AI territories and allow independent AI activations
• AI waves automatically handle entity pool issues for assigned AI agents, such as loading/unloading
In general, a search is time-sliced to use 0.5 ms per AI frame (configured using the console variable ai_PathfinderUpdateTime
). Options for pathfinding techniques include high priority, straight, and partial. Updates for human waypoints are heavy but time-sliced. The navigation graph is optimized but
Version 1.10
6
Lumberyard Developer Guide
AI System Overview needs memory. Navigation data is generated offline in Editor. With multi-layer navigation, the navigation mesh is regenerated when the designer modifies the map.
• Behavior selection system – Uses behavior trees to select AI behaviors
• Cover system – Provides AI agents with static and dynamic covers
• Smart object system – Allows AI agents to interact with their environment
• Interest system – Allows AI agents to perform intelligent actions when not alerted
• Tactical point system (TPS) – Allows AI agents to ask intelligent questions about their environment
(such as where to hide or where to attack)
• Faction system – Determines levels of hostility between AI agents
• Group coordination system – Uses coordination selection trees to select group behaviors
• Formation system – Allows AI agents to move in formations
• Cluster detector – detects clusters of points in space and subdivides them into separate groupings that satisfy specific properties (using a modified K-mean algorithm); used with AISquadManager to group different AI agents into dynamic squads
• Signals – To trigger events and/or change behaviors
• Perception system
• Perception handler (legacy, usually per game)
• Target track system – Uses configurable ADSR envelopes to represent incoming stimuli
• Communication system – Allows AI agents to play sound/voice/animation events
The design and development environment includes the following components:
• Game object model – Entity, movement controller, extensions
• Actor & vehicle system – Health, camera, IK, weapons, animation, etc.
• Flow graph – Visual definition of game logic
• AI debug renderer – HUD, geometric primitives, text labels, graphs, etc.
• Editor
• AI entities – Properties, flow graphs, scripts
• Entity archetypes – Templates for properties of individual AI agents
• AI shapes – AI territories, AI paths, forbidden areas
• Navigation – Navigation modifiers used instead of triangulation
• Cover surfaces – CoverSurface anchors to indicate where cover should be
• Visual AI debugger – Recording AI signals, active behaviors, goals, stimuli, etc.
• Scripting with Lua
• Entity definitions (including entity flow graph nodes)
• AI behavior definitions
Version 1.10
7
Lumberyard Developer Guide
AI System Overview
• Group behavior definitions
• Library or shared Lua code (game rules, basic entities)
• Blackboards to share information globally or among groups
• Examples of AI functionality available in Lua:
• AI.Signal
• AI.FindObjectOfType
• AI.GetAttentionTargetType (Visual, Memory, Sound, None)
• AI.GetAttentionTargetAIType (Actor, Grenade, Car, etc.)
• AI.GetRefPointPosition
• AI.DistanceToGenericShape
• AI.SetBehaviorVariable (to change behavior)
• AI.CanMelee
• AI.RecComment (make comment for Visual AI Debugger
• Scripting with XML
• Behavior/coordination trees
• AI communications
• Items (e.g., weapons)
• Entity system
• Spatial queries – GetPhysicalEntitiesInBox()
• AI agents and vehicles are entities in the Entity system
• To spawn an entity, its Entity class is required – Can be defined either using the
.ent
file in
Game
\Entities
OR through a C++ call to RegisterFactory() in game code
• An entity pool can be used to limit the number of active AI agents per each specified Entity class.
• AI Debugger and AI Debug Draw
• Use AI Debugger to track multiple features, including active behavior, signal received, attention target, comments, etc.
• ai_DebugDraw
• 1 – Basic info on AI agents (selected by ai_DrawAgentStats
)
• 74 – All of the navigation graph (can be slow)
• 79 – Parts of the navigation graph around the player
• ai_statsTarget <AI name>
– Detailed info for the specified AI
• ai_DebugTargetTracksAgent <AI name>
– Perception information on the specified AI
• ai_Recorder_Auto
– Record AI activity in Editor game mode for AI Debugger
• ai_DebugTacticalPoints
– Debug TPS queries
• ai_DrawPath <AI name>
– Draw the path of the specified AI (optionally specify "all" for all AI agents)
• ai_DrawPathFollower
– Draw the actual path being followed
• ai_DrawSmartObjects
– Display smart objects and their classes and attributes
• ai_DebugDrawEnabledActors
– List currently enabled AI agents.
• AI update is called every frame, but are fully updated only at ~10Hz
• Some AI subsystems use independent time-slicing (pathfinding, tactical point, dynamic waypoints updating, smart object, interest, and dead bodies removal)
• Some services can be called synchronously from game code (such as tactical point system (TPS) queries)
8
Lumberyard Developer Guide
Pathfinding Costs
For agents to behave in a believable way, they need to find paths that are appropriate for their current state. Sometimes these paths will take the most direct route; other times they will be longer paths to maximize use of roads, cover, or other properties of the environment. The current system needs to be extended to support this. The pathfinding system uses A* to find minimal-cost paths.
The cost of a path is given by the sum of the costs of the links that make up that path. Currently the cost traversing a link in the navigation graph is normally simply the physical (3D) length of that link. However, the A* implementation makes it easy for the requester to modify these distance-based costs with simple code changes to extend the current system . For example, the cost of traveling between two road nodes can be scaled by a factor of 0.1 so that road-traveling agents have a strong preference for finding roadbased paths.
The cost of a path link connecting two graph nodes should be determined by two sets of properties:
• Link properties, including the path's length.
• Pathfinding agent properties in relation to link properties. For example, a stealthy agent might evaluate a link passing through trees as a lower cost-per-unit-length than one passing along a road.
However, the same agent might reach a different conclusion when leading a convoy containing vehicles.
In general, the cost of a link is determined by the product of these two factors: the link-length multiplied by a relative cost-per-unit-length. The latter is what needs to be determined.
We want to use the same navigation graph for different kinds of agents. This means that link cost should be calculated at run time by combining the inherent link properties with the agent properties.
Link properties
Associate these properties with each link:
Link.Length
Length of the link (in meters).
Link.Resistance
The link's resistance to traversal. A road would be close to 0, off-road would be larger, water deep enough to require swimming might be close to 1.
Link.Exposure
How exposed the link is. Trees and dense vegetation would be close to 0, low vegetation would be larger, and a road/open space would be close to 1.
Link.DeepWaterFraction
Fraction of the link that contains deep water (e.g., > 1.5m).
Link.DestinationDanger
Additional "danger value" associated with the destination node. A dead body might be 1. This value can be stored in the destination node itself to save memory.
Agent properties
Associate these properties with each agent (normally set when the agent is created):
Version 1.10
9
Lumberyard Developer Guide
Pathfinding Costs
Agent.CanTraverseTriangular
True/false indicator determining if the agent can traverse triangular nodes.
Agent.CanTraverseWaypoint
True/false indicator determining if the agent can traverse waypoint nodes.
Associate these properties with an agent if relevant for the link type:
Agent.CanSwim
True/false indicator determining if the agent can swim.
Pathfinder request properties
Associate these properties with each agent pathfinder request:
Agent.TriangularResistanceFactor
Extra link cost factor when the link is of type Triangular and its resistance is 1.
Agent.WaypointResistanceFactor
Extra link cost factor when the link is of type Waypoint and its resistance is 1.
Agent.RoadResistanceFactor
Extra link cost factor when the link is of type Road and its resistance is 1.
Associate these properties with an agent pathfinder request if relevant for the link type (note: if a path link has different start/end node types, the result is obtained by averaging):
Agent.SwimResistanceFactor
Extra link cost factor when the link deep water fraction is 1.
Agent.ExposureFactor
Extra link cost factor when the link's exposure is 1.
Agent.DangerCost
Extra link cost when the link danger value is 1.
All link properties, except for Link.DestinationDanger, are calculated when the triangulation is generated.
Link.DestinationDanger is initially set to 0 and then calculated as the game runs. For example, whenever a character dies, each link going into the death node will have its DestinationdangerCost incremented by
1. This will cause an agent with Agent.DangerCost = 100 to prefer paths up to 100m longer (assuming no other path cost differences) in order to avoid this death node. These link modifications need to be serialized to support load/save.
In addition, extra costs can be calculated at run time. For example, an extra cost associated with exposure could be added when an agent wishes to find a path that avoids the player; this can be done by using raycasts in the A* callback that calculates costs.
When determining pathfinding costs, there are two problems that need to be solved:
• How should the link properties be calculated?
• How should the link and agent properties be combined to give a numerical cost for traversing each graph link?
Version 1.10
10
Lumberyard Developer Guide
Pathfinding Costs
Keep in mind that link properties represent the average nature of the environment over the length of the link. If the region has not been triangulated reasonably finely, this may negatively impact the quality of pathfinding results. If the impact is significant, it may be necessary to add additional triangulation points.
An additional issue to consider: should pathfinding differentiate between variable visibility conditions, such as night vs. day or fog vs. clear weather? This would involve splitting the link exposure into terms derived from physical cover and shadow cover. Given the number of links involved, adding too much information of this type to each link should be considered carefully. A simpler solution might be to have stealthy agents be less likely to request a stealthy path in these conditions, or to set the agent's
ExposureFactor lower.
Calculating link properties
Because link resistance is only dependant on the actual type of nodes involved in the link, it can be stored in a lookup table. Here's an example set of resistance values for each node type:
Node type
Triangular-no-water
Triangular-water
Waypoint
Road
Flight/Volume
Resistance
0
0
0.5
1.0
0.6
Note
• Consider adding a separate resistance for Flight/Volume in underwater terrain.
• For links between nodes of different types, the resistance values can be averaged.
The Link.Exposure value, which is stored in the link, is determined by the environment properties sampled over the length of the link. For triangular, waypoint and volume navigation regions, this can be done by firing rays from points along the link. (This is done by using
IPhysicalWorld::RayWorldIntersection and checking for HIT_COVER | HIT_SOFT_COVER with
COVER_OBJECT_TYPES.) It does not make sense to try to get a really accurate value, because in practice the beautified path will not follow the link directly.
Combining link and agent properties
Link cost must account for intersections between link properties and agent properties. For example: if a link is marked as containing deep water and the agent cannot swim, the link should be treated as impassable.
A factor representing the extra costs associated with travel resistance and exposure will be calculated, and the total link cost should be set as follows:
Cost = Link.DestinationDanger * Agent.DangerCost + (1 + Factor) * Link.Length where
Version 1.10
11
Lumberyard Developer Guide
Sensory Models
Factor = Agent.[link-type]ResistanceFactor * Link. [link-type]Resistance +
Agent.ExposureFactor * Link.Exposure
Consider this scenario: with no exposure/destination costs, and assuming that road links have
Link.Resistance {{0}} while off-road links have Link.Resistance {{0.5}}, then in order to make road travel ten times more attractive than off-road (such as if the agent is a car), the agent could have
Agent.TriangularResistanceFactor set to {{(10-1)/0.5}} (or 18) and Agent.RoadResistanceFactor set to 0.
If the agent is a human character that always moves at about the same speed whether or not it is on or off a road, then it could have both Agent.TriangularResistanceFactor and Agent.RoadResistanceFactor set to 0.
Assuming the agent can traverse deep water or is not affected by water (such as a hovercraft),
Agent.SwimResistanceFactor could be set to 0. For a human agent, this factor might be set to a value as high as 3.0, so that the agent will take significant detours to avoid swimming across a river.
This topic describes the modelling and principal operation of the sensors implemented in the
Lumberyard AI system. These include the visual sensors, sound sensors, and a general-purpose signalling mechanism.
Sensory information is processed during a full update of each enemy (the actual time that a sensory event was received is asynchronous). These sensors are the only interface the enemy has with the outside world, and provide the data that the enemy will use to assess their situation and select potential targets.
All sensors are completely configurable, and they can be turned on/off at run-time for any individual enemy.
The visual sensory model is the heart of the AI system. It is an enemy's most important sense. The model is designed to simulate vision as realistically as possible, while still maintaining a low execution cost, using a combination of compromises and optimizations.
During a full update for an individual enemy, the system traverses all potential targets from the enemy’s point of view and runs each one through a visibility determination routine. All targets that survive this filtering procedure are placed in a visibility list that is maintained until the next full update. For a target to persist as "visible" it must pass the visibility test in each full update. Targets that change from visible to not visible during an update are moved to a memory targets list. If a previously visible target becomes visible again, it is moved from the memory target list back to the visibility list. Memory targets have an expiration time to simulate the enemy "forgetting" the target; this time interval is determined by several factors, including the threat index of the target and the length of time it was visible. Visible targets are given the highest priority and will become the current attention target even if there is another target with a higher threat index. This approach simulates the natural tendency of humans to act based on what they see faster than on what they remember (or hear).
The visibility determination routine determines whether a target is considered visible to an enemy. It is run against each of the enemy's potential targets during a full update.
Identifying Targets
Visibility determination can be very CPU intensive; to mitigate this cost, only potential targets are evaluated for visibility. There is a mechanism to register any AI object as an object that should be
Version 1.10
12
Lumberyard Developer Guide
Sensory Models included in the visibility determination (including user-defined objects). This includes objects such as the grenades in Lumberyard, flashlights, etc. There are also special objects called attributes, which will be discussed in more detail later in this topic.
To be considered a potential target, an AI object must be:
• currently active
• of a different species than the enemy (enemies don't need to keep track of members of their own team)
In addition, the visibility determination test is performed automatically against the player, even if the player is of the same species as the enemy. This rule ensures that the player is accurately specified as an object type and is always taken into account when checking visibility.
The game developer can also designate certain AI object types for visibility determination. These userdefined types are added to a list maintained by the AI system identifying object types to be included in the visibility check. Objects can be freely added to and removed from this list, even from script. To include an object in the list, specify an assessment multiplier to the desired object type. For example, refer to the file aiconfig.lua
, which can be found in the
/scripts
directory. For more about assessment multipliers, see the topics on threat assessment.
Checking Visibility
Each potential target identified is evaluated for visibility using a series of tests. In situations where the player is facing a single species, no visibility determination is performed between AI enemy objects, only against the player.Key measures determining visibility include:
Sight-range test
This check is done first, as it is fast and cheap to filter out all AI objects that are outside the enemy's sight range. This is done by comparing the distance between enemy and target against the enemy's sight range value.
enemy sight range
Floating point value that determines how far the enemy can see (in meters); the value represents the radius of a sphere with the enemy at the center.
Field-of-view test
Objects that are inside the enemy's sight range sphere are then checked for whether they are also inside the enemy's field of view (FOV).
enemy field of view
Floating point value that determines the angle of the enemy's visibility cone (in degrees); the cone's tip is at the enemy's head and extends outward in the direction the enemy is facing.
The FOV is the angle that determines how far the enemy can see to the left and to the right of his current forward orientation (that is, the scope of his peripheral vision). For example, an FOV of 180 degrees means that the enemy can see everything which is 90 degrees or less to the left and 90 degrees or less to the right of the direction in which he is currently facing. An FOV of 90 degrees means that he can see 45 degrees or less to the left and 45 degrees to the right of his current forward orientation.
The FOV check is performed using a simple dot product between the enemy's orientation vector and the vector created as the difference between the positions of the potential target and the enemy. The resulting scalar is then compared to the value of the FOV. Note that by using a conical shape, FOV is not limited to 2D representations.
Version 1.10
13
Lumberyard Developer Guide
Sensory Models
Physical ray test
Objects that survive the two initial checks are very likely to be seen. The next check is an actual ray trace through the game world, which is an expensive process. Because the low layer of the AI system performs distributed updates over all frames, it is very seldom that a large number of rays needs to be shot per frame. Exceptions include scenes with a high number of objects belonging to different species and huge combat scenes, such as those with more than 20 participants per species.
The visibility physical ray is used to determine whether there are any physical obstacles between the enemy and the target. It originates from the head bone of the enemy character (or if the enemy does not have an animated character, it originates from the entity position – which is often on the ground) and is traced to the head bone of the target (if it has one, otherwise the entity position is used). If this visibility ray hits anything in its path, then the target is considered not visible. If the ray reaches the target without hitting any obstacles, then the target has passed this tests and can be added to the visibility list for this update.
Not all obstacles are the same. The physical ray test distinguishes between hard cover and soft cover obstacles. For more information on how cover type affects enemy behavior, see the section on soft cover later in this topic.
Perception test
This test is for player AI objects only (and other AI objects as defined by the game developer). Once the player has passed all the visibility tests for an enemy, this final test determines whether or not the enemy can see the player object. Each enemy calculates a perception coefficient for the player target, which ultimately describes the likelihood that the enemy can see the target.
perception coefficient (SOM value)
Floating point value (between 0 and 10) that defines how close the enemy is to actually seeing the target.
The perception coefficient is calculated based on a range of factors, including the distance between enemy and target, height of the target, and whether the target is moving. The value must reach the maximum value (currently 10) before it can receive a definite visual stimulus--that is, see the target.
For more details on how a perception value is derived, see the section on calculating perception later in this topic.
The physical ray test also evaluates the surface type of obstacles when determining visibility. The
AI system can discriminate between two types of surfaces: soft cover and hard cover. The primary difference in a physical sense is that game players can pass through soft cover but cannot pass through had cover. Players can hide behind soft cover objects but the visibility determination is slightly “skewed” when a target is behind a soft cover object rather than a hard cover object or just in the open. When determining a target's visibility behind soft cover, the AI system takes into account whether or not the enemy already identified the target as "living" (not a memory, sound or other type of target). If the enemy does not have a living target, then the soft cover is considered equal to hard cover and normal visibility determination is performed. This occurs when the enemy is idle--or when the enemy is looking for the source of a sound but has not yet spotted it.
However, the behavior is slightly different when the enemy already has a target identified. During the physical ray test, if only soft cover is detected between the enemy and their target, then the target will remain visible for short length of time--between 3 and 5 seconds. If the target remains behind soft cover during this time, the enemy will eventually lose the target and place a memory target at the last known position. However, if the target leaves soft cover within this time, then the timer is reset and normal visibility rules are put into effect.
Version 1.10
14
Lumberyard Developer Guide
Sensory Models
This behavior simulates the following example: when a soldier perceives that the target has run inside a bush, they do not immediately forget about it because they can make out the target’s silhouette even inside the bush. But following a target like that is difficult over time, and after a while the soldier will lose track of the target. The same rules apply to covers made of penetrable cover, like wood, but the rationale is a bit different. If a target runs behind a thin wooden wall, the soldier knows that bullets will still pierce the wall, so for a short time the target's position is still known, and the enemy continues to shoot through it. This can make for some really intense situations in a Lumberyard game.
In order for this process to work in a closed and rational system, all surfaces in the game need to be properly physicalized (wood, grass, and glass should be soft cover, while rock, concrete, metal should be hard cover). This is consistently done in Lumberyard.
Unlike visibility between AI agents, visibility of player objects to enemy AI agents in Lumberyard is not an on/off switch. This added layer of complexity is designed to allow for variations in game playing style
(such as action versus stealth). Perception allows the player to make a certain number of mistakes and still be able to recover from them. (This is one of the reasons why a player AI object is specifically defined even in the lowest layer of the AI system hierarchy.) It is not used with other AI objects, where “switch” vision is used (that is, the target is visible as soon as a ray can be shot to its position). Note that it is possible to declare some AI objects should also trigger use of a perception coefficient.
An enemy is given a perception coefficient that describes how close the enemy is to actually seeing a particular target. The initial value of the perception coefficient is 0 and increases or decreases based on a defined set of rules. If a player target passes all prior visibility tests, the enemy begins applies the perception coefficient. Once the maximum value has been reached, the player target is visible to the enemy. This statement contains several corollaries:
• Each enemy has a perception coefficient for each player target it is processing.
• Each enemy will receive notification that the player target is visible only after the perception coefficient reaches maximum value.
• The perception coefficient of two different enemies are unrelated, even for the same player target.
• There is no game-level perception coefficient (that is, a value that determines how any enemy perceives a player target), although this information could be derived by statistics.
When an enemy starts receiving notification that a player target is passing the visibility determination routine, it begins calculating the perception coefficient. This is done by evaluating the following factors, all of which impact the rate at which the coefficient increases. Keep in mind that a player target must still pass all other phases of the visibility determination routine before the perception coefficient is applied.
Distance
Distance between the enemy and the player target has the highest influence on perception. The closer the player target is to the enemy, the faster the coefficient rises, while greater distances cause the coefficient to rise slower. The increase function is a basic quadratic function. At distances very close to the enemy, the time to reach maximum perception is almost non-existent and the target is instantly seen. In contrast, a player target may be able to move more freely along the boundaries of the enemy's sight range, as the perception value rises more slowly.
Height from ground
This factor takes into account the player target’s distance above the ground. The rationale for this behavior is that a prone target is much harder to spot than one who is standing upright. The AI system measures the distance of the target from the ground based on the “eye height” property of an AI object. This property is set when the AI object is initialized, and can be changed at any time during execution of the game. If enemies and players are represented in the game by animated
Version 1.10
15
Lumberyard Developer Guide
Sensory Models characters, the eye height is calculated using the actual height of the character's head bone. This factor influences the rate of increase in the perception coefficient as follows: if the player target has a height above ground of less than one meter, the increase due to distance is lowered by 50%.
Target motion
The perception coefficient is affected by whether or not the player target is moving. Movement attracts attention, while stationary targets are harder to spot. This factor influences the rate of increase in the perception coefficient as follows: if the player target is standing still, the increase due to other factors is lowered by additional 50%.
Artificial modifiers
Additional values can define how fast the perception coefficient increases. Some affect all enemies in the game world, while some affect only particular targets. An example of a modifier that affects all enemies is the console variable ai_SOM_SPEED
. Its default value varies depending on a game's difficulty level, but it provides a constant multiplier that is applied on top of all other calculations, and it applies to all enemies. In contrast, it is possible to set a custom multiplier for a specified object type that is used only for certain player targets; however, this setting is limited to the lowest level of the AI system and is not available for tweaking.
The effect of perception is cumulative while the target is considered visible to the enemy. A floating point value is calculated based on the factors described above, and each time the enemy fully updated, this value is added to the perception coefficient (along with an updated visibility determination). So, for example, a player target that is within the enemy's range of sight might remain unperceived by the enemy significantly longer if they are crouching and motionless.
At the same time, a non-zero perception coefficient can fall back to zero over time if value is not increased constantly with each full update. For example, a player target might become visible for a few seconds, raise the coefficient up to 5, and then break visual contact. In this scenario, the coefficient will drop slowly to zero. This scenario was implemented to reward players that tactically advance and then pause before continuing; players can wait for the coefficient to drop to zero before continuing to sneak.
A statistical overview of the perception coefficients of all enemies for a player is used for the HUD stealth-o-meter, showing as a small gauge to the left and right of the radar circle in the HUD. It represents the highest perception coefficient of the player across all enemies that currently perceive him.
In effect, it shows the perception coefficient of the one enemy that is most likely to see the player. so, a full stealth-o-meter does not mean that all enemies see the player; it means that there is at least one enemy that can. An empty stealth-o-meter means that currently no enemy can see the player.
An attribute object is not a full AI object; instead, it is more of a special helper that can be attributed to an existing AI object. The attribute is a special class of AI object, specifically defined at the lowest level in the AI system. Every attribute object must have a principal object associated with it. The principal object can be any type of an object (including puppet, vehicle, player, etc,.) but cannot be an attribute.
Attributes can impact visibility determination. When an enemy determines that it sees an attribute object, the system will switch the attribute with the principal object before adding it into the visibility list of the enemy. Thus, an enemy who sees an attribute will believe it is seeing the principal object attached to the attribute.
Essentially, attributes are a systematic way of connecting certain events to a single target. For example, a player switches on a flashlight and the beam hits a nearby wall. The light hitting the wall creates an attribute object associated with the principal object, which is the player. In this scenario, the player is hidden, but because an enemy sees the attribute object (the light on the wall), it will in fact "see" the player. The rationale is that enemies have enough intelligence to interpolate the origin of the light ray and thus know the player’s position.
Version 1.10
16
Lumberyard Developer Guide
Flight
This feature is also used with regard to rocks, grenades, rockets etc. It can be extended to add more features to a game; for example, a target might leave footprints on the ground that evaporate over time.
The footprints spawn attribute objects, which enable any enemy who sees them to perceive the location of the target who left them. Another application might be blood tracks.
To ensure that attribute objects are included in the visibility determination, they must have an assessment multiplier set. Refer to aiconfig.lua
in the
Scripts\AI
directory to see where the AI system defines the multiplier for attribute objects.
Use these archetypes and flow nodes in conjunction with entities to control flying vehicles. See these archetypes in the characters archetype library:
•
CELL/Helicopter.Regular
•
Ceph/Dropship.Regular
•
Ceph/Gunship.Regular
The following flow nodes to be used with these entities are found under the Helicopter category.
This flow node sets the current path that the flight AI uses.
• When the AI is not in combat mode.
• If the AI is set to loop through the flow node path, the AI tries to go from its current location to the closest point of the path and then follows it to the end. The node outputs indicating that the AI has reached the end of the path is sent once only.
• Without looping, the AI tries to go from its current location to the beginning of the path and then follows it to the end.
• When the AI is in combat mode.
• If the target is visible, the path is used to position the AI in the best location to attack the target. It is also used to navigate between positions within the path.
• If the target is not visible, the path is used as a patrol path. Where possible, it simplifies setup to have paths in combat mode be set to loop.
This flow node enables or disables the AI's ability to position itself within the combat path in order to engage and shoot at its current target. By default, an AI is not in combat mode until it's explicitly allowed to go into combat mode.
• When an AI is in combat mode and has identified a target location, it will try to reposition itself within the current path to a position from which it can engage.
• Any character of an opposing faction is a good candidate for a target.
This flow node enables or disables the ability of the AI to shoot at its current target when in combat mode. By default, an AI is allowed to fire when in combat mode until it's explicitly disabled using this node.
Version 1.10
17
Lumberyard Developer Guide
AI C++ Class Hierarchy
C++ classes for AI objects are structured as follows.
CAIObject
Defines basic AI object properties (entity ID, position, direction, group ID, faction, etc.)
CAIActor
Basic perception and navigation, behavior selection, coordination, blackboard, AI territory awareness,
AI proxy
CAIPlayer
AI system's representation of an actual game player
CPuppet
Aiming, firing, stances, covers, a full-fledged AI agent
CAIVehicle
Vehicle-specific code
This section includes the following topics:
Version 1.10
18
Lumberyard Developer Guide
AI System Concept Examples
•
AI Multi-Layered Navigation (p. 19)
•
Individual AI: Dynamic Covers (p. 19)
•
Individual AI: Tactical Points (p. 19)
•
Group and Global AI: Factions (p. 20)
•
Group and Global AI: Flow Graphs (p. 20)
Useful AI debug draw:
• ai_useMNM=1
• ai_DebugDraw=1
• ai_DebugDrawNavigation=1
• ai_DrawPath=all
• ai_DrawPathFollower=1
Example: CoverSurface and HMMWV
This example shows the use of dynamic covers that are generated offline and adjusted during run time.
Useful AI debug draw:
• ai_DebugDraw=1
• ai_DebugDrawCover=2
• [AI/Physics] is on
Example: A very shy civilian who always wants to hide from the player
• Tactical point system (TPS) query:
AI.RegisterTacticalPointQuery({
Name = "Civilian_HideFromEnemy",
{
Generation =
{
cover_from_attentionTarget_around_puppet = 25
},
Conditions =
{
reachable = true,
},
Weights =
{
distance_from_puppet = -1,
},
},
});
• Useful AI debug draw:
• ai_DebugTacticalPoints=1
Version 1.10
19
Lumberyard Developer Guide
AI Bubbles System
• ai_StatsTarget=Grunt1
• ai_TacticalPointsDebugTime=10
• For more realism, add the following before goalop TacticalPos:
<Speed id="Sprint"/>
Example: AI formations of different factions
Place on a map three grunts of the following factions. Note who is hostile to who.
• grunts
• assassins
• civilians
For example:
<Factions>
<Faction name = "Players">
<Reaction faction- "Grunts" reaction="hostile"/>
<Reaction faction- "Civilians" reaction="friendly"/>
<Reaction faction- "Assassins" reaction="hostile"/>
</Faction>
<Faction name="Civilians default="neutral"/>
...
</Factions>
(see
Game/Scripts/AI/Factions.xml
)
Flow Graph Editor allows non-programmers to build global AI logic visually. Experiment with flow graph debugger features, such as signal propagation highlighting and breakpoints.
The AI Bubbles system collects AI error messages for level designers to address. This system streamlines the debugging process by helping to track down which system(s) are connected to a problem. To use the AI Bubbles system, programmers need to push important messages into the system, which will then provide notification to the level designers when a problem is occurring.
Message include a set of information (agent name, position, etc.) that help the designer to understand that something is wrong in the normal flow. Message notifications can be displayed in any of the following ways:
• Speech bubble over the AI agent
• Error message in the console
Version 1.10
20
Lumberyard Developer Guide
Specifying Notification Display Types
• Blocking Windows message box
Use one of the following ways to specify a display type for error messages:
ai_BubblesSystem
Enables/disables the AI Bubbles System.
ai_BubblesSystemDecayTime
Specifies the number of seconds a speech bubble will remain on screen before the next message can be drawn.
ai_BubblesSystemAlertnessFilter
Specifies which notification types to show to the designer:
• 0 - No notification types
• 1 - Only logs in the console
• 2 - Only bubbles
• 3 - Logs and bubbles
• 4 - Only blocking popups
• 5 - Blocking popups and logs
• 6 - Blocking popups and bubbles
• 7 - All notifications types
ai_BubblesSystemUseDepthTest
Specifies whether or not the notification needs to be occluded by the world geometries.
ai_BubblesSystemFontSize
Specifies the font size for notifications displayed in the 3D world.
In C++, use the method AIQueueBubbleMessage() to define how to display the message notification.
Method signature:
bool AIQueueBubbleMessage(const char* messageName, const IAIObject* pAIObject, const char*
message, uint32 flags);
Parameters: messageName
String describing the message. This is needed to queue the same message error more than once.
(The message can be pushed into the system again when it expires is deleted from the queue.)
Version 1.10
21
Lumberyard Developer Guide
AI Tactical Point System
pAIObject
Pointer to the AI object that is connected to the message.
message flags
Text of the message to be displayed.
Notification type. This parameter can include one or more flags; multiple flags are separated using a pipe (|).
• eBNS_Log
• eBNS_Balloon
• eBNS_BlockingPopup
Example:
AIQueueBubbleMessage("COPStick::Execute PATHFINDER_NOPATH non continuous", pPipeUser, "I
cannot find a path.", eBNS_Log|eBNS_Balloon);
local entityID = System.GetEntityIdByName("Grunt.AlienGrunt1");
AI.QueueBubbleMessage(entityID,"I cannot find a path.");
The Tactical Point System (TPS) provides the AI system with a powerful method of querying an AI agent's environment for places of interest. It includes the GetHidespot functionality and expands on the "hide" goalop.
TPS is a structured query language over sets of points in the AI's world. Using TPS, AI agents can ask intelligent questions about their environment and find relevant types of points, including hidespots, attack points, and navigation waypoints. The TPS language is simple, powerful, and designed to be very readable.
For example, this query requests all points that match the following criteria:
• Generate locations within 7 meters of my current location where I can hide from my attention target.
• Only accept places with excellent cover that I can get to before my attention target can.
• Prefer locations that are closest to me.
hidespots_from_attentionTarget_around_puppet = 7 coverSuperior = true, canReachBefore_the_attentionTarget = true distance_from_puppet = -1
TPS uses a highly efficient method to rank points, keeping expensive operations like raycasts and pathfinding to an absolute minimum. Queries are optimized automatically.
This section includes the following topics:
•
Tactical Point System Overview (p. 23)
Version 1.10
22
Lumberyard Developer Guide
Tactical Point System Overview
•
TPS Query Execution Flow (p. 24)
•
•
•
TPS Query Language Reference (p. 27)
•
Point Generation and Evaluation (p. 30)
•
Integration with the Modular Behavior Tree System (p. 32)
•
Future Plans and Possibilities (p. 32)
Key features of the Tactical Point system (TPS) include:
• Use of a structured query language
• Powerful and quick to change in C++ and Lua
• Query support for a variety of point characteristics, beyond conventional hiding places behind objects:
• Points near entity positions
• Points along terrain features
• Points suggested by designers
• Arbitrary resolutions of nearby points in the open or on terrain
• Query combinations, such as:
• "Find a point somewhere behind me AND to my left, AND not soft cover, AND not including my current spot"
• "Find a point hidden from my attention target AND visible to the companion"
• Preferential weighting, such as:
• Find a point nearest to (or furthest from) a specified entity
• Balance between points near an entity and far from the player
• Prefer points in solid cover over soft cover
• Query fallback options, such as:
• Prioritize good cover nearby; if none exists, go backwards to any soft cover
• Query visualization:
• See which points are acceptable and which are rejected, as well as their relative scores
• See how many expensive tests are being used by a query and on which points
• Automatic query optimization
• Understands the relative expense of individual evaluations comprising queries
• Dynamically sorts points based on potential fitness, according to weighting criteria
• Evaluates the "fittest" points first, in order to minimize the use of expensive tests
• Recognizes when the relative fitness of a point indicates that it can't be beat, in order to further reduce evaluations
• Provides framework for further optimization specific to architecture, level, or locale
In addition to these key feature benefits, this framework offers these advantages from a coding perspective:
• Separates query from action
• Arbitrary queries can be made at any time without changing the agent's state
• Query language is easy to expand
• Easily adapted for time-slicing (and in principle multi-threading):
Version 1.10
23
Lumberyard Developer Guide
TPS Query Execution Flow
• Progression through query is fine-grained
• Progress is tracked as state, so it can be easily paused and resumed
• Provides mechanism for delaying expensive validity tests on generated points until needed
The following steps summarize the definition and execution stages of a TPS query. Note that only stages
3 and 4 have a significant impact on performance.
1. Parse query:
• Parse query strings and values.
• This step is usually performed once and cached.
2. Make query request:
• Query is made using C++, ScriptBind, goalops, etc.
• A query is stateless; it does not imply a movement operation.
3. Generate points:
• Create a set of candidate points.
• Point candidates are based on the query's Generation criteria.
4. Evaluate points (this is by far the most intensive stage):
• Accept or reject points based on Conditions criteria.
• Assign relative scores to points based on Weights criteria.
5. Consider query fallbacks:
• If no point matches the Conditions criteria, consider fallback options.
• Where there is a fallback, return to step 3.
6. Visualize points:
• If visualization is required, draw all points to screen.
• Include point data such as its accepted/rejected status and relative scores.
7. Return results:
• Return one or more points, if any fit the query conditions.
• Each point is returned as a structure that describes the selected point.
There are some optimizations possible that depend on the execution flow. For example, relevant query results can be cached between fallback queries.
These C++ interfaces allow you to use TPS from other C++ code and within goalops. Lua queries are translated through it.
There are two C++ interfaces:
• Internal - For use only within the AI system
• Uses a CTacticalPointQuery object to build queries
• Allows you to create or adapt queries on the fly
• Provides greater access to relevant AI system classes
• External - For use from any module
• Suitable for crossing DLL boundaries
• Simpler, not object-oriented, just as powerful
Version 1.10
24
Lumberyard Developer Guide
TPS Querying with C++
• Uses stored queries for efficiency
In the example below, some parsing is obviously taking place here. This is crucial to the generality of the system.
// Check for shooter near cover using TPS static const char *sQueryName = "CHitMiss::GetAccuracy";
ITacticalPointSystem *pTPS = gEnv->pAISystem->GetTacticalPointSystem(); int iQueryId = pTPS->GetQueryID( sQueryName ); if ( iQueryId == 0 )
{
// Need to create query
iQueryId = pTPS->CreateQueryID( sQueryName );
pTPS->AddToGeneration( iQueryId, "hidespots_from_attentionTarget_around_puppet", 3.0f);
pTPS->AddToWeights( iQueryId, "distance_from_puppet", -1.0f);
} pTPS->Query( iQueryId, CastToIPuppetSafe( pShooter->GetAI() ),vHidePos, bIsValidHidePos );
The following examples and explanations illustrate the use of TPS query syntax. For a more detailed discussion of the TPS query language, see the topic on TPS Query Language Syntax and Semantics.
option.AddToGeneration("hidespots_from_attTarget_around_puppet", 50.0)
This query request is expressed as generation criteria and specifies a float to represent distance. The query is broken up into five words:
• "hidespots" indicates that generated points should positioned behind known cover as is conventional
• "from" and "around" are glue words to aid readability
• "target" specifies the name of the object to hide from
• "puppet" identifies a center location that points will be generated around
• The float value indicates the radial distance, measured from the center location, that defines the area within which points should be generated
Note that no raycasts are performed at this stage. We have here considerable flexibility, for example, how we choose to hide from a player: (1) somewhere near the player, (2) somewhere near us, or (3) somewhere near a friend. We can also specify a completely different target to hide from, such as an imagined player position. By providing flexibility at the point generation stage, we can support more powerful queries and allow users to focus computations in the right areas.
option2.AddToConditions("visible_from_player",true)
This query request is expressed as condition criteria, so we can expect a Boolean result. The query specifies points that are visible to the player, which is curious but perfectly valid. The term "visible" specifies a ray test, with "player" specifying what object to raycast to from a generated point.
option2.AddToConditions("max_coverDensity",3.0)
This query is expressed as a condition, so we can expect a Boolean result. The term "Max" specifies that the resulting value must be compared to the given float value--and be lower than. The term
"coverDensity" identifies this as a density query (measuring the density of things like cover, friendly AI agents, etc.) and specifies measurement of covers.
Version 1.10
25
Lumberyard Developer Guide
TPS Querying with Lua
option1.AddToWeights("distance_from_puppet",-1.0)
This query is expressed as a weight component; the query result will be a value between zero and one
(normalized as required). Boolean queries are allowed to indicate preference (such as primary cover over secondary cover), with return values of 0.0 for false and 1.0 for true.
This query component indicates a preference for points at a certain location relative to an object. The term "distance" identifies this as a distance query, with the given float values specifying the distance amount. The term "puppet" identifies the object to measure the distance from.
In Lua, there are two ways to use the TPS:
• Scriptbinds allow you to use TPS queries from a Lua behavior and have the results returned as a table without any side-effects. This can be useful for higher-level environmental reasoning, such as:
• Choose behaviors based on suitability of the environment (for example, only choose a "sneaker" behavior if there's lots of soft cover available).
• Run final, very specific tests on a short list of points, rather than adding a very obscure query to the
TPS system.
• Enable greater environmental awareness (for example, tell me three good hidespots nearby, so I can glance at them all before I hide).
• With goal pipes, you can use goalops to pick a point and go there, using a predefined TPS table:
• Use a "tacticalpos" goalop, which is equivalent to a previous "hide" goalop.
• Use fallback queries to avoid lists of branches in goalpipes.
• More flexible goalops can be provided to decouple queries from movement.
Both methods define query specifications using the same table structure, as shown in the following example:
Hide_FindSoftNearby =
{
-- Find nearest soft cover hidespot at distance 5-15 meters,
-- biasing strongly towards cover density
{
Generation= { hidespots_from_attentionTarget_around_puppet = 15 },
Conditions= { coverSoft = true,
visible_from_player = false,
max_distance_from_puppet = 15,
min_distance_from_puppet = 5},
Weights = { distance_from_puppet = -1.0,
coverDensity = 2.0},
},
-- Or extend the range to 30 meters and just accept nearest
{
Generation ={ hidespots_from_attentionTarget_around_puppet = 30 },
Weights = { distance_from_puppet = -1.0}
}
}
AI.RegisterTacticalPointQuery( Hide_FindSoftNearby );
Note
Registering a query returns a query ID that then refers to this stored query.
Querying with Scriptbind
Version 1.10
26
Lumberyard Developer Guide
TPS Query Language Reference
The following script runs a query using an existing specification. See comments in
Scriptbind_AI.h
for details.
AI.GetTacticalPoints( entityId, tacPointSpec, pointsTable, nPoints )
Querying with Goalops
The following script runs an existing query. Because queries can have fallbacks built in, branching is usually unnecessary (the branch tests are still supported).
AI.PushGoal("tacticalpos",1, Hide_FindSoftNearby);
There are ways to define a query in both C++ and Lua (and potentially in XML), but the same core syntax is used. This page formally defines the TPS query language, with query components expressed in
Generation, Conditions or Weights, and defines and discusses the query language semantics.
Note
Non-terminal symbols are in bold. Not all of the symbols are implemented, but are shown for illustration.
Generator ::= GenerationQuery '_' 'around' '_' Object
Condition ::= BoolQuery | (Limit '_' RealQuery)
Weight ::= BoolQuery | (Limit '_' RealQuery) | RealQuery
GenerationQuery ::= ( 'hidespots' '_' Glue '_' Object)
| 'grid' | 'indoor'
BoolQuery ::= BoolProperty | (Test '_' Glue '_' Object)
BoolProperty ::= 'coverSoft' | 'coverSuperior' | 'coverInferior' | 'currentlyUsedObject' |
'crossesLineOfFire'
Test ::= 'visible' | 'towards' | 'canReachBefore' | 'reachable'
RealQuery = ::= RealProperty | (Measure '_' Glue '_' Object)
RealProperty ::= 'coverRadius' | 'cameraVisibility' | 'cameraCenter'
Measure ::= 'distance' | 'changeInDistance' | 'distanceInDirection' | 'distanceLeft' |
'directness' | 'dot' | 'objectsDot' | 'hostilesDistance'
Glue ::= 'from' | 'to' | 'at' | 'the'
Limit ::= 'min' | 'max'
Object ::= 'puppet' | 'attentionTarget' | 'referencePoint' | 'player'
| 'currentFormationRef' | 'leader' | 'lastOp'
Note
• "Tunable" denotes that the exact values used should be possible to tweak/tune later.
• "Real" means that it returns a float value (rather than a boolean).
Objects
puppet
AI agent making a query
attentionTarget
Object that is the target of the AI agent's attention
Version 1.10
27
Lumberyard Developer Guide
TPS Query Language Reference
referencePoint
AI agent's point of reference, perspective
player
Human player (chiefly useful for debugging and quick hacks)
Glue
from | to | at | the
Glue words used for readability in a query statement. Each query must have a glue word, but it has not active function and the parser doesn't distinguish between them. Readability is encouraged to aid in debugging and long-term maintenance.
Generation
Hidespot
Individual point just behind a potential cover object with respect to a "from" object (as in "hide from object"). There is typically one point per cover object. Use of this symbol should generate multiple points behind large cover objects and cope with irregularly shaped and dynamic objects.
Around
A glue word with special meaning. This word should be followed by the name of an object around which to center the generation radius.
Conditions/Weight Properties (use no object)
These properties relate to a specified point:
coverSoft
Boolean property, value is true if the specified point is a hidespot using soft cover.
coverSuperior
Boolean property, value is true if the specified point is a hidespot using superior cover.
coverInferior
Boolean property, value is true if the specified point is a hidespot using inferior cover.
currentlyUsedObject
Boolean property, value is true if the specified point is related to an object the puppet is already using (such as the puppet's current hide object).
coverRadius
Real (float) property, representing the approximate radius of the cover object associated with the specified point, if any, or 0.0 otherwise. When used for condition tests, returns an absolute value in meters. When used as a weight, returns a normalized value, mapping the range [0.0-5.0m] to
[0.0-1.0]. (Tunable)
coverDensity
Real property, representing the number of potential hidespots that are close by to the specified point. When used for condition tests, returns an absolute value representing an estimate of the number of hidespots per square meter using a 5m radius sample. When used as a weight, returns a normalized value, mapping the range (0.0-1.0) to [0.0-1.0] (hidespots per square meter). (Tunable)
Version 1.10
28
Lumberyard Developer Guide
TPS Query Language Reference
Conditions/Weight Test/Measures (require object)
These properties relate to a specified object, such as distance_to_attentionTarget or visible_from_referencePoint.
distance
Real (float) measure, representing the straight-line distance from a point to the specified object.
When used for condition tests, returns an absolute value in meters. When used as a weight, returns a normalized value, mapping the range [0.0-50.0m] to [0.0-1.0]. (tunable)
changeInDistance
Real (float) measure representing how much closer the puppet will be to the specified object if it moves to a certain point. Takes the distance to the specified object from the current location and subtracts it from the distance to the object from the proposed new location. When used for condition tests, returns an absolute value in meters. When used as a weight, returns a normalized value, mapping the range [0.0-50.0m] to [0.0-1.0]. (tunable)
distanceInDirection
Real (float) measure representing the distance of the point in the direction of the specified object.
Takes the dot product of the vector from the puppet to the point and the normalized vector from the puppet to the object. When used for tests, returns an absolute value in meters. When used as a weight, returns a normalized value, mapping the range [0.0-50.0m] to [0.0-1.0]. (tunable)
directness
Real (float) measure representing the degree to which a move to a certain point approaches the specified object. Takes the difference in distance to the object (changeInDistance) and divides it by the distance from the puppet to the point. Always uses the range [-1.0 to 1.0], where 1.0 is a perfectly direct course and negative values indicate movement further away from the object.
Limits
min | max
Limits can be used to test a real value in order to product a Boolean. Useful for conditions that can also be used as coarse Weights; for example, the condition MAX_DISTANCE = 10 can be used to express that a distance of less than 10 is preferable, but without favoring nearer points in a more general way.
There are a few different ways queries can fail, and it's important to understand how each case is handled.
•
No points matched the conditions of the query.
This is a valid result, not a failure; the AI can move to fallback queries or try a different behavior.
•
The query does not make sense in the context of an individual point.
Sometimes a query doesn't make sense for a certain point or at a certain time. In this case, the query tries to return the "least surprising" results. For example: a query about a point generated in the open asks "is this soft cover?"
The result will be "false", because this isn't any kind of cover. Query names should be chosen carefully to help avoid potential confusion.
•
The query does not make sense in the context of the puppet, at this time and for any point.
As with the point context issue, the query tries to return the "least surprising" results. For example: a query about a puppet asks "am I visible to my attention target?" when the puppet doesn't have an attention target. The query could return false, but it would disqualify every point. This case will usually
Version 1.10
29
Lumberyard Developer Guide
Point Generation and Evaluation indicate a code error--the puppet should have an attention target at this point, but does not. Note:
This situation can cause a similar problem in the point generation phase, with a query like "generate hidespots from my attention target". both of these situations are flagged as code errors.
•
The query failed due to a code error.
You can test for errors in the TPS queries and raise them there also. For example, a query or combination hasn't been fully implemented yet or is being used as a kind of assert to test variables.
An AI agent makes a TPS point generation query in order to generate a set of points for consideration.
Once generated, each point can be evaluated based on its position and any available metadata.
Input
The following information are required to generate points:
• Specific criteria defining the types of points to generate.
• A central or focal position around which to generate points. This might be the current position of the puppet itself, an attention target, or some other given position.
• For some queries, the position of a secondary object, such as a target to hide from.
It is possible to specify multiple sets of point generation criteria. For example, a query might request point generation around both the puppet and an attention target.
Processing
Based on the input, TPS begins generating points to evaluate. All points fall into two main types:
• Hidepoints. These are generated based on the following calculations:
• Hideable objects
• Generated only if a position to hide from was provided
• Hidepoints represent final positions, for example calculating positions behind cover
• Using the object and delaying finding an actual point is a possibility
• Open points. These are generated based on query specifications and the following calculations:
• Usually on terrain, but may be on surfaces, etc.
• Resolution/pattern (such as triangular with 1-meter spacing)
• Potentially may perform more general sampling to find an exact point, but an initial resolution is still required
• Radial/even distributions
Output
The result of a point generation query is a list of point objects. Each point object includes the point's position and available metadata, such as any associated hide objects.
Once a generation query generates a set of points, they can be evaluated. Point evaluation tries to establish the "fitness" of each point, that is, how well the point matches the specified criteria. The goal is to choose either one good point, or the best
N
number of good points.
Version 1.10
30
Lumberyard Developer Guide
Point Generation and Evaluation
Input
The following elements are required to evaluate points:
• List of candidate points from the point generator
• Point evaluation criteria:
• Boolean – Condition criteria used to include or exclude a point independently of any other points
• Weight – Criteria that, combined, give a measure of fitness relative to other points (those included by the boolean criteria)
Processing
The primary goal is to find an adequately good point as quickly as possible. Often, "adequately good" also means "the best", but there is a lot of potential for optimization if a user-specified degree of uncertainty is allowed.
The order of evaluation has a non-trivial and crucial impact on query efficiency. As a result, evaluation uses the following strategy to minimize the number of expensive operations:
1. Cheap booleans, with an expense on the order of one function call or some vector arithmetic. These allow the system to completely discount many points without significant cost. For example:
Is this point a primary or secondary hidespot? Is this point less than 5 meters from the target?
2. Cheap weights, with an expense similar to cheap booleans. These allow the system to gauge the likelihood that a given point will eventually be the optimal choice; by focussing on points with a high likelihood, the number of expensive tests can be reduced. For example:
closeness_to_player * 3 + leftness * 2
.
3. Expensive booleans, approximately 100 times costlier. These are yes/no questions that will require expensive calculations to answer, but further eliminate points from contention. For example, the question
Is this point visible by the player?
requires an expensive ray test.
4. Expensive weights, with an expense similar to expensive booleans. These help to rank the remaining points. For example:
nearby_hidepoint_density * 2
Algorithmic Details
It turns out that the system can go further with this by interleaving the final two steps and making evaluation order completely dynamic. Unlike conditions (booleans), weights don't explicitly discount points from further evaluation. However, by tracking the relative "fitness" of points during evaluation, we can still employ weights to dramatically reduce evaluations by employing two basic principles:
• Evaluate points in order of their maximum possible fitness, to fully evaluate the optimal point as quickly as possible.
• If, based on the initial weight evaluation, a point can be established as better than any other point, then immediately finish evaluating it against the remaining conditions. If the point passes all condition criteria, then it is the optimal point and no other points need to be evaluated. In addition, this point does not need to be evaluated on any remaining weights.
This implementation is based on a heap structure that orders points according to their maximum possible fitness and tracks the evaluation progress of each point separately. Each weight evaluation collapses some of the uncertainty around the point, adjusting both the minimum and maximum possible fitness. If the weight evaluation scored highly, the maximum will decrease a little and the minimum increase a lot; if it scored badly, the maximum will decrease a lot and the minimum increase a little.
In each iteration, the next most expensive evaluation is done on the point at the top of the heap, after which the point is re-sort into place if necessary. If all evaluations on a point have been completed and
Version 1.10
31
Lumberyard Developer Guide
Integration with the Modular Behavior Tree System it still has the maximum possible fitness, then it must be the optimal point. This approach tends towards evaluation of the optimal point with relatively few evaluations on all other points.
Output
The result of point generation evaluation is a single point or group of
N
number of points, and the opportunity to request all metadata leading to its selection. As a result, behaviors can adapt their style to reflect the nature the hidepoint received.
From inside the Modular Behavior Tree (MBT), the
<QueryTPS>
node can be used to call pre-defined TPS queries by name. The
<QueryTPS>
node will return either success or failure.
The most common usage pattern involving the
<QueryTPS>
node is to use it in conjunction with the
<Move>
node inside a
<Sequence>
to determine the status of a specified position. The example below illustrates a call to a pre-defined TPS query called
SDKGrunt_TargetPositionOnNavMesh
, with the expected inputs. If the query succeeds, the AI agent will move to the queried position.
<Sequence>
<QueryTPS name="SDKGrunt_TargetPositionOnNavMesh" register="RefPoint"/>
<Move to="RefPoint" speed="Run" stance="Alerted" fireMode="Aim" avoidDangers="0"/>
</Sequence>
The definition of the pre-defined query
SDKGrunt_TargetPositionOnNavMesh
is as follows.
AI.RegisterTacticalPointQuery({
Name = "SDKGrunt_TargetPositionOnNavMesh",
{
Generation =
{
pointsInNavigationMesh_around_attentionTarget = 20.0
},
Conditions =
{
},
Weights =
{
distance_to_attentionTarget = -1.0
},
},
});
The following topics represent potential areas of development for TPS.
Higher-level environmental reasoning
One possible application of TPS: rather than simply using TPS to choose a point and move to it, there is the potential for some nice environmental deductions based on results.
For example: The player runs around a corner, followed by an AI puppet. When the AI puppet turns the corner, the player is no longer visible. The puppet queries TPS for places it would choose to hide from itself, with the following possible results.
• TPS returns that 1 hidepoint is much better than any other. This is because there's a single large box in the middle of an empty room. The AI puppet assumes the player is there and charges straight at the box, firing.
Version 1.10
32
Lumberyard Developer Guide
Navigation Q & A
• TPS returns that there are several good hiding places. This is because there's a stand of good cover trees. All the hidepoints are stored in a group blackboard, and the AI puppet (or a group) can approach each spot in turn to discover the player.
This scenario is workable with some extra code, and much easier when built upon TPS.
Sampling methods
When generating points in the open, generate points in a grid or radially around objects and treat each point individually. This supports a basic sampling method. Where an area must be sampled, some kind of coherency in the evaluation functions can be assumed, and so could use some adaptive sampling approaches instead.
Dynamic cost evaluation
A crucial aspect of optimizing TPS involves adjusting the relative expense function of queries. The costs of evaluations will vary across platforms, levels, and even locations within levels, and will change over time as the code changes. It is critical to make sure that the evaluation order is correct, to prevent more expensive evaluations from being favored over cheaper ones. The need to profile the evaluation function in all these difference circumstances suggests an automatic profiling solution at run-time.
In addition, the relative weighting of weight criteria should also be considered; a cheap query may not be worth doing first if it only contributes 10% of the final fitness value, while an expensive query that contributes 90% may actually save many other evaluations.
Relaxing the optimality constraint
When evaluating points the maximum and minimum potential fitness is always known at every stage; this provides the error bounds, or a relative measure of uncertainty about the point.
It may make sense to relax the optimality constraint and accept a point when it becomes clear that no other point could be significantly better. For example, the minimum potential fitness of a point may be less than 5% lower than the maximum potential fitness of the next best point. This information could be used to stop evaluation early and yield a further performance saving.
Q: I have created a big flat map, placed an AI agent on it, and generated AI navigation triangulation.
I noticed that the AI agent doesn't always take the shortest straight path from point A to point B.
Why?
A: To illuminate the issue, use the following tools:
• AI debug console variable ai_DebugDraw
set to "74". This value draws the AI navigation graph.
(Note: a value of 79 will run faster, but limits the result to the area close to the player (with 15 m).
• AI debug console variable ai_DrawPath
set to "all". This variable draws AI agent paths, including links (the corridors between adjacent triangles).
• The
Ruler
tool in Editor, used to visualize paths. You don't even need actual AI agents on the map to run experiments. (Note: this tool is located between
Snap Angle
and
Select Object(s)
.)
The AI navigation triangulation is intended to be fast and have a small memory footprint. One of the decisions made in this regard was to use 16-bit signed integers to store corridor (or "link") radius measurements between two adjacent triangles. Using centimeters as the uint of measure, this means
Version 1.10
33
Lumberyard Developer Guide
Path Following that the maximum link radius is 32767 cm (327.67 m). When an AI agent moves to another triangle, it can only go through this corridor, which is naturally very narrow if the triangles are still very large.
This problem does not exist for triangles with edges less than 2 * 327.67 = 655.34 m.
This problem can only appear in the very initial stages of map development. Every forbidden area, tree or other map irregularity makes triangulation more developed, which results in more triangles that are smaller in size. As a result, the problem goes away.
Q: How does path following actually work? Where to start?
A: See the topic on
.
Q: How do you keep patrols always active, regardless of their distance from the player?
A: See the topic on
This topic provides some high-level insight on how path following is done in Lumberyard. To illustrate some concepts, we'll use the relatively simplistic example of Racing HMMWVs, which is a good representation of classic path following as presented in many AI texts.
Path following with Racing HMMWVs adheres to the following sequence.
1. Get the closest (to the AI agent) point on path.
2. Get the path parameter of this point. Paths usually have some kind of parametrization,
t -> (x,y,z).
3. Add a certain value, usually called a "lookahead", to this parameter.
4. Get the path point that corresponds to this new parameter. This is called the look-ahead position.
5. Use this point as the navigation target.
6. If the vehicle is stuck, beam it straight to the closest point on the path.
Use the goalop
followpath
to instruct an AI agent to follow a path. You can observe this sequence in action by setting a breakpoint at the beginning of a call to COPFollowPath::Execute. In the call stack window in Visual Studio, you'll be able to see the update operations for all (active) AI agents being called as part of the AI system update procedure. This action in turn calls the execute operations of the currently active goalops being run by the AI.
COPFollowPath::Execute accomplishes the following tasks:
• Uses the goalop
pathfind
to find a path leading to the beginning of a path. Optionally, it finds a path to the closest point on a path using a parameter passed to the
followpath
goalop.
• Traces the path by following it using the goalop
trace
• Listens for the signal "OnPathFollowingStuck" to make sure the AI agent isn't stuck
Version 1.10
34
Lumberyard Developer Guide
COPTrace::ExecuteTrace and COPTrace::Execute
The goalops
pathfind
and
trace
are commonly used for navigational goalops, including
approach
and
stick
.
COPTrace::ExecuteTrace is used to clean up path-following issues, including handling edge cases and smart objects. The core of this call is as follows:
IPathFollower* pPathFollower = gAIEnv.CVars.PredictivePathFollowing ? pPipeUser-
>GetPathFollower() : 0; bTraceFinished = pPathFollower ? ExecutePathFollower(pPipeUser, bFullUpdate,
pPathFollower) : Execute2D(pPipeUser, bFullUpdate);
COPTrace::Execute does the same work plus a bit more. For the AI following a path, when its lookahead position hits the end of the path, this operation sends the signal "OnEndWithinLookAheadDistance" to the AI. In the sample scenario, this allows our racing HMMWVs to start looking for a new path to follow while they're still moving along the current path. Normally AI agents stop moving when the path following process is completed. The following Lua script is also useful to maintain movement:
AI.SetContinuousMotion(vehicle.id, true);
This operation can be used as a fallback if an AI agent (CPipeUser, at least) doesn't have a path follower.
COPTrace::Execute2D accomplishes the following tasks:
• Gets the lookahead path position and the path direction at this position.
• Executes a maneuver, if necessary. For example, it makes cars go backwards to make a U-turn.
• Considers a number of reasons to slow down, including:
• The angle between current and desired (aforementioned path direction) directions.
• The curvature of the path.
• Approaching the end of the path.
• Approaching the top of a hill.
It then sets members
fDesiredSpeed
and
vMoveDir
of the AI agent's SOBJECTSTATE structure, which are brought to the game code later. For an example of how this data can be used for actual steering, take a look at CVehicleMovementArcadeWheeled::ProcessAI.
Note that COPTrace::Execute2D is not the only operation that sets
vMoveDir
. For example, obstacle avoidance code can overwrite it.
Key priorities for the AI Movement system include the following features.
• Robust and predictable. Navigation can be very unreliable, with no guarantee that a character will carry out the requested movement and end up at the desired destination. This is a very organic problem with no clear resolutions. The AI Movement system solves this by providing more explicit information about failure reasons.
• Central, clear ownership and easy debugging. Rather than having contextual movement information
– style, destination, requester, etc. – tied to a specific goalop and getting lost when a behavior switch
Version 1.10
35
Lumberyard Developer Guide
Using the Movement System occurs, Lumberyard maintains this information in a central location and separated from the goalop.
In practice, a movement request can be sent from anywhere and the movement system handles it centrally. when the goalop requester is no longer interested, it simply cancels the request. This doesn't mean the character stops immediately and all information is lost, it just means that interest in the request has expired.
• Planning. In Lumberyard, logic is handled in blocks for ease of use and organization. Movement blocks are responsible for their own isolated tasks, such as FollowPath, LeaveCover and UseSmartObject. A collection of blocks in sequence make up a plan, which is produced by a controller with a string-pulled path as input. This types of organization helps clarify a larger picture about what is being processed right now and what is coming up.
Note
This system is still a work in progress, and it's design was focused on solving some critical problems with an existing code base. It may not be suitable for all game titles.
Using the movement system is pretty straightforward. Create a MovementRequest object with information about the destination, style and a callback. Queue it in MovementSystem and receive a
MovementRequestID. Use this if you want to cancel the request. Then wait for MovementSystem to process to your request. Once your request is processed, you'll be notified via the callback.
Here's what's happening internally to process your request:
1. Once MovementSystem receives your request, it creates an internal representation of the character, called a MovementActor. This is a container for all internal states and the proxy to all external states/ logic related to a character. It binds a MovementController to the actor. Currently there's only one controller available – GenericController, which is the result of what was done before. (The term
"controller" is also used on the game side for a similar but different entity. These entities may be merged in the future, and multiple types of controllers added, such as for the Pinger, Scorcher, or
BipedCoverUsed.)
2. MovementSystem informs the controller that there's a new request to start working on.
GenericController kicks off the path finder.
3. Once the pathfinding result is in, the GenericController produces a plan that it starts to follow.
4. When the GenericController finishes the last block in the plan, it informs MovementSystem that the task is finished.
5. MovementSystem notifies the requester of success, and moves on to the next request.
The following areas of improvement or enhancement are under consideration:
• Change request processing. Currently there is a request queue, with movement requests processed one at a time, in FIFO order. Requests are immutable, so it's impossible to change a request once it's been queued; as a result, the only option is to cancel a request and queue a new one. These issues could be resolved by removing the request queue and allowing only one request at a time. If a request comes in while one is already being processed, interrupt the current one and report it.
• Validate a pipe user before proceeding with the update.
• When a UseSmartObject block detects that the exact positioning system fails to position a character at the start of a smart object, it reports this failure through the agent's bubble and in the log. It then resolves the problem by teleporting the character to the end of the smart object and proceeds to the next block in the plan.
Version 1.10
36
Lumberyard Developer Guide
Auto-Disable
• The GenericController is only allowed to start working on a new request while it is executing a
FollowPath block. It then shaves off all subsequent blocks so that the actor doesn't find itself in the middle of a smart object when planning takes place. This could be improved by allowing the controller to produce a part of the plan, looking further ahead, and then patch it with the current plan.
• The plan isn't removed when a request is canceled. This is because a subsequent 'stop' or 'move' request should follow the cancellation. However, until this request has been received, the controller has no way to know what to do.
• The pathfinding request is being channeled through the pipe user, and the result is returned to the pipe user as well as stored in m_path
. This path is then extracted by the movement controller. It would be better if the pathfinder could be employed directly by the movement controller and skip the pipe user as a middle layer.
• The movement controller code would fit better on the game side, since that's where the information about the characters should live. It could be merged with the movement transitions that are handled on the game side.
• Being able to pull out a movement request at any time makes the code slightly more complex, because we can't rely on that fact that the controller is always working on a request that still exists. It may be better to keep the request, flag it as abandoned and clear the callback.
• The code could be improved by separating planning and plan execution into two different code paths instead of one.
You can save CPU time by not updating distant AI agents. Use the auto-disable feature to controlled updates either on a per-AI basis or globally.
• To control auto-disable for all vehicles: use the console variable v_autoDisable
.
• To control auto-disable for all AI agents: use the console variable ai_UpdateAllAlways
.
Per-AI auto-disable is controlled by the entity property AutoDisable. Refer to the Lumberyard User Guide for more details on AI and vehicle entities. You can also change this property (and behavior) at run time.
• C++: pAIActorProxy->UpdateMeAlways(true);
• Lua:
AI.AutoDisable(entity.id, 1);
• In Flow Graph Editor: turn
AI:AutoDisable
on or off for each AI.
This collection of topics describes how to handle some key AI capabilities using scripting.
This section includes the following topics:
•
•
•
•
Version 1.10
37
Lumberyard Developer Guide
Communication System
•
AI communication is about playing sound/voice and/or animations at the right times in the course of the game.
Setting up communication for an AI agent requires the following steps:
• General set up:
• Define communication channels. Channels are used to track the status of communication events for an AI.
• Define communications. Communications detail specifically what activity should occur (and how) when the communication is called for. Communications are grouped into configurations.
• Set up voice libraries. Voice libraries support localized dialogs, subtitles, and lip-syncing.
• Specify communication types for an AI using AI properties:
• Point an AI's CommConfig property to a communication configuration, which contains the set of communications for that AI.
• Point an AI's esVoice property to a voice library to use for that AI.
• Trigger a communication event:
• Specify the name of a communication channel for the event.
• Specify the name of a communication to fire.
Communications, channels, and voice libraries are defined in a set of XML files. At game start-up, the directory
Game/Scripts/AI/Communication
and all subfolders are scanned for XML files containing these configurations.
A communication channel determines whether an AI can play a communication at a given moment, depending on whether or not the communication channel is occupied. Channels are a self-contained concept, independent of other AI communication concepts. They have a sole purpose: to be in one of two possible states, "occupied" or "free".
AI communication channels are defined in an XML file stored in
Game/Scripts/AI/Communication
. The
SDK includes a template channel configuration XML file, called
ChannelConfg.xml
. Communication channels are configured in a hierarchy of parent and child channels. The hierarchical structure determines how a channel's occupied status affects the status of other channels (for example, a parent of an occupied child channel).
Channel Elements & Attributes
Communication channels are defined in a
<ChannelConfig>
element with the following attributes:
name
Channel name.
priority
minSilence
Minimum time (in seconds) that the channel should remain occupied after a communication has been completed.
Version 1.10
38
Lumberyard Developer Guide
Communication System
flushSilence
Time (in seconds) that the channel should remain occupied after it has been flushed. This value overrides the imposed silence time (
minSilence
) after playing a communication. If not specified, the value set for
minSilence
is used.
actorMinSilence
Minimum time (in seconds) to restrict AI agents from playing voice libraries after starting a communication.
ignoreActorSilence type
Flag indicating that AI agent communication restrictions from the script should be ignored.
Type of communication channel. Valid values are "personal", "group" or "global".
Example
Game/Scripts/AI/Communication/ChannelConfig.xml
<Communications>
<ChannelConfig>
<Channel name="Global" minSilence="1.5" flushSilence="0.5" type="global">
<Channel name="Group" minSilence="1.5" flushSilence="0.5" type="group">
<Channel name="Search" minSilence="6.5" type="group"/>
<Channel name="Reaction" priority="2" minSilence="2" flushSilence="0.5"
type="group"/>
<Channel name="Threat" priority="4" minSilence="0.5" flushSilence="0.5"
type="group"/>
</Channel>
<Channel name="Personal" priority="1" minSilence="2" actorMinSilence="3"
type="personal"/>
</Channel>
</ChannelConfig>
</Communications>
Communication configurations determine what communication activity AI agents can perform and how it will manifest. Communications for a particular type of AI are grouped into configurations.
For example, your game might have both human and non-human AI agents, each with its own set of communication activities. In this scenario, you might group all the human communications into a configuration object named "human" while communications for non-humans might be grouped into a "non-human" configuration. For a particular AI, you'll specify the configuration to use with the AI's
CommConfig
property. With this configuration structure, you can define a communication (such as
"surprise") differently in each configuration so that, when triggered, the communication activity fits the
AI involved.
For each communication, you also have the option to define multiple variations of action and specify how the variations are used.
AI communication channels are defined in one or more XML files stored in
Game/Scripts/
AI/Communication
. The SDK includes a template channel configuration XML file, called
BasicCommunications.xml
.
Communication Elements & Attributes
Communications are configured using the following elements and attributes:
Version 1.10
39
Lumberyard Developer Guide
Communication System
Config
Communication configurations are grouped into
<Config>
elements and use the following attributes.
Each configuration must contain at least one communication.
name
Configuration name, which can be referenced in the AI's CommConfig property.
Communication
A communication is defined in a
<Communication>
element with the following attributes. Each communication should contain at least one variation.
name
Communication name.
choiceMethod
Method to use when choosing a variation. Valid values include "Random", "Sequence",
"RandomSequence" or "Match" (uses only the first variation).
responseName
responseChoiceMethod
Similar to
choiceMethod
.
forceAnimation
Boolean flag.
Variation
Each variation is defined in a
<Variation>
element with the following attributes.
animationName
Animation graph input value.
soundName
voiceName
lookAtTarget
Boolean flag indicating whether or not the AI should look at the target during the communication.
finishMethod
Method that determines when communication is finished, such as after the communication type has finished or after a time interval. Valid values include "animation", "sound", "voice", "timeout" or "all".
blocking
AI behavior to disable during communication. Valid values include "movement", "fire", "all", or "none".
animationType
Valid values include "signal" or "action".
Version 1.10
40
Lumberyard Developer Guide
Communication System
timeout
Example
Game/Scripts/AI/Communication/BasicCommunications.xml
<Communications>
<!--sound event example-->
<Config name="Welcome">
<Communication name="comm_welcome" finishMethod="sound" blocking="none">
<Variation soundName="sounds/dialog:dialog:welcome" />
</Communication>
</Config>
<!--example showing combined animation + sound event (needs state using action/signal in
the animation graph)-->
<Config name="Surprise">
<Communication name="comm_anim" finishMethod="animation" blocking="all"
forceAnimation="1">
<Variation animationName="Surprise" soundName="sounds/ interface:player:heartbeat" />
</Communication>
</Config>
</Communications>
To support localized dialogs, subtitles, and lip syncing, you need to set up voice libraries. Once set up, you can assign a voice library to an AI (or entity archetype) using the AI's
esVoice
property.
Voice libraries are defined in a set of XML Excel files stored in
GameSDK/Libs/Communication/Voice
. The
SDK includes a template voice library file at
GameSDK/Libs/Communication/Voice/npc_01_example.xml
.
Each voice library must include the following information.
Language
Localization type for this library.
File Path
Location where the sound files for this library are stored.
Signal
Communication name associated with a sound file.
Sound File
File name of a sound file, listed by signal.
Example
Comment field used to describe or illustrate a sound file.
Example
GameSDK/Libs/Communication/Voice/npc_01_example.xml
Language
American English
Version 1.10
41
Lumberyard Developer Guide
Communication System
pain
death
File Path
Signal
see
alerted
languages/dialog/ai_npc_01/
Sound File SDK NPC 01 Example
see_player_00 see_player_01 see_player_02 pain_01 pain_02 pain_03 death_01 death_02 death_03 alerted_00 alerted_01 alerted_02 i see you hey there you are hey i have been looking for you ouch ouch ouch arrrhh arrrhh arrrhh watch_out be careful something there
An AI's communication methods are set using the AI agents properties. You can set AI properties in several ways. For information about using the Lumberyard Editor to set AI properties, see "Using
Database View to Set AI Communication" in the Lumberyard User Guide).
Set the following properties:
•
CommConfig
– Set this property to the name of the communication configuration you want this AI to use. Communication configurations are defined in XML files in
Game/Scripts/AI/Communication
, using
<Config>
elements.
•
esVoice
– Set this property to the name of the XML file containing the voice library you want this AI to use. Voice libraries are defined in XML files in
GameSDK/Libs/Communication/Voice
.
Turning Animation and Voice Off
Communication animation and/or voice can be turned off for an AI agent using the agent's Lua script (as in the example below) or the entity properties in Lumberyard Editor Editor.
Example
Game/Scripts/Entities/AI/Shared/BasicAITable.lua
Version 1.10
42
Lumberyard Developer Guide
Communication System
Readability =
{
bIgnoreAnimations = 0,
bIgnoreVoice = 0,
},
To trigger a communication event, use the goalop
communicate
with the following attributes. Note that communication animations are not played if the AI is currently playing a smart object action.
name
Name of the communication to trigger (sound, voice, and/or animation). Communication names are defined in an XML file referred to by the CommConfig property of this AI.
channel
Communication channel being used by this AI. An AI's communication channel is defined in an XML file in
Game/Scripts/AI/Communication
.
expirity (expiry)
Maximum allowable delay in triggering the communication when the communication channel is temporarily occupied. If a communication can't be triggered within this time period, it is discarded.
To trigger communications using flow graph logic, use the Flow Graph node
AI:Communication
.
Example
<GoalPipe name="Cover2_Communicate">
<Communicate name="comm_welcome" channel="Search" expirity="0.5"/>
</GoalPipe>
To get debug information on AI communication issues, use the following console variables
( ai_DebugDraw
should be set to "1"):
• ai_DebugDrawCommunication
• ai_DebugDrawCommunicationHistoryDepth
• ai_RecordCommunicationStats
Debug output is shown in the console as illustrated here:
Playing communication: comm_welcome[3007966447] as playID[84]
CommunicationPlayer::PlayState: All finished! commID[-1287000849]
CommunicationManager::OnCommunicationFinished: comm_welcome[3007966447] as playID[84]
CommunicationPlayer removed finished: comm_welcome[3007966447] as playID[84] with
listener[20788600]
[Warning] Communicate(77) [Friendly.Norm_Rifle1] Communication failed to start
Version 1.10
43
Lumberyard Developer Guide
Factions
You may get this message or a similar one if your AI's behavior tree calls a communication but the communication configuration is not set up properly. In this example message, "77" refers to line 77 in your AI's behavior tree script (or goalop script). This line is probably communication trigger such as this:
<Communicate name="TargetSpottedWhileSearching" channel="Reaction" expirity="1.0"
waitUntilFinished="0" />
Some things to check for::
• Does the specified communication name "TargetSpottedWhileSearching" exist in your communication configuration files (XML files located in
Game/Scripts/AI/Communication/
)?
• Check the
CommConfig
property for the AI. Is it set to the name of a
<Config>
element defined in your communication configuration files? If so, is the communication name "TargetSpottedWhileSearching" defined inside this
<Config>
element? This issue, calling communications that aren't configured for the
AI is a common source of this error.
• Check the communication's variation definition. Does it point to a resource (animation, sound) that exists? If using a voice library, does it point to a valid voice library file name?
AI agents use factions to determine their behavior when encountering other AI agents. There are a base set of behaviors such as neutral, friendly and hostile. For example, when an AI in the "Grunt" faction encounters an AI in the "Players" faction, the encounter will be hostile. Players encountering "Civilians" will be friendly, etc.
To set up faction communications:
• Create an XML file that defines all the factions in your game and their reactions to each other (see the example). This file should be placed in
\Games\Scripts\AI\
. The SDK includes a template faction XML file, called
Factions.xml
.
• Set the Faction property for all of your AI agents to one of the defined factions. You can also set factions using Flow Graph
Example: Faction setup
Factions.xml
<Factions>
<Faction name="Players">
<Reaction faction="Grunts" reaction="hostile" />
<Reaction faction="Civilians" reaction="friendly" />
<Reaction faction="Assassins" reaction="hostile" />
</Faction>
<Faction name="Grunts">
<Reaction faction="Players" reaction="hostile" />
<Reaction faction="Civilians" reaction="neutral" />
<Reaction faction="Assassins" reaction="hostile" />
</Faction>
<Faction name="Assassins">
<Reaction faction="Players" reaction="hostile" />
<Reaction faction="Civilians" reaction="hostile" />
<Reaction faction="Grunts" reaction="hostile" />
</Faction>
<Faction name="HostileOnlyWithPlayers" default="neutral">
<Reaction faction="Players" reaction="hostile" />
</Faction>
<Faction name="Civilians" default="neutral" />
Version 1.10
44
Lumberyard Developer Guide
Modular Behavior Tree
<Faction name="WildLife" default="neutral" />
</Factions>
Modular behavior tree (MBT) is a collection of concepts for authoring behaviors for artificial intelligent
(AI) agents in your game. Instead of writing complicated code in C++ or other general purpose programming language, MBT lets you describe AI behaviors at a high level without having to think about mechanics such as pointers, memory, and compilers. MBT concepts and implementation are optimized for rapid iteration and re-use.
Conceptually, MBT is based on two key objects: the
node
and the
tree
.
Node
The node is the most fundamental concept; it is a building block that can be combined with others to build behaviors. A node consists of a block of code that represents a simple task. All nodes have the same interface: when processed, they carry out a task and either succeed or fail.
Nodes can be standalone or may have child nodes, which are processed as part of the parent node processing. When processed, the success of a parent node often (but not always) depends on the success of each child node.
Nodes follow several common patterns, such as action, composite, and decorator nodes. These common node patterns are more fully described in later in this topic.
Tree
Game developers can create the nodes needed for their game. In addition, Lumberyard provides a set of standard nodes for general use. These include nodes for tasks related to AI, animation, flying, and common game activities, as well as generic nodes useful when building behaviors, such as for timeouts and looping tasks. These provided nodes are documented in the
.
Behaviors are constructed by building trees of nodes, collections of individual tasks that, when positioned as a root with branches that extend out into leaves, define how an AI agent will behave in response to input.
Action Nodes
An action node represents some sort of simple action. Action nodes might cause the AI agent to speak, play an animation, or move to a different location.
Composite Nodes
A composite node represents a series of actions to be performed in a certain order. Composite nodes consist of a parent node and two or more child nodes. Whether or not a child node is processed (and in
Version 1.10
45
Lumberyard Developer Guide
Modular Behavior Tree what order) can depend on the success or failure of previously processed nodes. Common composite patterns include sequential, selector, and parallel.
Sequential node
This composite pattern describes child nodes that are processed consecutively in a specified sequence. All child nodes are processed regardless of whether the previous child node succeeded or failed. For example, a sequential node might cause an AI monster to point at the player, roar, and then run toward the player. In this pattern, each child node in the sequence must succeed for the next child node to start processing; if any child node fails, the parent node immediately fails and processing is stopped.
Selector node
This composite pattern describes child nodes that are processed consecutively and in sequence only until one succeeds. As soon as one child node succeeds, the parent node succeeds immediately and stops processing child nodes. If all child nodes are attempted and all fail, the parent node fails. This pattern is useful for setting up AI agents to try multiple different tactics, or for creating fallback behaviors to handle unexpected outcomes.
Imagine, for example, that we want our AI monster to chase the player, but if it can't reach the player it should scream “Come and fight me, you coward!” To implement this scenario, a selector parent node is set up with two children, one for each possible action. The parent node first processes the “chase player” child node. If it succeeds, then the selector node stops there. However, if the
“chase player node fails, then the parent node continues and processes the “taunt player” child node.
Parallel node
This composite pattern describes child nodes that are processed concurrently. In this scenario,
Imagine we want our AI monster to scream and chase the player at the same time rather than one after the other.
Decorator Nodes
A decorator node represents some sort of functionality that can be added to another node and behaves regardless of how the other node works or what it does. Common decorator functionality includes looping and limiting concurrent functionality.
Version 1.10
46
Lumberyard Developer Guide
Modular Behavior Tree
Looping
Looping functionality can be used to process any other node multiple times. Rather than creating custom nodes every time you want to repeat a task, you can wrap any node in a parent loop decorator node. By setting a parameter for the loop node, you can dictate the number of times the child nodes will be processed. Each time the child node succeeds, the loop node count is updated and the child node is re-processed. Once the loop count meets the set parameter, the loop node succeeds.
Limiting concurrent users
This functionality lets you specify how many users should be allowed to concurrently use a specified node. It is a good way to ensure variations in behavior among a group of AI agents. A typical scenario illustrating this function is as follows: The player is spotted by a group of three monsters. You want one monster to sound an alarm while the others chase the player.
Limiting concurrent users works with a selector node, which steps through a sequence of child nodes until one succeeds. By wrapping one of a selector node’s child nodes in a limit decorator node, you can cause the child node to fail due to concurrent users, which in turn causes the selector node to move to the next child.
To handle the scenario described, the selector node would have two child nodes, “sound alarm” and “chase player”. The “sound alarm” node is wrapped in a limit node, with the user limit set to 1.
Monster #1 flows through the selector node to the limit node; as there is no one currently using the
“sound alarm” node, the Monster #1 takes this action. The limit node records that one AI agent is processing the child node, so effectively locks the door to it. Monsters #2 and #3 also flow through the selector node to the limit node, but because the limit node has reached its limit of user, it reports a failure. Consequently, the selector node moves on to the next child node in the sequence, which is “chase player”. So monsters #2 and #3 chase the player.
Behavior trees are described using XML markup language. Behavior trees are hot-loaded every time the user jumps into the game in the editor.
The following XML example describes the behavior tree for a group of monsters. In this example, only one monster at a time is allowed to chase the player. The remaining monsters stand around and taunt the player.
<BehaviorTree>
<Root>
<Selector>
<LimitConcurrentUsers max=”1”>
<ChasePlayer />
Version 1.10
47
Lumberyard Developer Guide
Modular Behavior Tree
</LimitConcurrentUsers>
<TauntPlayer />
</Selector>
</Root>
</BehaviorTree>
You'll find all MBT code encapsulated in the BehaviorTree namespace.
Understanding the Memory Model
MBT has a relatively small memory footprint. It accomplishes this by (1) sharing immutable (read-only) data between instances of a tree, and (2) only allocating memory for things that are necessary to the current situation.
Memory is divided into two categories: configuration data and runtime data. In addition, MBT uses smart pointers.
Configuration data
When a behavior tree such as the following example is loaded, a behavior tree template is created that holds all the configuration data shown in the example. This includes a sequence node with four children: two communicate nodes, an animate node, and a wait node. The configuration data is the animation name, duration, etc., and this data never changes.
<Sequence>
<Communicate name=”Hello” />
<Animate name=”LookAround” />
<Wait duration=”2.0” />
<Communicate name=”WeShouldGetSomeFood” />
</Sequence>
Memory for the configuration data is allocated from the level heap. When running the game through the launcher, this memory is freed on level unload; alternatively, it is freed when the player exits game mode and returns to edit mode in Lumberyard Editor.
Runtime data
When spawning an AI agent using a behavior tree, a behavior tree Instance is created and associated with the agent. The instance points to the behavior tree template for the standard configuration data, which means that the instance contains only instance-specific data such as variables and timestamps.
When the tree instance is accessed for the AI agent, it begins by executing the Sequence node. If the core system detects that this is the first time the behavior has been run for this AI agent, it allocates a runtime data object specifically for this node and agent. This means that every AI agent gets its own runtime data object when executing a behavior tree node. The runtime data object persists as long as the
AI agent is executing a node (this can be several frames) but is freed when the AI agent leaves a node.
Memory for runtime data is allocated from a bucket allocator. This design minimizes memory fragmentation, which is caused by the fact that runtime data is usually just a few bytes and is frequently allocated and freed. The bucket allocator is cleaned up on level unload.
Smart pointers
MBT uses Boost smart pointers to pass around data safely and avoid raw pointers as much as possible.
Memory management is taken care of by the core system. (While there are circumstances in which a
unique_ptr
from C++11 would work well, Lumberyard uses Boost's
shared_ptr
for compatibility reasons.)
Version 1.10
48
Lumberyard Developer Guide
Modular Behavior Tree
Implementing an MBT Node
To implement a new MBT node in C++, you'll need to do the following tasks:
• Create the node
• Expose the node to the node factory
• Set up error reporting for the node
Creating a node
The following code example illustrates a programmatic way to create a behavior tree node. When naming new nodes, refer to
Recommended Naming Practices (p. 54)
.
#include <BehaviorTree/Node.h> class MyNode : public BehaviorTree::Node
{
typedef BehaviorTree::Node BaseClass;
public:
// Every instance of a node in a tree for an AI agent will have a
// runtime data object. This data persists from when the node
// is visited until it is left.
//
// If this struct is left out, the code won't compile.
// This would contain variables like 'bestPostureID', 'shotsFired' etc.
struct RuntimeData
{
};
MyNode() : m_speed(0.0f)
{
}
// This is where you'll load the configuration data from the XML file
// into members of the node. They can only be written to during the loading phase
// and are conceptually immutable (read-only) once the game is running.
virtual LoadResult LoadFromXml(const XmlNodeRef& xml, const LoadContext& context)
{
if (BaseClass::LoadFromXml(xml, context) == LoadFailure)
return LoadFailure;
xml->getAttr("speed", m_speed);
return LoadSuccess;
} protected:
// Called right before the first update
virtual void OnInitialize(const UpdateContext& context)
{
BaseClass::OnInitialize(context);
// Optional: access runtime data like this
RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
}
// Called when the node is terminated
virtual void OnTerminate(const UpdateContext& context)
{
BaseClass::OnTerminate(context);
// Optional: access runtime data like this
RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
Version 1.10
49
Lumberyard Developer Guide
Modular Behavior Tree
}
virtual Status Update(const UpdateContext& context)
{
// Perform your update code and report back whether the
// node succeeded, failed or is running and needs more
// time to carry out its task.
// Optional: access runtime data like this
RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
return Success;
}
// Handle any incoming events sent to this node
virtual void HandleEvent(const EventContext& context, const Event& event)
{
// Optional: access runtime data like this
RuntimeData& runtimeData = GetRuntimeData<RuntimeData>(context);
} private:
// Store any configuration data for the node right here.
// This would be immutable things like 'maxSpeed', 'duration',
// 'threshold', 'impulsePower', 'soundName', etc.
float m_speed;
};
// Generate an object specialized to create a node of your type upon
// request by the node factory. The macro drops a global variable here.
GenerateBehaviorTreeNodeCreator(MyNode);
Exposing a node
To use the newly created node, you'll need to expose it to the node factory, as shown in the following code snippet.
BehaviorTree::INodeFactory& factory = gEnv->pAISystem->GetIBehaviorTreeManager()-
>GetNodeFactory();
ExposeBehaviorTreeNodeToFactory(factory, MyNode);
Setting up error reporting
Use the class
ErrorReporter
to report errors and warnings in the new node. It will let you log a printfformatted message and automatically include any available information about the node, such as XML line number, tree name, and node type.
ErrorReporter(*this, context).LogError("Failed to compile Lua code '%s'", code.c_str());
Variables
Variables are statically declared in XML, with information about how they will change in response to signals from AI agents (named text messages within the AI system).
The following code snippet illustrates the use of variables to receive input from the AI system. In this example, the AI agent takes action based on whether or not it can "see" the target.
<BehaviorTree>
<Variables>
<Variable name="TargetVisible" />
Version 1.10
50
Lumberyard Developer Guide
Modular Behavior Tree
</Variables>
<SignalVariables>
<Signal name="OnEnemySeen" variable="TargetVisible" value="true" />
<Signal name="OnLostSightOfTarget" variable="TargetVisible" value="false" />
</SignalVariables>
<Root>
<Selector>
<IfCondition condition=”TargetVisible”>
<Move to=”Target” />
</IfCondition>
<Animate name=”LookAroundForTarget” />
</Selector>
</Root>
</BehaviorTree>
Lua Scripting
Lua code can be embedded in a behavior tree and executed along with the tree nodes. This is useful for running fire-and-forget code or for controlling the flow in a tree. It's useful for prototyping or extending functionality without having to create new nodes.
The code is compiled once when the level is loaded in pure game to reduce fragmentation. Only code for behavior trees that are actually used in that level will be compiled.
All Lua nodes provide access to the
entity
variable.
•
ExecuteLua
runs a bit of Lua code. It always succeeds.
<ExecuteLua code=”DoSomething()” />
•
LuaWrapper
inserts a bit of Lua code before and after running child node. The post-node code is run regardless of whether the child node succeeded or failed.
<LuaWrapper onEnter=”StartParticleEffect()” onExit=”StopParticleEffect()”>
<Move to=”Cover” />
</LuaWrapper>
•
LuaGate
uses a bit of Lua code to control whether or not a child node should be run. If the Lua code returns true, the child node is run and
LuaGate
returns the status of the child node (success or failure).
If the code returns false or fails to execute, the child node is not run, and
LuaGate
returns failure.
<LuaGate code=”return IsAppleGreen()”>
<EatApple />
</LuaGate>
•
AssertLua
lets you make a statement. If the statement is true, the node succeeds; if it's false the node fails.
<Sequence>
<AssertLua code=”return entity.someCounter == 75” />
<AssertCondition condition=”TargetVisible” />
<Move to=”Target” />
</Sequence>
Timestamps
A timestamp identifies a point in time when an event happened. A lot of AI behavior depends on tracking the timestamp of certain events and measuring the amount of time from those points. For example, it
Version 1.10
51
Lumberyard Developer Guide
Modular Behavior Tree can be useful to tie behavior to how long it's been since the AI agent was last shot at or hit, when it last saw the player, or how long it's been since moving to the current cover location.
Timestamps can be declared as mutually exclusive, that is, both timestamps can't have a value at the same time. For instance,
TargetSpotted
and
TargetLost
can both have a value because the AI agent can't see a player and at the same time consider them lost. With exclusive timestamps, when one timestamp has a value written to it, the other timestamp is automatically cleared.
The following code snippet illustrates the use of timestamps.
<BehaviorTree>
<Timestamps>
<Timestamp name="TargetSpotted" setOnEvent="OnEnemySeen" />
<Timestamp name="ReceivedDamage" setOnEvent="OnEnemyDamage" />
<Timestamp name="GroupMemberDied" setOnEvent="GroupMemberDied" />
</Timestamps>
<Root>
<Sequence>
<WaitUntilTime since=”ReceivedDamage” isMoreThan=”5” orNeverBeenSet=”1” />
<Selector>
<IfTime since="GroupMemberDied" isLessThan=”10”>
<MoveCautiouslyTowardsTarget />
</IfTime>
<MoveConfidentallyTowardsTarget />
</Selector>
</Sequence>
</Root>
</BehaviorTree>
Events
Communication with AI agents is done using AI signals, which essentially are named text messages.
Signals such as OnBulletRain and OnEnemySeen communicate a particular event, which, when broadcast to other AI agents, can be reacted to based on each AI agent's behavior tree. This design allows AI behavior to remain only loose coupled with AI signals. AI Signals are picked up and converted to MBT events, then dispatched to the root node, which passes them along down the running nodes in the tree.
<Sequence>
<WaitForEvent name=”OnEnemySeen” />
<Communicate name=”ThereHeIs” />
</Sequence>
This section provides help with debugging behavior trees by providing a tree visualization view during debugging. This view allows you to track an AI agent's progress through the tree as the game progresses.
"Slashing" Agents
This feature allows you to view the behavior tree for a specific AI agent in DebugDraw. To enable this feature:
1. Set ai_DebugDraw to 0 or 1 (default is -1).
2. Select the AI agent you want to view a behavior tree for:
• Place the selected AI agent in the center of the camera view and press the numpad "/" key.
• Call "ai_DebugAgent closest" to select the agent closest to the camera.
• Call "ai_DebugAgent centerview" to select the agent closest to the center of the camera view (same as slash).
Version 1.10
52
Lumberyard Developer Guide
Modular Behavior Tree
• Call "ai_DebugAgent <AgentName>" to select a specific agent by its name.
• Call "ai_DebugAgent" without a parameter to remove the tree visualization.
The tree visualization displays the AI agent's name at the top of the screen and identifies the agent on the screen with a small green dot. Tree nodes are displayed and color coded as follows, with line numbers from the XML file shown on the left.
• White – nodes with custom data
• Blue – leaf nodes, which often carry special weight when debugging
• Gray – all other nodes
Adding Custom Debug Text
Tree visualization supports custom node information. This allows you to get a more in-depth view of the currently running parts of a behavior tree. For example, you can see the name of the event that the
WaitForEvent
node is waiting for, or how much longer
Timeout
is going to run before it times out.
To use this feature, override
GetDebugTextForVisualizer
, as follows.
#ifdef STORE_INFORMATION_FOR_BEHAVIOR_TREE_VISUALIZER virtual void GetDebugTextForVisualizer(
const UpdateContext& updateContext,
stack_string& debugText) const
{
debugText.Format("Speed %f", m_speed);
}
#endif
Logging and Tracing
Tracing log messages is a critical tool for diagnosing problems. Lumberyard provides native support for logging, as shown in the following code snippet.
<Sequence>
<QueryTPS name="CoverFromTarget" _startLog="Finding cover" _failureLog="Failed to find
cover" />
<Move to="Cover" _startLog="Advancing" _failureLog="Failed to advance"
_successLog="Advanced" />
</Sequence>
(The reserved attributes _startLog, _successLog, and _failureLog are automatically read in.)
Log messages are routed through an object deriving from the
BehaviorTree::ILogRouter
interface. This allows you to determine where the logging messages end up. For example, one option would be to route the info to a personal log and store a short history of log messages for each AI agent; with this approach, log messages can be displayed when debugging as part of an AI agent's tree visualization.
The AI Recorder also retains all log messages; use this tool to explore sequences of events.
Compiling with Debug Information
To compile a game with debug information, you need to define DEBUG_MODULAR_BEHAVIOR_TREE.
#if !defined(_RELEASE) && (defined(WIN32) || defined(WIN64))
# define DEBUG_MODULAR_BEHAVIOR_TREE
#endif
Version 1.10
53
Lumberyard Developer Guide
Modular Behavior Tree
Viewing Completed Trees
When a behavior tree finishes executing—either by failing or succeeding all the way through the root node, a notification is displayed in the console window along with a list of recently visited nodes and their line numbers.
[Error] Modular Behavior Tree: The root node for entity 'HumanSoldier' FAILED. Rebooting the tree next frame. (124) Move. (122) Selector. (121) Sequence.
Note that in the example above the tree will be rebooted in the next frame. This suggests that the behavior tree was not designed to handle a failure at this point.
The following suggestions help streamline code clarity and communication in a development team.
Naming Nodes
For action nodes, use names that identify the action the node will perform. These are usually action verbs.
Good
• Loop
• Animate
• LimitConcurrentUsers
• ExecuteLua
• Shoot
• AdjustCoverStance
Bad
• Fast
• PathPredictor
• Banana
• Script
• ActivationProcess
Naming Timestamps
Name timestamps based on the event they’re related to. Because timestamps describe an event that has already happened, use the past tense (TargetSpotted, not TargetSpots).
• TargetSpotted
• ReceivedDamage
• GroupMemberDied
This section contains reference information on modular behavior tree (MBT) node types. MBT node types are organized here based on the system they are defined into.
Version 1.10
54
Lumberyard Developer Guide
Modular Behavior Tree
It is possible to expose MBT nodes from anywhere in Lumberyard code. A node can have parameters that configure the behavior of its execution. If an invalid value is passed to the node, causing the node's parsing to fail, an error message is written to either
Editor.log
or
Game.log
.
Node Index
•
•
•
•
•
•
•
•
•
•
•
•
•
AimAroundWhileUsingAMachingGun (p. 62)
•
•
•
•
•
•
•
CheckIfTargetCanBeReached (p. 65)
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
•
Version 1.10
55
Lumberyard Developer Guide
Modular Behavior Tree
•
•
•
•
•
SmartObjectStatesWrapper (p. 76)
•
•
•
•
•
•
•
InflateAgentCollisionRadiusUsingPhysicsTrick (p. 79)
•
•
•
•
•
•
•
WaitAlignedWithAttentionTarget (p. 84)
•
•
FlyForceAttentionTarget (p. 86)
•
•
•
•
•
Generic Nodes
These nodes provide the basic functionality of MBT.
Loop
Executes a single child node a specified number of times or until the child fails its execution.
Parameters
count
Maximum number of times the child node will be executed. If left blank, it is assumed to be infinite and the node will continue running until failure.
Version 1.10
56
Lumberyard Developer Guide
Modular Behavior Tree
Success/Failure
The node SUCCEEDS if the maximum number of repetitions is reached. The node FAILS if execution of the child node FAILS.
Example
<Loop count="3">
<SomeChildNode />
</Loop>
LoopUntilSuccess
Executes a child node a specified number of times or until the child node succeeds its execution.
Parameters
attemptCount
Maximum number of times the child node will be executed. If left blank or set to <=0, it is assumed to be infinite and the node will continue running until success.
Success/Failure
The node SUCCEEDS if the child SUCCEEDS. The node FAILS if the maximum amount of allowed attempts is reached.
Example
<LoopUntilSuccess attemptCount="5">
<SomeChildNode />
</LoopUntilSuccess>
Parallel
Executes its child nodes in parallel.
Note
• A maximum number of 32 child nodes is allowed.
• When success and failure limits are reached at the same time, the node will succeed.
Parameters
failureMode
Method to use to evaluate when the node fails. Acceptable values include "any" or "all". Default:
"any".
successMode
Method to use to evaluate when the node succeeds. Acceptable values include "any" or "all". Default:
"all".
Success/Failure
When successMode
is set to "all", the node SUCCEEDS if all the child nodes SUCCEEDS.
Version 1.10
57
Lumberyard Developer Guide
Modular Behavior Tree
When successMode
is set to "any", the node SUCCEEDS if any of the child nodes SUCCEED.
When failureMode
is set to "any", the node FAILS if any of the child nodes FAILS.
When failureMode
is set to "all", the node FAILS if all of the child nodes FAIL.
Example
<Parallel successMode="any" failureMode="all">
<SomeChildNode1 />
<SomeChildNode2 />
<SomeChildNode3 />
</Parallel>
Selector
Executes its child nodes consecutively, one at a time, stopping at the first one that succeeds.
Parameters
None.
Success/Failure
The node executes the child nodes in sequential order and SUCCEEDS as soon as one of the child
SUCCEEDS. Once the node succeeds, the child nodes that follow are not executed. The node FAILS if all the child nodes FAIL.
Example
<Selector>
<SomeChildNode1 />
<SomeChildNode2ToExecuteIfSomeChildNode1Fails />
<SomeChildNode3ToExecuteIfSomeChildNode2Fails />
</Selector>
Sequence
Executes its child nodes one at a time in order.
Note
A maximum of 255 child nodes is allowed.
Parameters
None.
Success/Failure
The node SUCCEEDS if all the child nodes SUCCEED. The node FAILS if any of the child nodes FAILS.
Example
<Sequence>
<SomeChildNode1 />
<SomeChildNode2 />
<SomeChildNode3 />
</Sequence>
Version 1.10
58
Lumberyard Developer Guide
Modular Behavior Tree
StateMachine
Executes child nodes of type
State
one at a time. The first child node defined is the first to be executed.
The current status of a StateMachine node is the same as that of the child that is currently being executed.
Parameters
None.
Success/Failure
The node SUCCEEDS if the current State child node SUCCEEDS. The node FAILS if the current State child node FAILS.
Example
<StateMachine>
<State />
<State name="State1" />
<State name="State2" />
</StateMachine>
State & Transitions
Executes the content of its BehaviorTree node. This node can transition to another state (or itself). If a
State node is instructed to transition into itself while running, it will first be terminated, re-initialized, and then updated again.
A State node has the following characteristics:
• Is a basic block of a StateMachine node.
• MUST have a BehaviorTree node.
• MAY have a Transitions element.
Transitions
Transitions elements are described inside a State node, and can contain the definitions of as many transitions as are needed. The transitions elements are not MBT nodes. If a transition specifies a destination state that doesn't exist, an error message will be displayed when parsing the MBT node.
Parameters
<State />
elements must include the following parameters:
name
Name of the state. It must be unique within the scope of the StateMachine it is in.
<Transition />
elements must include the following parameters:
onEvent
Name of the event that may cause the transition to happen. These events are of type AISignal.
to
Name of the state to transition to.
Version 1.10
59
Lumberyard Developer Guide
Modular Behavior Tree
Success/Failure
The node SUCCEEDS if the content of the BehaviorTree node SUCCEEDS.
The node FAILS if the content of the BehaviorTree node FAILS.
Example
<State name="StateName">
<Transitions>
<Transition onEvent="EventOrTransitionSignalName" to="OtherStateName" />
</Transitions>
<BehaviorTree>
<SomeChildNode />
</BehaviorTree>
</State>
SuppressFailure
Owns and executes one child node. This node will succeed regardless of whether the child node succeeds.
Parameters
None.
Success/Failure
The node always SUCCEEDS once the child node has been executed.
Example
<SuppressFailure>
<SomeChildThatCanFail />
</SuppressFailure>
Timeout
Fails once a certain amount of time has passed.
Parameters
duration
Amount of time (in seconds) before failure occurs.
Success/Failure
The node FAILS if it runs for more than the amount of time specified in the duration
parameter.
Example
<Timeout duration=5" />
Wait
Succeeds once a certain amount of time has passed.
Version 1.10
60
Lumberyard Developer Guide
Modular Behavior Tree
Parameters
duration
Amount of time (in seconds) before the request succeeds.
variation
Maximum additional amount of time that may be randomly added to the value of duration
, in the range [0, variation
]. Setting this value causes the wait time to have random variations between different executions of the node.
Success/Failure
The node SUCCEEDS once it has run the duration specified (plus random variation).
Example
<Wait duration="5" variation="1" />
AI Nodes
These nodes provide MBT functionality for the AI system.
AdjustCoverStance
Updates the AI agent's cover stance based on the maximum height at which its current cover is effective.
Parameters
duration
(Optional) Length of time (in seconds) the node will execute. Set to
continuous
to specify an unlimited time span.
variation
(Optional) Maximum additional time (in seconds) that may be randomly added to the value of duration
, in the range [0, variation
]. Setting this value causes the wait time to have random variations between different executions of the node.
Success/Failure
The node SUCCEEDS if execution of the child runs the length of the specified duration. The node FAILS if the child is not in cover.
Example
<AdjustCoverStance duration="5.0" variation="1.0"/>
Aim
Sets a location for the AI agent to aim at, and then clears the location when the node stops executing.
Parameters
at
Location to aim at. Allowed values include:
Version 1.10
61
Lumberyard Developer Guide
Modular Behavior Tree
• RefPoint
• Target
angleThreshold
(Optional) Tolerance angle for aim accuracy.
durationOnceWithinThreshold
(Optional) Amount of time (in seconds) to continue aiming.
Success/Failure
The node SUCCEEDS after aiming at the desired location for the specified duration, if the location is not valid or if the timeout elapses.
Example
<Aim at="Target" durationOnceWithinThreshold="2.0" />
AimAroundWhileUsingAMachingGun
Updates the aim direction of the AI agent when using a mounted machine gun.
Parameters
maxAngleRange
(Optional) Maximum angle to deviate from the original direction.
minSecondsBeweenUpdates
(Optional) Minimum amount of delay (in seconds) between updates.
useReferencePointForInitialDirectionAndPivotPosition
Boolean.
Success/Failure
The node does not succeed or fail.
Example
<AimAroundWhileUsingAMachingGun minSecondsBeweenUpdates="2.5" maxAngleRange="30"
useReferencePointForInitialDirectionAndPivotPosition="1"/>
Animate
Sets the AI agent to play an animation.
Parameters
name
Animation to be played.
urgent
(Optional) Boolean indicating whether or not to add the urgent flag to the animation.
Version 1.10
62
Lumberyard Developer Guide
Modular Behavior Tree
loop
(Optional) Boolean indicating whether or not to add the loop flag to the animation.
setBodyDirectionTowardsAttentionTarget
(Optional) Boolean indicating whether or not to change the AI's body target direction to face the attention target.
Success/Failure
The node SUCCEEDS when the animation has finished playing, or if the animation failed to be initialized.
Example
<Animate name="LookAround" loop="1" />
AnimationTagWrapper
Adds an animation tag to the execution of a child node and clears it at the end.
Parameters
name
Animation tag to be set.
Success/Failure
The node returns the result of the execution of its child node.
Example
<AnimationTagWrapper name="ShootFromHip">
<Shoot at="Target" stance="Stand" duration="5" fireMode="Burst" />
</AnimationTagWrapper>
AssertCondition
Checks whether or not a specified condition is satisfied.
Parameters
condition
Condition to be checked.
Success/Failure
The node SUCCEEDS if the condition is true, otherwise it FAILS.
Example
<AssertCondition condition="HasTarget" />
Version 1.10
63
Lumberyard Developer Guide
Modular Behavior Tree
AssertLua
Executes a Lua script that returns true/false and translates the return value to success/failure. The result can be used to build preconditions in the MBT.
Parameters
code
Lua script to be executed.
Success/Failure
The node SUCCEEDS if the Lua script returns a value of true, otherwise it FAILS.
Example
<AssertLua code="return entity:IsClosestToTargetInGroup()" />
AssertTime
Checks whether or not a time condition is satisfied.
Parameters
since
Name of the time stamp to check for the condition.
isMoreThan
Condition statement used to test whether the time stamp is greater than a specified value. Cannot be used with the parameter isLessThan
.
isLessThan
Condition statement used to test whether the time stamp is less than a specified value. Cannot be used with the parameter isMoreThan
.
orNeverBeenSet
(Optional) Boolean indicating whether or not to set the node to succeed if the time stamp was never set.
Success/Failure
The node SUCCEEDS if the time condition is true, and FAILS if it is false. If the specified time stamp was not previously set, the node FAILS, unless the parameter orNeverBeenSet
is true, in which case it
SUCCEEDS.
Example
<AssertTime since="GroupLostSightOfTarget" isLessThan="10" orNeverBeenSet="1" />
Bubble
Displays a message in a speech bubble above the AI agent. See AI Bubbles System (p. 20) .
Version 1.10
64
Lumberyard Developer Guide
Modular Behavior Tree
Parameters
message
Message string to be shown in the speech bubble.
duration
Number of seconds to display the message. Default is 0.0.
balloon log
Boolean indicating whether or not to display the message in a balloon above the AI agent. Default is true.
Boolean indicating whether or not to write the message to the general purpose log. Default is true.
Success/Failure
The node SUCCEEDS immediately after having queued the message to be displayed.
Example
<Bubble message="MessageToBeDisplayedAndOrLogged" duration="5.0" balloon="true"
log="true" />
CheckIfTargetCanBeReached
Checks whether or not the AI agent's attention target can be reached.
Parameters
mode
Target to check for. Allowed values include:
• UseLiveTarget
• UseAttentionTarget
Success/Failure
The node SUCCEEDS if the target can be reached, otherwise it FAILS.
Example
<CheckIfTargetCanBeReached mode="UseLiveTarget" />
ClearTargets
Clears the AI agent's targets information.
Parameters
None.
Success/Failure
The node always SUCCEEDS.
Version 1.10
65
Lumberyard Developer Guide
Modular Behavior Tree
Example
<ClearTargets />
Communicate
Sends a request to the communication manager to play one of the AI agent's communications. See
Communication System (p. 38) .
Parameters
name
The name of the communication to be played.
channel
The channel on which the communication is to be set.
waitUntilFinished
(Optional) Specifies if the execution should wait for the end of the communication before finishing.
timeout
(Optional) The threshold defining the maximum amount of seconds the node will wait.
expiry
(Optional) The amount of seconds the communication can wait for the channel to be clear.
minSilence
(Optional) The amount of seconds the channel will be silenced after the communication is played.
ignoreSound
(Optional) Sets the sound component of the communication to be ignored.
ignoreAnim
(Optional) Sets the animation component of the communication to be ignored.
Success/Failure
If the node is set to wait, the node SUCCEEDS when the communication is complete. Otherwise, it
SUCCEEDS once the timeout elapses.
Example
<Communicate name="Advancing" channel="Tactic" expiry="1.0" waitUntilFinished="0" />
ExecuteLua
Executes a Lua script.
Parameters
code
Script to be executed.
Version 1.10
66
Lumberyard Developer Guide
Modular Behavior Tree
Success/Failure
The node always SUCCEEDS.
Example
<ExecuteLua code="entity:SetEyeColor(entity.EyeColors.Relaxed)" />
GroupScope
Makes execution of a child node conditional on entering the AI agent in a group scope. Groups allow a limited number of concurrent users.
Parameters
name
Name of the group scope to enter.
allowedConcurrentUsers
(Optional) Maximum number of simultaneous users allowed in the specified group scope.
Success/Failure
The node FAILS if the AI agent cannot enter the group scope; otherwise, it returns the result of executing the child node.
Example
<GroupScope name="DeadBodyInvestigator" allowedConcurrentUsers="1">
<SendTransitionSignal name="GoToPrepareToInvestigateDeadBody" />
</GroupScope>
IfCondition
Executes a child node if a specified condition is satisfied.
Parameters
condition
Condition statement to be checked.
Success/Failure
If the condition is satisfied, the node returns the result of executing the child node. If the condition is not satisfied, the node FAILS.
Example
<IfCondition condition="TargetVisible">
<Communicate name="AttackNoise" channel="BattleChatter" expiry="2.0"
waitUntilFinished="1" />
</IfCondition>
IfTime
Executes a child node if a time condition is satisfied.
Version 1.10
67
Lumberyard Developer Guide
Modular Behavior Tree
Parameters
since
Name of the time stamp to check for the condition.
isMoreThan
Condition statement test whether the time stamp is greater than a specified value. Cannot be used with the parameter isLessThan
.
isLessThan
Condition statement test whether the time stamp is less than a specified value. Cannot be used with the parameter isMoreThan
.
orNeverBeenSet
(Optional) Boolean indicating whether or not to set the node to succeed if the time stamp was never set.
Success/Failure
If the time condition is true, the node returns the result of executing the child node. It FAILS if the time condition is false. If the specified time stamp was not previously set, the node FAILS, unless the parameter orNeverBeenSet
is true, in which case it SUCCEEDS.
Example
<IfTime since="FragGrenadeThrownInGroup" isMoreThan="5.0" orNeverBeenSet="1">
<ThrowGrenade type="frag" />
</IfTime>
Log
Adds a message to the AI agent's personal log.
Parameters
message
Message to be logged.
Success/Failure
The node always SUCCEEDS.
Example
<Log message="Investigating suspicious activity." />
Look
Adds a location for the AI agent to look at, and clears it when the node stops executing.
Parameters
at
Location to look at. Allowed values are:
Version 1.10
68
Lumberyard Developer Guide
Modular Behavior Tree
• ClosestGroupMember
• RefPoint
• Target
Success/Failure
This node does not succeed or fail.
Example
<Look at="ClosestGroupMember" />
LuaGate
Executes a child node only if the result from running a Lua script is true.
Parameters
code
Lua script to be executed.
Success/Failure
The node SUCCEEDS if the result of the Lua script is true, and FAILS if the result is not true. On success, the node returns the result of executing the child node.
Example
<LuaGate code="return AI.GetGroupScopeUserCount(entity.id, 'DeadBodyInvestigator') == 0">
<Animate name="AI_SearchLookAround" />
</LuaGate>
LuaWrapper
Runs a Lua script before and/or after the execution of a child node.
Parameters
onEnter
(Optional) Script to be executed at the start.
onExit
(Optional) Script to be executed at the end.
Success/Failure
The node returns the result of executing the child node.
Example
<LuaWrapper onEnter="entity:EnableSearchModule()" onExit="entity:DisableSearchModule()">
<Animate name="AI_SearchLookAround" />
Version 1.10
69
Lumberyard Developer Guide
Modular Behavior Tree
</LuaWrapper>
MonitorCondition
Continuously checks the state of a specified condition.
Parameters
condition
Specifies the condition to be checked.
Success/Failure
The node SUCCEEDS when the condition is satisfied.
Example
<MonitorCondition condition="TargetVisible" />
Move
Moves the AI agent from its current position to a specified destination. If the destination is a target, then the end position is updated if it is not reached when the target moves. See
.
Parameters
speed
Speed of movement. Allowed values include:
• Walk
• Run
• Sprint
stance
Body stance while moving. Allowed values include:
• Relaxed
• Alerted
• Stand (default)
bodyOrientation
Direction the AI agents body should face during the move. Allowed values include:
• FullyTowardsMovementDirection
• FullyTowardsAimOrLook
• HalfwayTowardsAimOrLook (default)
moveToCover
Boolean indicating whether or not the AI agent is moving into cover. Default is false.
turnTowardsMovementDirectionBeforeMovingx
Boolean indicating whether or not the AI agent should first turn to the direction of movement before actually moving. Default is false.
Version 1.10
70
Lumberyard Developer Guide
Modular Behavior Tree
strafe
Boolean indicating whether or not the AI agent is allowed to strafe. Default is false.
glanceInMovementDirection
Boolean indicating whether or not the AI agent can glance in the direction of movement. If false, the
AI agent will always look at its look-at target. Default is false.
to
Movement destination. Allowed values include:
• Target - Current attention target.
• Cover - Current cover position.
• RefPoint - Current reference position.
• LastOp - Position of the last successful position-related operation.
stopWithinDistance
Distance from the target that the AI agent can stop moving. Default is 0.0.
stopDistanceVariation
Maximum additional distance that may be randomly added to the value of stopDistanceVariation
, in the range [0, stopDistanceVariation
]. Setting this value causes the stop distance to vary randomly between different executions of the node. Default is 0.0.
fireMode
Firing style while moving. Allowed values are listed for the
node.
avoidDangers
Boolean indicating whether or not the AI agent should avoid dangers while moving. Default is true.
avoidGroupMates
Boolean indicating whether or not the AI agent should avoid group mates while moving. Default is true.
considerActorsAsPathObstacles
Boolean indicating whether or not an AI agent's pathfinder should avoid actors on the path. Default is false.
lengthToTrimFromThePathEnd
Distance that should be trimmed from a pathfinder path. Use positive values to trim from the path end , or negative values to trim from the path start. Default is 0.0.
Success/Failure
The node SUCCEEDS if the destination is reached. The node FAILS if the destination is deemed unreachable.
Example
<Move to="Target" stance="Alerted" fireMode="Aim" speed="Run" stopWithinDistance="3" />
Priority & Case
Prioritizes to selects from a set of possible child nodes to execute. Within a
<Priority>
node, each child node is listed inside a
<Case>
node, which defines a condition statement. A child node is selected and executed based on (1) the first child to have its condition met, and (2) in the case of ties, the order the
Version 1.10
71
Lumberyard Developer Guide
Modular Behavior Tree child nodes are listed in. All but the last child must have a condition statement; the last child listed is the default case, so it's condition must always be true.
Parameters
The
<Priority>
node has no parameters.
The
<Case>
node has the following parameters:
condition
Condition statement used to prioritize a child node.
Success/Failure
The node returns the result of the executed child node.
Example
<Priority>
<Case condition="TargetInCloseRange and TargetVisible">
<Melee target="AttentionTarget" />
</Case>
<Case>
<Look at="Target" />
</Case>
</Priority>
PullDownThreatLevel
Lower's the AI agent's perception of the target's threat.
Parameters
to
Success/Failure
The node always SUCCEEDS.
Example
<PullDownThreatLevel to="Suspect" />
QueryTPS
Parameters
name
Name of the TPS query to run.
register
Location to store the result of the TPS query. Allowed values include:
Version 1.10
72
Lumberyard Developer Guide
Modular Behavior Tree
• RefPoint
• Cover (default)
Success/Failure
The node SUCCEEDS if the TPS returns a tactical position, or FAILS if it does not find a tactical position.
Example
<QueryTPS name="queryName" register="Cover" />
RandomGate
Executes a child node (or not) based on random chance.
Parameters
opensWithChance
Probability to use to determine whether the child node will be executed. Allowed values include floats 0.0 to 1.0.
Success/Failure
The node FAILS if the child node is not executed. If it is executed, the node SUCCEEDS AND returns the result of the execution of its child node.
Example
<RandomGate opensWithChance="0.5">
<ThrowGrenade type="frag" />
</RandomGate>
SendTransitionSignal
Sends a signal, destined for a state machine node on the behavior tree, with the explicit intent of causing a change of state.
Parameters
name
Name of the signal to be sent.
Success/Failure
This node does not succeed or fail.
Example
<SendTransitionSignal name="LeaveSearch" />
SetAlertness
Sets the AI agent's alertness level.
Version 1.10
73
Lumberyard Developer Guide
Modular Behavior Tree
Parameters
value
Alertness level. Allowed values include integers 0 to 2.
Success/Failure
The node always SUCCEEDS.
Example
<SetAlertness value="1" />
Shoot
Sets the AI agent to shoot at a target or location.
Parameters
duration
Length of time (in seconds) the AI agent should continue shooting.
at
Location to shoot at. Allowed values include:
• AttentionTarget
• ReferencePoint
• LocalSpacePosition
fireMode
Firing style. Allowed values include:
• Off - Do not fire (default).
• Burst - Fire in bursts at living targets only.
• Continuous - Fire continuously at living targets only.
• Forced - Fire continuously at any target.
• Aim - Aim only at any target.
• Secondary - Fire secondary weapon (grenades, etc.).
• SecondarySmoke - Fire smoke grenade.
• Melee - Melee.
• Kill - Shoot at the target without missing, regardless of the AI agent's aggression/attackRange/ accuracy settings.
• BurstWhileMoving - Fire in bursts while moving and too far away from the target.
• PanicSpread - Fire randomly in the general direction of the target.
• BurstDrawFire - Fire in bursts in an attempt to draw enemy fire.
• MeleeForced - Melee without distance restrictions.
• BurstSwipe - Fire in burst aiming for a head shot.
• AimSweep - Maintain aim on the target but don't fire.
• BurstOnce - Fire a single burst.
stance
Body stance while shooting. Allowed values include:
Version 1.10
74
Lumberyard Developer Guide
Modular Behavior Tree
• Relaxed
• Alerted
• Crouch
• Stand
position
(Required if the target is a local space position) Local space position to be used as the target.
stanceToUseIfSlopeIsTooSteep
(Optional) Alternative stance style if the slope exceeds a specified steepness. Allowed values are the same as for stance
.
allowedSlopeNormalDeviationFromUpInDegrees
(Optional) Maximum allowed steepness (in degrees of inclination above horizontal) to set the primary stance. At positions that exceed this slope, the alternative stance is used.
aimObstructedTimeout
(Optional) Length of time (in seconds) the AI agent's aim can be obstructed before the node will fail.
Success/Failure
The node SUCCEEDS if it executes for the specified duration. The node FAILS if the aim is obstructed for longer than the specified timeout.
Example
<Shoot at="Target" stance="Crouch" fireMode="Burst" duration="5"
allowedSlopeNormalDeviationFromUpInDegrees="30" stanceToUseIfSlopeIsTooSteep="Stand" />
ShootFromCover
Sets the AI agent to shoot at the target from cover and adjusts its stance accordingly.
Parameters
duration
Length of time (in seconds) the node should execute.
fireMode
Firing style. Allowed values are listed for the Shoot (p. 74) node.
aimObstructedTimeout
(Optional) Length of time (in seconds) the AI agent's aim can be obstructed before the node will fail.
Success/Failure
The node SUCCEEDS if it executes for the specified duration. The node FAILS if the AI agent is not in cover, if there's no shoot posture, or if the aim is obstructed for longer than the specified timeout.
Example
<ShootFromCover duration="10" fireMode="Burst" aimObstructedTimeout="3" />
Version 1.10
75
Lumberyard Developer Guide
Modular Behavior Tree
Signal
Sends a signal to the AI system. See
.
Parameters
name filter
Name of the signal to be sent.
(Optional) Signal filter to use when sending the signal, which determines which AI agents will receive it.
Success/Failure
The node always SUCCEEDS.
Example
<Signal name="StartedJumpAttack" />
SmartObjectStatesWrapper
Sets the states of certain smart objects immediately before and/or after the execution of a child node.
Parameters
onEnter
(Optional) Smart object states to set at the start.
onExit
(Optional) Smart object states to set at the end.
Success/Failure
The node returns the result of executing the child node.
Example
<SmartObjectStatesWrapper onEnter="InSearch" onExit="-InSearch">
<Animate name="LookAround" />
</SmartObjectStatesWrapper>
Stance
Sets the stance of the AI agent.
Parameters
name
Primary stance style. Allowed values include:
• Relaxed
• Alerted
Version 1.10
76
Lumberyard Developer Guide
Modular Behavior Tree
• Crouch
• Stand
stanceToUseIfSlopeIsTooSteep
(Optional) Alternative stance style if the slope exceeds a specified steepness. Allowed values are the same as for stance
.
allowedSlopeNormalDeviationFromUpInDegrees
(Optional) Maximum allowed steepness (in degrees of inclination above horizontal) to set the primary stance. At positions that exceed this slope, the alternative stance is used.
Success/Failure
The node always SUCCEEDS.
Example
<Stance name="Crouch" allowedSlopeNormalDeviationFromUpInDegrees="30"
stanceToUseIfSlopeIsTooSteep="Stand" />
StopMovement
Sends a request to the Movement system to stop all movements. See
.
Note
This may not immediately stop the AI agent The Movement system may be dependent on animations and physics that dictate a 'natural' stop rather than an immediate cessation of movement.
Parameters
waitUntilStopped
Boolean indicating whether or not the node should wait for the Movement System to finish processing the request.
waitUntilIdleAnimation
Boolean indicating whether or not the node should wait until the Motion_Idle animation fragment begins running in Mannequin.
Success/Failure
The node SUCCEEDS if the stop request has been completed.
Example
<StopMovement waitUntilStopped="1" waitUntilIdleAnimation="0" />
Teleport
Moves the AI agent when both the destination point and source point are outside the camera view.
Parameters
None.
Version 1.10
77
Lumberyard Developer Guide
Modular Behavior Tree
Success/Failure
The node always SUCCEEDS.
Example
<Teleport />
ThrowGrenade
Triggers the AI agent to attempt a grenade throw.
Parameters
timeout type
Maximum length of time (in seconds) to wait for the grenade to be thrown.
Grenade type to throw. Allowed values include:
• emp
• frag
• smoke
Success/Failure
The node SUCCEEDS if a grenade is thrown before it times out, otherwise the node FAILS.
Example
<ThrowGrenade type="emp" timeout="3" />
WaitUntilTime
Executes until a time condition is satisfied.
Parameters
since
Name of the time stamp to check for the condition.
isMoreThan
Condition statement used to test whether the time stamp is greater than a specified value. Cannot be used with the parameter isLessThan
.
isLessThan
Condition statement used to test whether the time stamp is less than a specified value. Cannot be used with the parameter isMoreThan
.
succeedIfNeverBeenSet
(Optional) Boolean indicating whether or not to set the node to succeed if the time stamp was never set.
Version 1.10
78
Lumberyard Developer Guide
Modular Behavior Tree
Success/Failure
The node SUCCEEDS if the time condition is true. If the specified time stamp was not previously set, the node FAILS, unless the parameter succeedIfNeverBeenSet
is true, in which case it SUCCEEDS.
Example
<WaitUntilTime since="BeingShotAt" isMoreThan="7" />
CryAction Nodes
These nodes provide MBT functionality for CryAction features.
AnimateFragment
Plays a Mannequin animation fragment and waits until the animation finishes.
Parameters
name
Name of the animation to play.
Success/Failure
The node SUCCEEDS if the animation is correctly played or if no operation was needed. The node FAILS if an error occurs while trying to queue the animation request.
Example
<AnimateFragment name="SomeFragmentName" />
Game Nodes
These nodes offer game-specific MBT functionality. These allow a game with multiple character types to trigger specific logic and perform actions involving each type's peculiarities. Game-specific nodes not likely to be good for "general use" will probably need customization for each game.
Character types are defined in a Lua file, which contains a table of settings for game nodes.
InflateAgentCollisionRadiusUsingPhysicsTrick
Enlarges an AI agent's capsule radius for collisions with a player. This node employs a trick in the physics system inflate the capsule radius for agent-player collisions while leaving the radius unchanged for collisions between the agent and the world.
Note
This trick is entirely isolated within this node. The node does not clean up after itself, so the capsule remains inflated after it has been used.
This trick works as follows:
1. Sets the player dimensions with the agent-vs.-player collision radius. The physics system is multithreaded, so there's a short wait while until the player dimensions are committed.
2. Periodically inspects the player dimensions to check that the agent-vs.-player collision radius has been successfully committed. This can sometimes fail to happen, such as when the AI agent is in a tight spot and can't inflate.
Version 1.10
79
Lumberyard Developer Guide
Modular Behavior Tree
3. Once the agent-vs.-player radius has been committed, goes into the geometry and sets the capsule's radius in place, using the agent-vs.-world radius. This will not affect the agent-vs.-player dimensions.
Parameters
radiusForAgentVsPlayer
Size of capsule to use when calculating collisions between the AI agent and the player.
radiusForAgentVsWorld
Size of capsule to use when calculating collisions between the AI agent and the world.
Success/Failure
The node does not SUCCEED or FAIL. Once executed, it continues running until it is out of the scope of the executed nodes.
Example
<InflateAgentCollisionRadiusUsingPhysicsTrick radiusForAgentVsPlayer="1.0"
radiusForAgentVsWorld="0.5" />
KeepTargetAtADistance
Keeps the live target at a distance by physically pushing the target away when it is within a specified distance. This node is useful when there is some sort of action close to the player and you want to avoid clipping through the camera. Use of this node is preferable over increasing the AI agent's capsule size, which will also affect how the character fits through tight passages. This node is generally used in parallel with other actions that need to be performed while the player cannot come too close to the AI agent; for example, when playing an animation on the spot that can move the AI agent without moving the locator, causing camera clipping.
Parameters
distance
Minimum distance allowed between the player and the AI agent.
impulsePower
Amount of impulse used to keep the player at least at the minimum distance.
Success/Failure
The node does not SUCCEED or FAIL. Once executed, it continues running until it is out of the scope of the executed nodes.
Example
<KeepTargetAtADistance distance="1.8" impulsePower="1.5" />
Melee
Triggers a melee attack against the AI agent's target. The melee attack is performed if the following condition are satisfied:
Version 1.10
80
Lumberyard Developer Guide
Modular Behavior Tree
• If failIfTargetNotInNavigationMesh
is set, the target must be on a valid walkable position. Some melee animations can move the character to a position outside the navigable area if trying to melee a target outside the navigation mesh.
• If the target is not within the threshold angle specified by the entity Lua value melee.angleThreshold
.
Parameters
target
Target of the melee attack. This parameter could be set with the AI agent's AttentionTarget or a generic RefPoint.
cylinderRadius
Radius of the cylinder used for the collision check of the hit.
hitType
Type of hit that will be reported to the game rules. Default is CGameRules::EHitType::Melee.
failIfTargetNotInNavigationMesh
Boolean indicating whether or not the node should try to melee a target that is outside the navigation mesh.
materialEffect
Name of the material effect used when the melee attack hits the target.
Success/Failure
This node succeeds regardless of whether or not a melee attack is executed and, if it is, whether or not the attack damages the target. This is because a failure in this node is not important for behavior tree logic. If it's important for the game to react to this situation, a fail option can be added.
Example
<Melee target="AttentionTarget" cylinderRadius="1.5" hitType="hitTypeName"
materialEffect="materialEffectName" />
Lua table settings
The Lua table melee
contains the following settings: melee =
{
damage = 400,
hitRange = 1.8,
knockdownChance = 0.1,
impulse = 600,
angleThreshold = 180,
},
damage
Amount of damage a melee attack inflicts on the target.
hitRange
Height of the cylinder used to check whether or not the melee attack can hit the target.
Version 1.10
81
Lumberyard Developer Guide
Modular Behavior Tree
knockdownChance
Probability that a successful melee attack knocks down the player.
impulse
Amount of impulse applied to the player in the case of a successful melee attack.
angleThreshold
Maximum angle allowed between the AI agent's direction of movement and the direction of a path between the AI agent and the target for melee attack to be attempted.
ScorcherDeploy
Manages how the Scorcher character type handles certain activity while deploying or undeploying as part of its shooting phase. This node relies on some external Lua scripts and various signals to work properly, but is useful in obfuscating some common functionality in the AI libraries.
Before and after the node runs, the following Lua functions are called:
EnterScorchTargetPhase() and
LeaveScorchTargetPhase()
. When the node starts running, the "ScorcherScorch" animation tag is requested by Mannequin. When the node stops , if it stops normally, the "ScorcherNormal" tag is requested again. If it is terminated prematurely, it is up to the behavior tree script to define a proper exit strategy, such as requesting the "ScorcherTurtle" tag.
On requesting animation tags, the node waits for the following animation events to be received (this ensures that the transition blend animations are not interrupted):
1. "ScorcherDeployed" – when the scorcher is ready to start firing
2. "ScorcherUndeployed" – when the scorcher is again ready to walk around
The node encapsulates the following child nodes:
RunWhileDeploying
and
RunWhileDeployed
, each of which can contain exactly one child node.
RunWhileDeploying
Causes activity to happen while the Scorcher is in the process of deploying, that is, getting ready for an attack. As an example, this node might be used to control aiming before actually shooting.
The node will continue running until one of the following events occur, after which the node will be forcefully stopped:
•
ScorcherFriendlyFireWarningModule
sends one of these signals to the entity: "OnScorchAreaClear" or
OnScorchAreaNotClearTimeOut"
• Mannequin animation sequence sends a "ScorcherDeployed" signal
• An internal timeout elapses
The node does not support any parameters. The node SUCCEEDS or FAILS depending on whether the child node succeeds or fails. The node is allowed to SUCCEED prematurely.
RunWhileDeployed
Controls actual aiming and firing during an attack. Duration and execution of the attack is controlled via this node.
The node does not support any parameters. The node SUCCEEDS or FAILS depending on whether the child node succeeds or fails. The node is allowed to SUCCEED prematurely. If the node SUCCEEDS, this triggers the parent node to start the undeployment sequence.
Version 1.10
82
Lumberyard Developer Guide
Modular Behavior Tree
Parameters
maxDeployDuration
Length of time (in seconds) to allow the "RunWhileDeploying" child node to run. Default is 2.0.
Success/Failure
The node SUCCEEDS if the entire deploy and undeploy sequence is completed. The node FAILS if either the
RunWhileDeploying
or
RunWhileDeployed
nodes FAILED.
Example
<ScorcherDeploy maxDeployDuration="1.0">
<RunWhileDeploying>
<SomeChildNode>
</RunWhileDeploying>
<RunWhileDeployed>
<SomeOtherChildNode>
</RunWhileDeployed>
</ScorcherDeploy>
SuppressHitReactions
Enables or disables the Hit Reaction system for the AI agent.
Parameters
None.
Success/Failure
The node SUCCEEDS or FAILS based on success of failure of its child node.
Example
<SuppressHitReactions>
<SomeChildNode />
</SuppressHitReactions>
Flying Nodes
These nodes provide MBT functionality related to flying vehicles.
Hover
Causes a flying AI agent to hover at its current position.
Parameters
None.
Success/Failure
The node does not SUCCEED or FAIL. Once executed, it continues running until forced to terminate.
Example
<Hover />
Version 1.10
83
Lumberyard Developer Guide
Modular Behavior Tree
FlyShoot
Allows the AI agent to shoot at its attention target when possible from its current position.
If the AI agent's secondary weapon system is used, the node will only open fire if the weapons are able to hit close enough to the target. Otherwise normal firing rules are applied.
Parameters
useSecondaryWeapon
Boolean indicating whether or not the secondary weapon system (such as rocket launchers) should be used. Default is 0.
Success/Failure
The node does not SUCCEED or FAIL. Once executed, the AI agent continues to shoot until forced to terminate.
Example
<FlyShoot useSecondaryWeapon="1" />
WaitAlignedWithAttentionTarget
Waits until the AI agent is facing its attention target.
Parameters
toleranceDegrees
Maximum angle (in degrees) between the attention target and the forward direction of the AI agent to consider the AI agent to be "facing" the attention target. Allowed values include the range
[0.0,180.0]. Default is 20.0.
Success/Failure
The node SUCCEEDS if the angle between the AI agent's forward direction and its attention target is within the allowed range. The node FAILS if the AI agent has no attention target.
Example
<WaitAlignedWithAttentionTarget toleranceDegrees="40" />
Fly
Allows an AI agent to fly around by following a path. Paths should be assigned to the AI agent using
Flow Graph.
Parameters
desiredSpeed
Speed of movement (in meters per second) along the path to move along the path. Default is 15.0.
pathRadius
Radius of the path (in meters). While flying, the AI agent tries to stay within this distance from the path's line segments. Defaults is 1.0.
Version 1.10
84
Lumberyard Developer Guide
Modular Behavior Tree
lookAheadDistance
Distance (in meters) to look forward along the path for 'attractor points' to fly to. Default is 3.0.
decelerateDistance
Distance (in meters) from the end of the path that the AI agent starts to decelerate. Default is 10.0.
maxStartDistanceAlongNonLoopingPath
Maximum distance (in meters) to look ahead for the closest point to link with another path. This parameter is used to link with non-looping paths; for example, it is useful to prevent the AI agent from snapping to the new path at a position that seems closer but is actually behind a wall after a
U-turn. Defaults is 30.0.
loopAlongPath
Boolean indicating whether or not the AI agent should follow a path in an endless loop. Default is 0.
startPathFromClosestLocation
Boolean indicating at what point the AI agent should start following a path. Default is 0.
• 1 - at its closest position
• 2 - at the first path waypoint
pathEndDistance
Distance (in meters) from the end of the path that this node should start sending arrival notification events. Defaults is 1.0.
goToRefPoint
Boolean indicating whether or not the current reference point should be appended to the end of the path. Default is 0.
Success/Failure
The node SUCCEEDS if the AI agent reached the end of the path. The node FAILS if no valid path was assigned to the AI agent.
Example
<Fly lookaheadDistance="25.0" pathRadius="10.0" decelerateDistance="20.0"
pathEndDistance="1" desiredSpeed="15" maxStartDistanceAlongNonLoopingPath="30"
loopAlongPath="0" goToRefPoint="1" startPathFromClosestLocation="1" />
Lua table settings
The following properties in the AI agent's Lua script table can override the default XML tags. This will allow for changes to be made at run-time through (Flow Graph) scripting.
When Lua variable
Each node tick
Helicopter_Speed
Node activation
Helicopter_Loop
Node activation
Helicopter_StartFromClosestLocation
XML tag
desiredSpeed loopAlongPath startPathFromClosestLocation
Upon arrival, the following events will be emitted:
Version 1.10
85
Lumberyard Developer Guide
Modular Behavior Tree
• ArrivedCloseToPathEnd
• ArrivedAtPathEnd
FlyForceAttentionTarget
Keeps an attention target on a flying vehicle by force. The attention target is acquired during each tick of the node from the
Helicopter_ForcedTargetId
Lua script variable. When the node is deactivated, a
ForceAttentionTargetFinished event is emitted.
Parameters
None.
Success/Failure
The node does not SUCCEED or FAIL. Once executed, it continues to force the attention target until deactivation.
Example
<FlyForceAttentionTarget />
FlyAimAtCombatTarget
Aims a flying AI agent at its target, taking into account special aiming adjustments for weapons.
Parameters
None.
Success/Failure
The node does not SUCCEED or FAIL. Once executed, it continues to force the AI agent to rotate its body towards the attention target until termination.
Example
<FlyAimAtCombatTarget />
HeavyShootMortar
Controls shooting the mortar (or Heavy X-Pak) weapon. It tries to simplify and centralize the precondition check and initialization of the weapon, plus re-selection of the primary weapon.
Parameters
to
(Optional) Shooting target. Allowed values include:
• Target (default)
• Refpoint
fireMode
(Optional) Type of firing. Allowed values include:
• Charge (default)
• BurstMortar
Version 1.10
86
Lumberyard Developer Guide
Modular Behavior Tree
timeout
(Optional) Maximum time (in seconds) to continue shooting. Default is 5.0.
aimingTimeBeforeShooting
(Optional) Time (in seconds) to spend aiming before starting to shoot. Value must be longer than the global timeout. Default is 1.0.
minAllowedDistanceFromTarget
(Optional) Minimum distance (in meters) to the target required to start shooting. Default is 10.0.
Success/Failure
The node FAILS if the weapon is closer to the target than the value of minAllowedDistanceFromTarget
.
The node FAILS if there are obstructions less than two meters in front of the weapon; a cylinder check is done to avoid this. The node FAILS if the timeout is reached. The node SUCCEEDS if the shooting
SUCCEEDS.
Example
<HeavyShootMortar to="RefPoint" fireMode="Charge" aimingTimeBeforeShooting="2"
timeout="7" />
SquadScope
Makes execution of a child node conditional on adding the AI agent to a squad scope. Squads allow a limited number of concurrent users.
Note
The dynamic squad system uses the AI system's cluster detector. This tool is used with
AISquadManager
to group AI agents into dynamic squads.
Parameters
name
Name of the squad scope to enter.
allowedConcurrentUsers
(Optional) Maximum number of simultaneous users allowed in the specified squad scope. Default is
1.
Success/Failure
The node SUCCEEDS when the child SUCCEEDS. The node FAILS if the AI agent can't enter the squad scope or if the child FAILS.
Example
<SquadScope name="SomeScopeName" allowedConcurrentUsers="5">
<SomeChildNode />
</SquadScope>
SendSquadEvent
Sends an event to squad members only.
Version 1.10
87
Lumberyard Developer Guide
Refpoints
Note
The dynamic squad system uses the AI system's cluster detector. This tool is used with
AISquadManager
to group AI agents into dynamic squads.
Parameters
name
Name of the event to be sent.
Success/Failure
The node always SUCCEEDS after sending the event.
Example
<SendSquadEvent name="SomeEventName" />
IfSquadCount
Makes execution of a child node conditional on whether or not the number of squad members meets a specified condition. Although all parameters are optional, at least one parameter must be used.
Note
The dynamic squad system uses the AI system's cluster detector. This tool is used with
AISquadManager
to group AI agents into dynamic squads.
Parameters
isGreaterThan
(Optional) Condition statement used to test whether the number of squad members exceeds a specified value.
isLesserThan
(Optional) Condition statement used to test whether the number of squad members is under a specified value.
equals
(Optional) Condition statement used to test whether the number of squad members exactly equals a specified value.
Success/Failure
The node SUCCEEDS if the number of squad members satisfies the specified condition statement, and
FAILS if not.
Example
<IfSquadCount isGreaterThan="1">
<SomeChildNode />
</IfSquadCount>
A refpoint, or reference point, is a special AI object used by goalpipes. It primarily specifies a position and, as needed, a direction. The following examples illustrate how refpoints are used.
Version 1.10
88
Lumberyard Developer Guide
Refpoints
Example 1: Updating a refpoint involving sub-goalpipes
In this example, a refpoint position is set, and a goalpipe is created containing three goalops: Locate,
Stick, and Signal. Using the refpoint, Locate sets a value called LASTOP, which is used in Stick to pinpoint a destination.
Notice that the goalop Stick is defined as "+stick". This ensures that Stick is grouped with the previous goalop (Locate). As a result, if the interrupting goalpipe affects values that Stick depends on (such as
LASTOP), it will return to the appropriate goalop to update the dependent values.
ACT_GOTO = function(self, entity, sender, data)
if (data and data.point) then
AI.SetRefPointPosition(entity.id, data.point);
-- use dynamically created goal pipe to set approach distance
g_StringTemp1 = "action_goto"..data.fValue;
AI.CreateGoalPipe(g_StringTemp1);
AI.PushGoal(g_StringTemp1, "locate", 0, "refpoint");
AI.PushGoal(g_StringTemp1, "+stick", 1, data.point2.x, AILASTOPRES_USE, 1,
data.fValue); -- noncontinuous stick
AI.PushGoal(g_StringTemp1, "signal", 0, 1, "VEHICLE_GOTO_DONE",
SIGNALFILTER_SENDER);
entity:InsertSubpipe(AIGOALPIPE_SAMEPRIORITY, g_StringTemp1, nil, data.iValue);
end end,
Example 2: Using an AI anchor to set a refpoint
In this example, the Smart Object system spots a relevant AI anchor using
OnBiomassDetected
. This anchor is used to set both the position and direction of the refpoint. As a result, the AI agent walks to the refpoint, turns to the indicated direction, and then selects the next goalpipe.
OnBiomassDetected = function(self, entity, sender, data)
entity:SetTargetBiomass(sender);
entity:SelectPipe(0, "AlienTick_ReachBiomass"); end, function AlienTick_x:SetTargetBiomass(biomass)
self.AI.targetBiomassId = biomass.id;
AI.SetRefPointPosition(self.id, biomass:GetWorldPos());
AI.SetRefPointDirection(self.id, biomass:GetDirectionVector(1)); end
<GoalPipe name="AlienTick_ReachBiomass">
<Speed id="Walk"/>
<Locate name="refpoint"/>
<Stick distance="0.3" useLastOp="true"/>
<Signal name="OnBiomassReached"/>
</GoalPipe>
OnBiomassReached = function(self, entity)
entity.actor:SetForcedLookDir(AI.GetRefPointDirection(entity.id));
entity:SelectPipe(0, "AlienTick_CollectBiomass"); end,
Note
The tag <Group> was not used in this example because this particular goalpipe is not intended to be interrupted (which is not generally the case).
Version 1.10
89
Lumberyard Developer Guide
Signals
The Lumberyard AI system includes a fully customizable Signal system that enables AI entities to communicate with each other. Communication consists of signal events that can be sent by an AI agent to another single agent (including itself), or to a group of AI agents currently active in the game.
This topic describes how to send and receive signals between AI agents.
Signals are sent from an AI agent's behavior to one or more other AI agents using the method
AI:Signal()
.
AI:Signal(Signal_filter, signal_type, *MySignalName*, sender_entity_id);
Signal_filter
Group of AI agents to receive the signal. Allowed values include:
• 0 – AI agent specified with the entity_id parameter (usually but not always the sender itself ).
• SIGNALFILTER_LASTOP – AI agent's last operation target (if it has one).
• SIGNALFILTER_TARGET – AI agent's current attention target.
• SIGNALFILTER_GROUPONLY – All AI agents in the sender's group (same group id) within communication range.
• SIGNALFILTER_SUPERGROUP – All AI agents in the sender's group (same group id) within the whole level.
• SIGNALFILTER_SPECIESONLY – All AI agents of the sender's species within communication range.
• SIGNALFILTER_SUPERSPECIES – All AI agents of the sender's species within the whole level.
• SIGNALFILTER_HALFOFGROUP – Half the AI agents in the sender's group, randomly selected.
• SIGNALFILTER_NEARESTGROUP – Nearest AI agent in the sender's group.
• SIGNALFILTER_NEARESTINCOMM – Nearest AI agent in the sender's group within communication range.
• SIGNALFILTER_ANYONEINCOMM – All AI agents within communication range.
• SIGNALID_READIBILITY – Special signal used to make the recipient perform a readability event
(sound/animation).
signal_type
Type of signal, which determines how the recipient will process it. Allowed values include:
• 1 – Recipient processes signal only if it is enabled and not set to "ignorant" (see
AI:MakePuppetIgnorant
).
• 0 – The entity receiving the signal will process it if it's not set to ignorant.
• -1 – The entity receiving the signal will process it unconditionally.
MySignalName
The actual identifier of the signal. It can be any non-empty string; for the signal recipient, it must exist a function with the same name either in its current behavior, its default behavior or in the
Scripts/AI/Behaviors/Default.lua
script file in order to react to the received signal.
entity_id
The entity id of the signal's recipient. Usually you may want to put entity.id (or self.id if it's called from the entity and not from its behavior), to send the signal to the sender itself, but you can also put any other id there to send the signal to another entity.
Version 1.10
90
Lumberyard Developer Guide
Signals
The action to be performed once a signal is received is defined in a function like this:
MySignalName = function(self, entity, sender)
self
The recipient entity's behavior.
entity
The recipient entity.
sender
The signal's sender.
This function is actually a callback which, exactly like the system events, can be defined in the recipient entity's current behavior, the default idle behavior (if it's not present in current behavior) or in the
Scripts/AI/Behaviors/Default.lua
script file (if not present in the default idle behavior).
As for system events, a signal can be used also to make a character change its behavior; if we add a line like the following in a character file:
Behaviour1 = {
OnEnemySeen = *Behaviour1*,
OnEnemyMemory = *Behaviour2*,
…
MySignalName = *MyNewBehaviour*,
}
This means that if the character is currently in Behaviour1, and receives the signal MySignalName, after having executed the callback function above it will then switch its behavior to MyNewBehaviour.
A typical example is when a player's enemy spots the player: its OnEnemySeen system event is called, and let's suppose he wants to inform his mates (The guys with his same group id). In his default idle behavior (i.e.,
CoverAttack.lua
if the character is Cover), we modify its OnEnemySeen event like this:
OnEnemySeen = function( self, entity, fDistance )
-- called when the enemy sees a living enemy
AI:Signal(SIGNALFILTER_GROUPONLY, 1, "ENEMY_SPOTTED",entity.id); end,
Here we have defined a new signal called ENEMY_SPOTTED.
The next step is to define the callback function. Let's assume the other members in the group have the same character, we then add the callback function to the same idle behavior in which we have just modified OnEnemySeen.
ENEMY_SPOTTED = function (self, entity, sender)
entity:Readability("FIRST_HOSTILE_CONTACT");
entity:InsertSubpipe(0, "DRAW_GUN");
Version 1.10
91
Lumberyard Developer Guide
Signals
End,
This will make the guys (including the signal sender itself, who has the same behavior) change their animation and producing some kind of alert sound (readability), and then draw their gun. Notice that by modifying its idle behavior, we create a default callback which will be executed for any behavior the character is in. Later on, we may want to override this callback in other behaviors. For example, if we wanted the character to react differently whether it's in idle or attack behavior, we'll add the following callback function in the
CoverAttack.lua
file:
ENEMY_SPOTTED = function (self, entity, sender)
entity:SelectPipe(0, "cover_pindown");
End,
Where "cover_pindown" is a goalpipe that makes the guy hide behind the nearest cover place to the target.
We can extend this to other characters: if there are group members with different characters (i.e. Scout,
Rear etc) and we want them to react as well, we must add the ENEMY_SPOTTED callback also to their idle/attack behavior. Finally, we want the guys to switch their behavior from idle to attack if they see an enemy.
We'll then add the following line to the character (
Scripts/AI/Characters/Personalities/Cover.lua
in the example):
CoverIdle = {
…
ENEMY_SPOTTED = *CoverAttack*,
},
If specific signals are to be used in more than one behavior, there is an inheritance mechanism.
Behavior classes can either directly inherit a more general implementation by keyword
Base =
[CRYENGINE:ParentBehaviorName]
or indirectly, as a character's Idle behavior as well as the default behavior (defined in file DEFAULT.lua) are considered as fallback behaviors if a signal is not implemented in the current behavior.
A typical signal handler looks something like this:
OnEnemySeen = function(self, entity, distance)
-- called when the AI sees a living enemy end,
Parameters self (behavior table) and entity (entity table) are passed to every signal. Additional parameters are specific to the signal being used.
See also:
\Game\Scripts\AI\Behaviors\Template.lua
.
Perception Signals
The following signals are sent to AI agents when perception types of their attention targets change.
Note that AITHREAT_SUSPECT < AITHREAT_INTERESTING < AITHREAT_THREATENING <
AITHREAT_AGGRESSIVE.
Version 1.10
92
Lumberyard Developer Guide
Signals
No Target
Name
OnNoTarget
Parameters
Sound
Sound heard (no visible target).
Name
OnSuspectedSoundHeard
Parameters
OnInterestingSoundHeard
OnThreateningSoundHeard
OnEnemyHeard
Description
Attention target is lost
Description
Threat is AITHREAT_SUSPECT
Threat is AITHREAT_INTERESTING
Threat is AITHREAT_THREATENING
Threat is AITHREAT_AGGRESSIVE
Memory
The target is not visible and is in memory.
Name
OnEnemyMemory
OnLostSightOfTarget
OnMemoryMoved
Parameters Description
Threat is AITHREAT_THREATENING
Threat is AITHREAT_AGGRESSIVE
Threat is AITHREAT_AGGRESSIVE and its location or owner has changed
Visual
The target is visible.
Name
OnSuspectedSeen
OnSomethingSeen
OnThreateningSeen
OnEnemySeen
OnObjectSeen
OnExposedToExplosion
OnExplosionDanger
Parameters
distance distance, data data
Version 1.10
93
Description
Threat is AITHREAT_SUSPECT
Threat is AITHREAT_INTERESTING
Threat is AITHREAT_THREATENING
Threat is AITHREAT_AGGRESSIVE
AI sees an object registered for this signal. data.iValue = AI object type (e.g.
AIOBJECT_GRENADE or AIOBJECT_RPG)
AI is affected by explosion at data.point
Destroyable object explodes
Lumberyard Developer Guide
Signals
Awareness of Player
Name
OnPlayerLooking
Parameters
sender, data
OnPlayerSticking
sender
OnPlayerLookingAway
sender
OnPlayerGoingAway
sender
Awareness of Attention Target
Name
OnTargetApproaching
OnTargetFleeing
OnNewAttentionTarget
Parameters
OnAttentionTargetThreatChanged
OnNoTargetVisible
OnNoTargetAwareness
OnSeenByEnemy
sender
Weapon Damage
Name
OnBulletRain
OnDamage
OnEnemyDamage
Parameters
sender sender, data sender, data
Description
Player is looking at the AI for entity.Properties.awarenessOfPlayer seconds.
data.fValue = player distance
Player is staying close to the AI since
<entity.Properties.awarenessOfPlayer> seconds
Player has just stopped looking at the AI
Player has just stopped staying close to the AI
Description
AI is seen by the enemy
Description
Enemy is shooting
AI was damaged by another friendly/unknown AI.
data.id = damaging AI's entity id
AI was damaged by an enemy AI. data.id = damaging enemy's entity id
Proximity
Name
OnCloseContact
OnCloseCollision
Parameters Description
enemy gets at a close distance to an AI (defined by Lua Property "damageRadius" of this AI)
Version 1.10
94
Lumberyard Developer Guide
Signals
Vehicles
Name
OnVehicleDanger
Parameters
sender, data
Description
vehicle is going towards the AI. data.point = vehicle movement direction, data.point2 = AI direction with respect to vehicle
OnEndVehicleDanger
OnTargetTooClose
sender, data sender, data
OnTargetTooFar
OnTargetDead
attention target is too close for the current weapon range (it works only if AI is a vehicle) attention target is too close for the current weapon range (it works only if AI is a vehicle)
User-defined
Custom signals can be sent when an attention target enters or leaves certain ranges. This is configured using the following Lua functions:
AI.ResetRanges(entityID);
AI.AddRange(entityID,range, enterSignal, leaveSignal);
AI.GetRangeState(entityID, rangeID);
AI.ChangeRange(entityID, rangeID, distance);
Weapon-Related Signals
Name
OnLowAmmo
OnMeleeExecuted
OnOutOfAmmo
OnReload
Parameters Description
OnReloadDone
OnReloaded
AI goes into automatic reload after its clip is empty reload is done
Navigation Signals
Pathfinding
Name
OnEndPathOffset
Parameters
sender
OnNoPathFound
sender
Version 1.10
95
Description
AI has requested a path and the end of path is far from the desired destination
AI has requested a path which is not possible
Lumberyard Developer Guide
Signals
Name
OnPathFindAtStart
OnBackOffFailed
OnPathFound
Parameters
sender sender
Description
AI tried to execute a "backoff" goal which failed
AI has requested a path and it's been computed successfully
Steering
Name
OnSteerFailed
Smart Objects
Name
OnEnterNavSO
OnLeaveNavSO
OnUseSmartObject
Navigation Shapes
Name
OnShapeEnabled
OnShapeDisabled
Parameters
Parameters
Description
Description
Parameters
Tactics Signals
Tactical Point System
Name
OnTPSDestNotFound
OnTPSDestFound
OnTPSDestReached
Parameters
Cover
Name
OnHighCover
Description
Description
Parameters
Version 1.10
96
Description
Lumberyard Developer Guide
Signals
Name
OnLowCover
OnMovingToCover
OnMovingInCover
OnEnterCover
OnLeaveCover
OnCoverCompromised
Parameters
Groups Signals
Description
Name
OnGroupChanged
Parameters
Description
Formation
Name
OnNoFormationPoint
Parameters
sender
OnFormationPointReached
OnGetToFormationPointFailed
Description
AI couldn't find a formation point
Group Coordination
Group target is the most threatening target of the group.
Name
OnGroupTargetNone
OnGroupTargetSound
OnGroupTargetMemory
OnGroupTargetVisual
PerformingRole
Parameters
Description
Flow Graph Signals
These are signals sent by corresponding Flow Graph nodes when they are activated.
Version 1.10
97
Lumberyard Developer Guide
Signals
Name
ACT_AIMAT
ACT_ALERTED
ACT_ANIM
ACT_ANIMEX
ACT_CHASETARGET
ACT_DIALOG
ACT_DIALOG_OVER
ACT_DUMMY
ACT_DROP_OBJECT
ACT_ENTERVEHICLE
ACT_EXECUTE
ACT_EXITVEHICLE
ACT_FOLLOW
ACT_FOLLOWPATH
ACT_GRAB_OBJECT
ACT_GOTO
Parameters Description
AI:AIShootAt
AI:AIAlertMe
AI:AIAnim
AI:AIAnimEx
Vehicle:ChaseTarget
AI:ReadabilityDialog (also sent by Dialog System)
Sent by Dialog System
ACT_JOINFORMATION
ACT_SHOOTAT
ACT_USEOBJECT
ACT_VEHICLESTICKPATH
ACT_WEAPONDRAW
ACT_WEAPONHOLSTER
ACT_WEAPONSELECT
Other Signals
Forced Execute
Name
OnForcedExecute
Parameters
Version 1.10
98
Description
AI:AIDropObject
Vehicle:Enter
AI:AIExecute
Vehicle:Exit, Vehicle:Unload
AI:AIFollow
AI:AIFollowPath, AI:AIFollowPathSpeedStance,
Vehicle:FollowPath
AI:AIGrabObject
AI:AIGoto, AI:AIGotoSpeedStance, and the AI
Debugger when the user clicks the middle mouse button.
AI:AIFormationJoin
AI:AIShootAt
AI:AIUseObject
Vehicle:StickPath
AI:AIWeaponDraw
AI:AIWeaponHolster
AI:AIWeaponSelect
Lumberyard Developer Guide
Signals
Animation
Name
AnimationCanceled
Game
Name
OnFallAndPlay
Vehicle-related
Name
OnActorSitDown
Parameters
Parameters
Parameters
Actor has entered a vehicle
Description
Description
Description
Squads
Name
OnSomebodyDied
OnBodyFallSound
OnBodyFallSound
OnUnitDied
OnSquadmateDied
OnPlayerTeamKill
OnUnitBusy
OnPlayerDied
Parameters
Description
Name
OnFriendInWay
URPRISE_ACTION
OnActionDone
Parameters
sender data
Description
AI is trying to fire and another friendly AI is on his line of fire
Version 1.10
99
AI action of this agent was finished.
data.ObjectName is the action name, data.iValue
is 0 if action was cancelled or 1 if it was finished normally, data.id is the entity id of "the object" of the AI action
Lumberyard Developer Guide
Animation Overview
This section describes Lumberyard's Animation system. It includes discussions of key concepts and provides information on working with the system programmatically.
This section includes the following topics:
•
•
•
•
•
•
•
Time in the Animation System (p. 112)
One of Lumberyard’s goals is to push the boundaries of animations, which are all rendered in real time.
Lumberyard provides tools to create both linear and interactive animations:
• Linear animation is the kind of animation seen in movies and cut-scenes, which play as a video.
• Interactive animation is used to convey AI and avatar (player) behavior, with sequences dependent on player choices in gameplay.
There is a big difference between how each type of animation is incorporated into a game, although this difference may not be obvious to the player, who simply sees characters moving on-screen. The key difference is in the decision-making process: who decides what a character on the screen is going to do next?
In linear animation, the decision-making process happens inside the head of the people designing the animation. During this process, an animator has direct control over every single keyframe. They don’t need to deal with collision detection, physics and pathfinding; characters only run into walls or collide with each other when the animator wants them to. AI behavior does not need to react to player behavior; the person who writes the storyboard decides how intelligent or stupid the characters are.
To show interactions between characters, you can put them in motion-capture suits and record their performances.
Version 1.10
100
Lumberyard Developer Guide
Interactive Animations
A linear animation sequence needs to show action from a single camera angle because the audience won't be moving during the animation; as a result, animators don't need to deal with transitions and motion combinations; they control every aspect of the motion clip. Because everything is fixed and predicable, it's possible to guarantee a consistent motion quality. Animators can always go back and adjust details in the scene, such as add or delete keyframes, adjust the lighting, or change the camera position.
The technical challenges with creating linear animation primarily involve rendering issues, such as not dropping the frame rate and ensuring that facial and body animations are in sync.
All linear animations in Lumberyard are created with
Track View
editor.
Creating interactive animations presents significantly tougher challenges. Animators and programmers do not have direct control over a character's on-screen movements. It is not always obvious where and how the decision-making process happens. It is usually a complex combination of AI systems, player input, and sometimes contextual behavior.
By definition, interactive animation is responsive. It looks visibly different depending on an individual user's input and adapts automatically to actions on the screen. Moving from linear animation to interactive animation requires more than just a set of small tweaks or a change in complexity—it requires a completely different technology under the hood. With interactive animation, an animator cannot precisely plan and model a character's behavior. Instead, animators and programmers develop a system that allows them to synthesize motion automatically and define rules for character behavior.
Automatic motion synthesis
is a crucial feature in making animation more interactive. A system that synthesizes motion must be very flexible, because it is difficult to predict the sequence of actions that a character may take, and each action can start at any time.
Imagine, for example, a character moving through an outdoor environment. At a minimum, the designer needs to specify the style, speed, and direction of the character's locomotion. There should also be variations in motion while running uphill or downhill, leaning when running around corners or carrying objects of different sizes and weights—the character should run faster while carrying a pistol than when hefting a rocket launcher. It might also be necessary to interactively control emotional features such as happiness, anger, fear, and tiredness. Additionally, the character may need to perform multiple tasks simultaneously, such as walking in one direction, turning head and eyes to track a bird in another direction, and aiming a gun at a moving object in third direction. Providing unique animation assets for every possible combination and degree of freedom is nearly impossible and would involve an incredibly large amount of data. A mechanism for motion modifications is needed to keep the asset count as low as possible.
Developing such a system involves close collaboration and a tight feedback loop between programmers, animators, and designers. Problems with the behavior and locomotion systems (either responsiveness or motion quality) are usually addressed from several sides.
Interactive animation can be divided into two categories:
Avatar control
and
AI control
. In both cases, animators and programmers have indirect control over the actual behavior of a character in gameplay, because decision making for the character's next action happens elsewhere. Let's take a closer look at the situation in game environments.
An avatar character is controlled by the game player, whose decisions determine all of the avatar's actions. The locomotion system takes the player's input and translates it on the fly into skeleton movements (using procedural and data-driven methods). With avatar control, high responsiveness is the top priority, while motion quality might be limited by the game rules. This means that many well-
Version 1.10
101
Lumberyard Developer Guide
Scripted Animations established rules for 'nice'-looking animations are in direct conflict with the responsiveness you need for certain types of gameplay.
The quality of animations as executed on the screen depends largely on the skills and decisions of each player controlling the character—they decide what the avatar will do next. Because a player's actions are unpredictable, motion planning based on predictions is not possible. Complex emotional control is not possible (and probably not needed). It's only possible on a raw level, such as soft punch versus an aggressive punch. However, it might be possible to let the player control the locomotion of the avatar, and to let the game code control the emotional behavior of the avatar by blending in "additive animations" based on the in-game situation.
In all these scenes, the player is controlling the character with a game pad. The character's presentation on the screen is using animation assets created by animators.
For AI characters, the decision-making process happens entirely inside the game code. Game developers design a system to generate behavior, which acts as an intermediary between the game creators and players. For the system to perform this task, it is necessary for game designers to explicitly specify behavioral decisions and parameters for AI characters, including a clear definition of the rules of movements for each character type. Interactive animation for AI characters is much harder to accomplish than animations for avatars, but at the same time it offers some (not always obvious) opportunities to improve motion quality. High responsiveness is still the primary goal but, because character choices happen inside the game code, it is possible in certain circumstances to predict a character's actions. If the
AI system knows what the AI character wants to do next, then it is possible to incorporate this knowledge into motion planning. With good motion planning, interactive animation might be able to use more classical or 'nice' animation rules. As a result, AI control can have a somewhat higher motion quality than avatar control, though at the cost of having more complex technology under the hood.
The only source of uncertainty in such a prediction system is the player: the AI reacts to the player, and predicting the player's actions is impossible. As a result, it's nearly impossible to create the right assets for every in-game situation, and this in turn makes it impossible to guarantee a consistent motion quality. For an animator working on interactive animation, it can be a significant problem to have no direct control over the final animation—it's never clear when the work is complete. This is one reason why the linear animation in movies and cut-scenes look superior, and why interactive animations can be troublesome.
Lumberyard tackles the problem with interactive animation in multiple levels:
• In the low-level CryAnimation system library, the engine provides support for animation clips, parametrized animation, and procedural modification of poses. Animations can be sequenced together or layered on top of each other in a layered transition queue.
• In the high-level CryAction library, the CryMannequin system helps to manage the complexity of animation variations, transitions between animations, animations that are built up out of many others, sequencing of procedural code, links to game code, and so on.
Because interactive animation is much more difficult than linear animation, many games blur the line between cut-scenes and in-game actions by using interactive scripted sequences.
In this case, characters act on a predefined path. The quality of this kind of motion can be very high.
Because it is not fully interactive, animators have more control over the entire sequence, a kind of manually designed motion planning. These are perfectly reasonable cheats to overcome hard-to-solve animation problems. It may be even possible to script the entire AI sequence to allow near-cut-scene quality. The action feels interactive and looks absolutely cinematic, but it is actually more an illusion of interactivity.
Version 1.10
102
Lumberyard Developer Guide
Animation Events
In the game Crysis, Crytek designers made use of scripted animations in many scenes. In the "Sphere" cut-scene, the Hunter is shown walking uphill and downhill and stepping over obstacles. This is a scripted sequence where the assets were made for walking on flat ground, but Crytek used CCD-IK to adapt the character's legs to the uneven terrain. In the "Fleet" cut-scene with the Hunter on the carrier deck, the player can move around while the Hunter is fighting other non-playing characters.
Both scenes look and feel highly interactive but they are not. The Hunter doesn't respond to the player and the player cannot fight the Hunter. The scenes are fully linear and scripted, basically just animated background graphics. These sequences were created in
Track View
editor. Some of them used the Flow
Graph Editor. When the cut-scene is over, the Hunter turns into an AI-controlled interactive character.
Animations in Lumberyard can be marked up to send custom events at a specific time in an animation.
This markup is used for time-aligned blending; for example, to match footplants in animations. Another application of animation events is to spawn particle effects at the right moment.
These events can also be used by a variety of systems that need to receive information about when an animation has reached a certain point, such as in combination with a melee system.
Events for animations are stored in an XML file that is loaded when the character starts up. For this to happen automatically, the database must be included in the chrparams
file.
Animation events are passed on to the game object once they have been triggered. The Actor and Player implementations both handle these animation events. See either
Actor.cpp
or
Player.cpp
for the function: void AnimationEvent(ICharacterInstance *pCharacter, const AnimEventInstance &event)
Lumberyard's animation system allows the setup of IK chains for characters.
When an IK chain is active, the system calculates the joint angles in the chain so that the end effector
(typically a hand or foot) reaches the target position.
IK chains are defined in the chrparams
file.
To activate a Limb IK chain from outside the Animation system, use the function
SetHumanLimbIK
, accessible through the
ISkeletonPose
interface. The
SetHumanLimbIK
function needs to be called in each frame in which you want the IK chain to be active. The name of the Limb IK chain is defined in the chrparams
file:
Version 1.10
103
Lumberyard Developer Guide
Animation Streaming
ISkeletonPose& skeletonPose = ...; skeletonPose.SetHumanLimbIK(targetPositionWorldSpace, "RgtArm01");
Animation is very memory-intensive and tends to use a large amount of resources. Limited memory budgets, high numbers of animated joints, and requirements for high animation quality make it wasteful for a project to keep all animations constantly loaded in memory.
Lumberyard's animation system alleviates this issue by streaming in animation resources (file granularity level) when needed, and unloading them when not needed. Streaming of asset files is achieved by using the DGLINK Streaming System . Streaming assets in and out allows the system to keep only the needed resources in memory—which is done at the expense of complexity, as you must now plan how and when animation resources are used.
Animation data usage is divided into two main sections:
• The
header
section contains generic information for an animation (filename, duration, flags, etc).
• The
controller
section contains the animation curves. For each joint involved, this section contains information on all the position and orientation values that the joint needs in order to play that animation. Even when compressed, controller data can easily take up more than 95% of the total memory required for an animation.
Header data for animations is stored in
CAF
files and in the animations.img
file.
CAF
files contain the header information on a single animation, while animations.img
contains header information for all animations in the build. The animations.img
is obtained as a result of processing all the animations with the Resource Compiler.
The engine usually loads all the animation files' headers from the animations.img
file instead of loading from individual files (reading the information from individual files can considerably slow down loading time).
Because of the extreme size difference between controllers and headers, Lumberyard streams only the controller data in and out of memory. The header data for all animations is kept at all times in memory, as it is practical to have that information available at all times.
Note
During development—for example, when working with local animation files—you must disable usage of animations.img
and load the header information from individual
CAF
files instead. To do so, set the ca_UseIMG_CAF
console variable to 0 before the engine starts.
The controller data for animations is stored in CAF files or DBA files.
•
CAF
files contain controller information for a single animation.
•
DBA
files contain controller information for a group of animations.
Version 1.10
104
Lumberyard Developer Guide
Animation Controller Data
When a DBA is loaded, controllers for all animations contained in that DBA are available until the DBA is unloaded. For this reason, it is useful to group animations that are used together in the same DBA. An extra benefit of putting similar animations together in a DBA is that equal controllers are only stored once. This reduces the memory usage of your animations.
The animation system properly plays animations only when their controllers are in memory.
If controller data is not available when playback of an asset is requested, the animation system streams it in from disk. Streaming of controller data is performed asynchronously—the animation system does not wait until after asset playback is requested. This prevents stalling the system.
If high level systems fail to notify the animation system that they require controller data (see the preload functions section), the animation system does not know that an asset is required until it is requested to play. This is dangerously close to when the controller data is needed. If the controller data is not available in time, it typically leads to visual glitches, which can sometimes be observed, for example, only the first time an animation is played.
Therefore, it is important to have controller data streamed in before playback of an animation is requested. This minimizes undesired glitches that occur while waiting for animation streaming to end.
The amount of time required for streaming to complete depends on many factors, such as the current system load, streaming speed of the target system, size of the resource that needs to be loaded, and so on.
The animation system will not unload controller data that is currently in use.
It is possible to prevent unloading of animation data entirely by setting ca_DisableAnimationUnloading to 1.
Controllers in
CAF
files are unloaded after the system detects that they are no longer in use. To prevent controllers in CAF files from being unloaded, set ca_UnloadAnimationCAF
to 0.
Controllers in DBA files remain in memory until a certain amount of time passes after the animations in them are used. However, if the DBA is locked, controllers are not unloaded until the lock status is set back to 0.
To change the time that the animation system waits to unload controllers in DBA files, use the following cvars
:
• ca_DBAUnloadUnregisterTime
– Timeout in seconds after the last usage of a controller and all animations using that DBA; when this timeout is reached, the DBA marks their controller data as
'unloaded'.
• ca_DBAUnloadRemoveTime
– Timeout in seconds after the last usage of a controller in a DBA; when this timeout is reached, the DBA performs an actual unload from memory. This value should be greater than or equal to ca_DBAUnloadUnregisterTime
.
The following section describes how to lock individual resources in memory to prevent the system from unloading them.
Preload functions are performed by high level systems or user code (usually game code), as these contain most of the information on when and how assets are accessed. For example, trackview looks a number of seconds ahead in the timeline for any animations that appear, and calls the preload functions.
Version 1.10
105
Lumberyard Developer Guide
Animation Debugging
Preloading Controllers in DBA files
To preload and trigger the streaming of a
DBA
file: gEnv->pCharacterManager->DBA_PreLoad(dbaFilename, priority);
To trigger the streaming of a
DBA
file, and request a change to the locked state (which specifies whether it should be locked in memory): gEnv->pCharacterManager->DBA_LockStatus(dbaFilename, lockStatus, priority);
To unload all controller data in a DBA from memory (unloads data only if none of the controllers are currently being used): gEnv->pCharacterManager->DBA_Unload(dbaFilename);
Note
To make the system automatically load and lock a DBA file while a character is loaded, use the flags="persistent"
in the chrparams
file.
Preloading Controllers in CAF files
To increase the reference count of a
CAF
file: gEnv->pCharacterManager->CAF_AddRef(lowercaseAnimationPathCRC);
Controllers for a
CAF
file start streaming in when its reference count goes from 0 to 1.
To decrease the reference count of a
CAF
file: gEnv->pCharacterManager->CAF_Release(lowercaseAnimationPathCRC);
Controllers for a
CAF
file are unloaded by the animation system only after the reference count reaches 0
(the animation system, when playing a CAF file, also increases this reference count, so that an animation is not unloaded while in use).
To check whether the controllers for a
CAF
file are loaded: gEnv->pCharacterManager->CAF_IsLoaded(lowercaseAnimationPathCRC);
To synchronously load the controllers for a CAF file: gEnv->pCharacterManager->CAF_LoadSynchronously(lowercaseAnimationPathCRC);
Synchronously loading CAF assets is strongly discouraged unless absolutely necessary, as it will likely result in stalls.
Several tools are available for debugging animation issues.
Version 1.10
106
Lumberyard Developer Guide
Layered Transition Queue Debugging
You can enable on-screen debug information to see which animations are queued and playing, as well as information about the applied pose modifiers and IK.
To show the transition queue for all the character instances of a specified entity: es_debuganim <entityname> [0 | 1]
<entityname>
Name of the entity to debug. In a single player game, the player is typically called "dude." Note that the GameSDK example player has both a first person and a third person character instance.
[0 | 1]
Specify 1 or no second parameter to turn it on for this specific entity. Specify 0 to turn it off.
Examples
To turn on debugging for a player with the entity name "dude": es_debuganim dude 1
To turn off debugging for an entity called "npc_flanker_01": es_debuganim npc_flanker_01 0
You can show the transition queue for all character instances or the ones that have a specific model name.
ca_debugtext [<modelname-substring> | 1 | 0]
<modelname-substring>
Shows information for all character instances whose modelname contains the specified string.
[0 | 1]
If 1 is specified, all character instances are shown. If 0 is specified, the debug text is turned off.
Examples
To show information on all character instances with "player" in their model name: ca_debugtext player
To turn off all transition queue information:
Version 1.10
107
Lumberyard Developer Guide
Layered Transition Queue Debugging ca_debugtext 0
Each animation in the transition queue is displayed as in the following example. Key elements of this display are described following the example.
AnimInAFIFO 02: t:1043 _stand_tac_idle_scar_3p_01 ATime:0.84 (1.17s/1.40s) ASpd:1.00
Flag:00000042 (----------I-K----) TTime:0.20 TWght:1.00 seg:00 inmem:1
(Try)UseAimIK: 1 AimIKBlend: 1.00 AimIKInfluence: 1.00 (Try)UseLookIK: 0 LookIKBlend: 0.00
LookIKInfluence: 0.00
MoveSpeed: 4.49 locked: 1
PM class: AnimationPoseModifier_OperatorQueue, name: Unknown
...
LayerBlendWeight: 1.00
...
ADIK Bip01 RHand2RiflePos_IKTarget: 0.24 Bip01 RHand2Aim_IKTarget: 1.00 Bip01
LHand2Aim_IKTarget: 0.00
Text Color
• When an animation is not yet active, it is in black or green.
• When an animation is active, it is in red or yellow.
Or in detail:
• Red Channel = Animation Weight
• Green Channel = (layerIndex > 0)
• Alpha Channel = (Weight + 1)*0.5
AnimInAFIFO Line (one per animation)
AnimInAFIFO 02: t:1043 _stand_tac_idle_scar_3p_01 ATime:0.84 (1.17s/1.40s) ASpd:1.00
Flag:00000042 (----------I-K----) TTime:0.20 TWght:1.00 seg:00 inmem:1
AnimInAFIFO 02
Layer index (decimal, zero-based)
t:1043
User token (decimal)
_stand_tac_idle_scar_3p_01
Animation name (alias) of the currently playing animation, aim/look-pose or bspace
ATime:0.84 (1.17s/1.40s)
ATime:XXXX (YYYYs/ZZZZs)
• XXXX = Current time in 'normalized time' (0.0...1.0) within the current segment
• YYYY = Current time (seconds) within the current segment
• ZZZZ = Expected duration (seconds) of the current segment
ASpd:1.00
Current animation speed (1.0 = normal speed)
Version 1.10
108
I n
S
F x
3
char
b
V
+ y
R
L
M
A
K
T
flag
Lumberyard Developer Guide
Layered Transition Queue Debugging
Flag:00000042 (----------I-K----)
Animation Flags
Flag:XXXXXXXX (+ybVFx3nSIAKTRLM)
The first number is the animation flags in hexadecimal
Between parentheses you see the individual flags:
CA_FORCE_TRANSITION_TO_ANIM
CA_FULL_ROOT_PRIORITY
CA_REMOVE_FROM_FIFO
CA_TRACK_VIEW_EXCLUSIVE
CA_FORCE_SKELETON_UPDATE
CA_DISABLE_MULTILAYER
CA_KEYFRAME_SAMPLE_30Hz
CA_ALLOW_ANIM_RESTART
CA_MOVE2IDLE
CA_IDLE2MOVE
CA_START_AFTER
CA_START_AT_KEYTIME
CA_TRANSITION_TIMEWARPING
CA_REPEAT_LAST_KEY
CA_LOOP_ANIMATION
CA_MANUAL_UPDATE
value
0x008000
0x004000
0x002000
0x001000
0x000800
0x000400
0x000200
0x000100
0x000080
0x000040
0x000020
0x000010
0x000008
0x000004
0x000002
0x000001
TTime:0.20
Transition Time
Total length of transition into this animation in seconds (this is static after pushing the animation)
TWght:1.00
Transition Weight
Current weight of this animation within the transition (0 = not faded in yet, 1 = fully faded in)
seg:00
Current segment index (zero-based)
inmem:1
Whether or not the animation is in memory (0 basically means it's not streamed in yet)
Version 1.10
109
Lumberyard Developer Guide
Layered Transition Queue Debugging
Aim/Look-IK Line
(Try)UseAimIK: 1 AimIKBlend: 1.00 AimIKInfluence: 1.00 (Try)UseLookIK: 0 LookIKBlend: 0.00
LookIKInfluence: 0.00
(Try)UseAimIK: 1
Whether Aim IK is turned on or not (set using PoseBlenderAim::SetState)
AimIKBlend: 1.00
Weight value requested for Aim IK (could go up and down based on fade times, etc.)
AimIKInfluence: 1.00
Final influence weight value of AimIK (== smoothed(clamped(AimIKBlend)) * weightOfAllAimPoses)
(Try)UseLookIK: 0
Whether Look IK is turned on or not
LookIKBlend: 0.00
Weight value requested for Look IK (could go up and down based on fade times, etc.)
LookIKInfluence: 0.00
Final influence weight value of LookIK (== smoothed(clamped(LookIKBlend)) * weightOfAllLookPoses)
Parameter Line(s) (only for blend spaces)
MoveSpeed: 4.500000 locked: 1
TravelAngle: 0.000000 locked: 0
MoveSpeed: 4.500000
Value for the specified blend space parameter (MoveSpeed in this case)
locked: 1
Whether or not the parameter is locked (= unable to change after it is set for the first time)
PoseModifier Lines (if running)
PM class: AnimationPoseModifier_OperatorQueue, name: Unknown
Displays which pose modifiers are running in this layer. Shows the class as well as the name (if available).
LayerBlendWeight Line (not on layer 0)
LayerBlendWeight: 1.00
The weight of this layer (0.00 - 1.00)
ADIK Line(s) (only if animation driven IK is applied)
ADIK Bip01 RHand2RiflePos_IKTarget: 0.24 Bip01 RHand2Aim_IKTarget: 1.00 Bip01
LHand2Aim_IKTarget: 0.00
Version 1.10
110
Lumberyard Developer Guide
CommandBuffer Debugging
Displays a list of the animation driven IK targets and their current weight. For more detailed position/ rotation information, use the separate cvar ca_debugadiktargets 1
.
At the lowest level, the animation system executes a list of simple commands to construct the final skeleton's pose.
These commands are, for example, "sample animation x at time t, and add the result with weight w to the pose". Or "clear the pose".
To enable on-screen debug information to see what is pushed on the command buffer (for all characters), use the following command: ca_debugcommandbuffer [0 | 1]
To control when the animation system produces warnings using the ca_animWarningLevel cvar: ca_animWarningLevel [0 | 1 | 2 | 3]
0
Non-fatal warnings are off.
1
Warn about illegal requests.
For example, requesting to start animations with an invalid index.
2
Also warn about things like 'performance issues.'
For example, animation-queue filling up. This might 'spam' your console with a dump of the animation queue at the time of the issue.
3 (default)
All warnings are on. This includes the least important warnings; for example, a warning when playing uncompressed animation data.
"Fall and Play" activates when a character is ragdollized (on an interface level, it is called
RelinquishCharacterPhysics
) with a >0 stiffness. This activates angular springs in the physical ragdoll that attempts to bring the joints to the angles specified in the current animation frame. The character also tries to select an animation internally based on the current fall and play stage. If there are none, or very few, physical contacts, this will be a falling animation; otherwise it will be the first frame of a standup animation that corresponds to the current body orientation.
Standup is initiated from outside the animation system through the fall and play function. During the standup, the character physics is switched back into an alive mode and his final physical pose is blended into a corresponding standup animation. This, again, is selected from a standup anims list to best match this pose.
Version 1.10
111
Lumberyard Developer Guide
Time in the Animation System
Filename convention for standup animations: When an animation name starts with "standup", it is registered as a standup animation. Also, a type system exists which categorizes standup animations by the string between "standup_" and some keywords ("back", "stomach", "side"). You can control which type to use with
CSkeletonPose::SetFnPAnimGroup()
methods. At runtime, the engine checks the most similar standup animation registered to the current lying pose and blends to it.
Some example filenames:
• standUp_toCombat_nw_back_01
• standUp_toCombat_nw_stomach_01
While the character is still a ragdoll, it is also possible to turn off the stiffness with a
GoLimp
method.
The Animation system uses different units of 'time,' depending on the system. How those units of time compare is best explained using an example.
The definition of 'frames': The Animation system uses a fixed rate of 30 frames per second (fps). Of course, games can run at higher frame rates, but some operations in the Editor that use the concept of
'frames'—or operations that clamp the animation duration to 'one frame'—assume a frame rate of 30 fps.
Assume then that you have an animation with a duration of 1.5 seconds. This means that the animation has 46 frames (note that this includes the final frame). So, in the case of Real Time, assume an animation starts at time 0, has no segmentation, and is played back at normal speed. However, rather than using
Real Time, the Animation system typically uses Animation Normalized Time. This is compared with Real
Time in the following table:
..
44
45
Frame Index
0
1
..
30
Real Time (seconds)*
0.0 s
0.033.. s = 1/30 s
..
1.0 s
..
1.466.. s = 44/30 s
1.5 s = 45/30 s
Animation Normalized Time**
0.0
0.022.. = 1/45
..
0.666.. = 30/45
..
0.977.. = 44/45
1.0
* Real time is used to define duration:
• Duration = lastFrame.realTime - firstFrame.realTime. That's 1.5s in our example.
•
IAnimationSet::GetDuration_sec()
returns the duration of an animation.
Note
: For a parametric animation, this returns only a crude approximation—the average duration of all its examples, ignoring parameters or speed scaling.
•
CAnimation::GetExpectedTotalDurationSeconds()
returns the duration of an animation that is currently playing back.
Version 1.10
112
Lumberyard Developer Guide
Segmentation
Note
: For a parametric animation, this returns only a crude approximation, assuming the parameters are the ones that are currently set and never change throughout the animation.
• No function exists that returns the Real Time of an animation. To calculate that, you must manually multiply Animation Normalized Time with the duration.
** Animation Normalized Time:
• Time relative to the total length of the animation.
• Starts at 0 at the beginning of the animation and ends at 1 (= RealTime/Duration = Keytime/
LastKeyTime).
• Used by functions such as
ISkeletonAnim::GetAnimationNormalizedTime()
and
ISkeletonAnim::SetAnimationNormalizedTime()
.
• Is not well-defined for parametric animations with examples that have differing numbers of segments.
For more information, see the following section, Segmentation.
In practice, the animation system does not use Animation Normalized Time; this terminology was used to make the introduction easier to understand. Typically, Segment Normalized Time is used. To understand
Segment Normalized Time, you must first understand segmentation.
For time warping (phase matching) purposes, animations can be split into multiple segments. For example, to time warp from a walk animation with 2 cycles to a walk animation with 1 cycle, you have to annotate the first animation and split it into two (these are segments). To achieve this segmentation, you must add a segment1 animation event at the border between the cycles.
Note
An animation without segmentation has exactly 1 segment, which runs from beginning to end.
Segmentation introduces a new unit for time, Segment Normalized Time, which is time relative to the current segment duration.
Extending our example further, observe what happens when a segment1 animation event at 1.0s is added to split the animation into two segments.
Frame Index
0
1
..
30
..
44
45
Real Time
0.0 s
0.033.. s
..
1.0 s
..
1.466.. s
1.5 s
AnimEvents
segment1
(Animation)
Normalized
Time
0.0
0.022..
..
0.666..
..
0.977..
1.0
0
0
..
1
..
1
Segment
Index*
1
Segment
Normalized
Time**
0.0
0.033.. = 1/30
..
0.0
..
0.933.. =
14/15
1.0
* Segment index:
Version 1.10
113
Lumberyard Developer Guide
Playback Speed
• Identifies which segment you are currently in. Runs from 0 to the total number of segments minus 1.
• While an animation is playing, you can use
CAnimation::GetCurrentSegmentIndex()
to retrieve it.
• When using ca_debugtext or es_debuganim, then this index is displayed after "seg:".
** Segment normalized time:
• Time relative to the current segment's duration.
• 0 at the beginning of the segment, 1 at the end (only 1 for the last segment, as you can see in the table).
• While an animation is playing, you can use
CAnimation::Get/SetCurrentSegmentNormalizedTime()
to get or set the Segment Normalized Time.
• As the names suggest,
CAnimation::GetCurrentSegmentIndex()
retrieves the current segment index and
CAnimation::GetCurrentSegmentExpectedDurationSecondsx()
retrieves the duration of the current segment.
• When representing time within parametric animations, it is more convenient to use Segment
Normalized Time than Animation Normalized Time; therefore, Segment Normalized Time is used at runtime.
• AnimEvent time is specified using Animation Normalized Time (except for the special case of parametric animation; see the following section).
• When using ca_debugtext
or es_debuganim
, Segment Normalized Time is displayed after "ATime:".
Following that, the real time within the segment and the segment duration are displayed within the parentheses.
Playback speed does not impact the functions that compute duration of playing animations, such as
CAnimation::GetExpectedTotalDurationSeconds()
or
ISkeletonAnim::CalculateCompleteBlendSpaceDuration()
.
Animation Normalized Time, Segment Index, and Duration all create ambiguity for segmented parametric animations. This is because each example animation within the parametric animation can have its own number of segments. To avoid ambiguity, animation events in or on segmented parametric animations use Segment Normalized Time. As a result, an animation event will be fired multiple times
(once per segment) during the animation.
•
ISkeletonAnim::GetAnimationNormalizedTime()
uses a heuristic: It currently looks for the example animation with the largest number of segments and returns the animation normalized time within that example.
•
ISkeletonAnim::GetCurrentSegmentIndex()
uses a different heuristic: It currently returns the segment index in the example animation, which happens to be the first in the list.
Given this, we are considering redefining the above based on the following observation: You can define the total number of segments in a parametric animation as the number of segments until repetition starts.
So, say you have a parametric animation consisting of 2 examples—one with 2 segments and the other with 3 segments. This will start to repeat after 6 segments (the lowest common multiple of 2 and 3).
However, you can uniquely identify each possible combination of segments using any number from 0 to
5.
Version 1.10
114
Lumberyard Developer Guide
Animation with Only One Key
The Character Tool uses this method to achieve a well-defined duration. The
ISkeletonAnim::CalculateCompleteBlendSpaceDuration()
function calculates the duration until the parametric animation starts to repeat (assuming the parameters remain fixed). It reverts to the regular
GetExpectedTotalDurationSeconds()
implementation for non-parametric animations so that the function can be used in more general situations.
Normally your animations have at least two keys. However, when you convert these into additive animations, the first frame is interpreted as the base from which to calculate the additive, leaving only 1 frame in the additive animation (this means that, in respect to the asset, both the start and end time of the asset are set to 1/30 s).
Functions retrieving the total duration of this animation will return 0.0 (for example,
IAnimationSet::GetDuration_sec()
,
ISkeletonAnim::CalculateCompleteBlendSpaceDuration()
, and
CAnimation::GetExpectedTotalDurationSeconds()
).
However, for playback purposes, the animation system handles these animations as if they have a duration of 1/30th of a second. For example, Animation Normalized
Time still progresses from 0 to 1, while real time goes from 0 to 1/30th of a second.
CAnimation::GetCurrentSegmentExpectedDurationSecondsx()
also returns 1/30th of a second in this case.
Time typically cannot run backward when playing an animation. You can move time backward only if you do it manually by setting the flag
CA_MANUAL_UPDATE
on the animation and using
CAnimation::SetCurrentSegmentNormalizedTime
. See the example DGLINK
CProceduralClipManualUpdateList::UpdateLayerTimes()
.
Different units are used for controllers that contain the actual key data and are used for animation sampling.
..
30
..
Frame Index
0
1
44
45
Real Time
0.0 s
0.033.. s
..
1.0 s
..
1.466.. s
1.5 s
I_CAF Ticks*
0
160
..
4800
..
7040
7200
Keytime**
0.0
1.0
..
30.0
..
44.0
45.0
* I_CAF Ticks:
• Used within I_CAF files to represent time
• There are 4800 I_CAF ticks per second (this is currently expressed by the fact that TICKS_CONVERT =
160 in Controller.h, which assumes 30 keys/second)
Version 1.10
115
Lumberyard Developer Guide
Time within Controllers
** Keytime
• Used at runtime to pass time to the controllers for sampling animation
• Used within CAF files to represent time
• A floating point version of 'frame index'
• Can represent time in between frames
• Use
GlobalAnimationHeaderCAF::NTime2KTime()
to convert from Animation Normalized Time to
Keytime
• All animation controllers in the runtime use Keytime
Animation assets can also have a StartTime other than 0.0s—this complicates matters slightly, but only for the controllers. Typically, for everywhere but the controllers, time is taken relative to this StartTime.
Version 1.10
116
Lumberyard Developer Guide
Builder Modules
You can use the asset builder API to develop a custom asset builder that creates your own asset types.
Your asset builder can process any number of asset types, generate outputs, and return the results to the asset processor for further processing. This can be especially useful in a large project that has custom asset types.
A builder module is a
.dll
module that contains a
lifecycle component
and one or more
builders
. The lifecycle component is derived from
AZ::Component
. The builders can be of any type and have no particular base class requirements.
The job of the lifecycle component is to register its builders during the call to
Activate()
and to make sure that resources that are no longer being used are removed in the calls to
Deactivate
and
Destructor
.
To create a builder module, you must perform the following steps.
• Create the exported
.dll
entry point functions and invoke the
REGISTER_ASSETBUILDER
macro, which creates a forward declaration for the entry point functions.
• Register your lifecycle component's
Descriptor
• Add your lifecycle component to the
Builder
entity
Version 1.10
117
Lumberyard Developer Guide
Main Entry Point
• Register your builder instances when your lifecycle component's
Activate()
function is called
• Shut down safely
Note
A complete example of a builder module is in the Lumberyard dev\Code\tools\AssetProcessor
\Builders
directory. We recommend that you follow the commented example as you read this documentation. The asset builder SDK is located in the Lumberyard directory
\dev\Code\Tools
\AssetProcessor\AssetBuilderSDK\AssetBuilderSDK
.
The following code shows an example of a main.cpp
file for an asset builder module.
#include <AssetBuilderSDK/AssetBuilderSDK.h>
#include <AssetBuilderSDK/AssetBuilderBusses.h>
// Use the following macro to register this module as an asset builder.
// The macro creates forward declarations of all of the exported entry points for you.
REGISTER_ASSETBUILDER
void BuilderOnInit()
{
// Perform any initialization steps that you want here. For example, you might start a
third party library.
} void
BuilderRegisterDescriptors
()
{
// Register your lifecycle component types here.
// You can register as many components as you want, but you need at least one component
to handle the lifecycle.
EBUS_EVENT(AssetBuilderSDK::AssetBuilderBus, RegisterComponentDescriptor,
ExampleBuilder::BuilderPluginComponent::CreateDescriptor());
}
// You can also register other descriptors for other types of components that you might
need.
void
BuilderAddComponents
(AZ::Entity* entity)
{
// You can attach any components that you want to this entity, including management
components. This is your builder entity.
}
// You need at least one component that is the lifecycle component.
entity->CreateComponentIfReady<ExampleBuilder::BuilderPluginComponent>(); void
BuilderDestroy
()
{
// By the time you leave this function, all memory must have been cleaned up and all
objects destroyed.
// If you have a persistent third party library, you could destroy it here.
}
The lifecycle component reflects the types that you want to serialize and registers the builder or builders in your module during its
Activate()
function.
The following shows example code for the lifecycle component.
//! This is an example of the lifecycle component that you must implement.
Version 1.10
118
Lumberyard Developer Guide
Lifecycle Component
//! You must have at least one component to handle your module's lifecycle.
//! You can also make this component a builder by having it register itself as a builder
and
//! making it listen to the builder bus. In this example it is just a lifecycle component
for the purposes of clarity. class BuilderPluginComponent
: public AZ::Component
{ public:
AZ_COMPONENT(BuilderPluginComponent, "{8872211E-F704-48A9-B7EB-7B80596D871D}")
static void Reflect(AZ::ReflectContext* context);
BuilderPluginComponent(); // Avoid initializing here.
//////////////////////////////////////////////////////////////////////////
// AZ::Component
virtual void Init(); // Create objects, allocate memory and initialize without reaching
out to the outside world.
virtual void Activate(); // Reach out to the outside world and connect to and register
resources, etc.
virtual void Deactivate(); // Unregister things, disconnect from the outside world.
//////////////////////////////////////////////////////////////////////////
virtual ~BuilderPluginComponent(); // free memory and uninitialize yourself.
private:
ExampleBuilderWorker m_exampleBuilder;
};
In the following example, the
Activate()
function registers a builder, creates a builder descriptor, and then provides the details for the builder.
void BuilderPluginComponent::Activate()
{
// Activate is where you perform registration with other objects and systems.
// Register your builder here:
AssetBuilderSDK::AssetBuilderDesc builderDescriptor;
builderDescriptor.m_name = "Example Worker Builder";
builderDescriptor.m_patterns.push_back(AssetBuilderSDK::AssetBuilderPattern("*.example",
AssetBuilderSDK::AssetBuilderPattern::PatternType::Wildcard));
builderDescriptor.m_createJobFunction = AZStd::bind(&ExampleBuilderWorker::CreateJobs,
&m_exampleBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
builderDescriptor.m_processJobFunction = AZStd::bind(&ExampleBuilderWorker::ProcessJob,
&m_exampleBuilder, AZStd::placeholders::_1, AZStd::placeholders::_2);
// The above binds are an example of how to bind to a class. You could just use a set
of functions instead; there is no particular requirement to use a class.
builderDescriptor.m_busId = ExampleBuilderWorker::GetUUID(); // Shutdown is
communicated on this bus address.
m_exampleBuilder.BusConnect(builderDescriptor.m_busId); // You can use a global
listener for shutdown instead of
// for each builder; it's up to
you.
EBUS_EVENT(AssetBuilderSDK::AssetBuilderBus, RegisterBuilderInformation,
builderDescriptor);
}
Notes
• The example calls an EBus to register the builder. After you register a builder, the builder receives requests for assets from its two registered callback functions.
Version 1.10
119
Lumberyard Developer Guide
Creating a Builder
• If the application needs to shut down, the asset processor broadcasts the
Shutdown()
message on the builder bus using the address of the registered builder's UUID.
• Your builders do not have to be more than functions that create jobs and then process those jobs. But if you want your builder to listen for
Shutdown()
messages, it must have a listener that connects to the bus.
Your next step is to create a builder. You can have any number of builders, or even all of your builders, inside your module. After registering your builders as described in the previous section, implement the two
CreateJobFunction
and
ProcessJobFunction
callbacks.
The following example code declares a builder class:
#include <AssetBuilderSDK/AssetBuilderSDK.h> class ExampleBuilderWorker : public AssetBuilderSDK::AssetBuilderCommandBus::Handler //
This handler delivers the "shut down!"
//
message on another thread.
{
public:
ExampleBuilderWorker();
~ExampleBuilderWorker();
//! Asset Builder Callback Functions
void
CreateJobs
(const AssetBuilderSDK::CreateJobsRequest& request,
AssetBuilderSDK::CreateJobsResponse& response);
void
ProcessJob
(const AssetBuilderSDK::ProcessJobRequest& request,
AssetBuilderSDK::ProcessJobResponse& response);
//////////////////////////////////////////////////////////////////////////
//!AssetBuilderSDK::AssetBuilderCommandBus interface
void ShutDown() override; // When this is received, you must fail all existing jobs
and return.
//////////////////////////////////////////////////////////////////////////
static AZ::Uuid GetUUID();
private:
bool m_isShuttingDown = false;
};
The asset processor calls the
Shutdown()
function to signal a shutdown. At this point, the builder should stop all tasks and return control to the asset processor.
Notes
• Failure to terminate promptly can cause a hang when the asset processor shuts down and restarts. The shutdown message comes from a thread other than the
ProcessJob()
thread.
• The asset processor calls the
CreateJobs(const CreateJobsRequest& request,CreateJobsResponse& response)
function when it has jobs for the asset types that the builder processes. If no work is needed, you do not have to create jobs in response to
CreateJobsRequest
, but the behavior of your implementation should be consistent.
• For the purpose of deleting stale products, the job that you spawn is compared with the jobs spawned in the last iteration that have the same input, platform, and job key.
• You do not have to check whether a job needs processing. Instead, at every iteration, emit all possible jobs for a particular input asset on a particular platform.
Version 1.10
120
Lumberyard Developer Guide
Creating a Builder
• In general, in the
CreateJobs
function, you create a job descriptor for each job that you want to emit, and then add the job to the list of job descriptors for the response.
The following code shows an example
CreateJobs
function.
// This function runs early in the file scanning pass.
// This function should always create the same jobs, and should not check whether the job
is up to date.
void ExampleBuilderWorker::
CreateJobs
(const AssetBuilderSDK::CreateJobsRequest& request,
AssetBuilderSDK::CreateJobsResponse& response)
{
// The following example creates one job descriptor for the PC platform.
// Normally, you create a job for each platform that you can make assets for.
if (request.m_platformFlags & AssetBuilderSDK::Platform_PC)
{
AssetBuilderSDK::JobDescriptor descriptor;
descriptor.m_jobKey = "Compile Example";
descriptor.m_platform = AssetBuilderSDK::Platform_PC;
// You can also place whatever parameters you want to save for later into this map:
descriptor.m_jobParameters[AZ_CRC("hello")] = "World";
response.m_createJobOutputs.push_back(descriptor);
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
}
}
You can use the Builder SDK API to declare dependencies for a source file on other source files. These other files can be any file within the project directory or directories. They do not have to be source files consumed by a builder.
Declaring dependencies for a source file implies that the data in its output changes if the files that the source file depends on change. If any of the source dependency files are modified, the Asset
Processor retriggers the
CreateJobs
and
ProcessJobs
sequence for those files. This causes the data to be recompiled by your builder when needed.
The Asset Processor recurses source file dependencies automatically. If the source files depended on emit their own dependencies when they are queried, you do not have to recurse in your own source files to the full tree. Just emit your local dependencies for each node in the tree, and the Asset Processor takes care of the rest.
To declare dependencies, add them during CreateJobs to m_sourceFileDependencyList
in your
CreateJobsResponse
structure.
Metafiles do not have to be added as dependencies. Metafiles are a special case and cause your asset to rebuild automatically.
The
SourceFileDependency
structure contains m_sourceFileDependencyPath
and m_sourceFileDependencyUUID
. The builder must supply a value for only one of these fields. For example, if the UUID of the file to be added as a source dependency is known inside the
CreateJobs
method, the builder can just fill in the field m_sourceFileDependencyUUID
. Otherwise the builder would need to fill in the field m_sourceFileDependencyPath
with the appropriate source dependency file path.
It is important to note that the field m_sourceFileDependencyPath
can take both absolute and relative file paths. If a relative path is specified, the appropriate overriding asset is used if present.
Version 1.10
121
Lumberyard Developer Guide
Creating a Builder
If the builder is populating the m_sourceFileDependencyPath
field with a relative file path, then it has to be in relative to one of the watched directories. However, if both the source and the source dependency file exist in the same directory, you can provide just the filename without a path.
The following code snippet that shows how to use the Builder SDK API to add a source file dependency.
//! CreateJobsResponse contains job data that will be send by the builder to the
assetProcessor in response to CreateJobsRequest struct CreateJobsResponse
{
CreateJobsResultCode m_result = CreateJobsResultCode::Failed; // The result
code from the create jobs request
AZStd::vector<SourceFileDependency> m_sourceFileDependencyList; // This is required for
source files that want to declare dependencies on other source files.
AZStd::vector<JobDescriptor> m_createJobOutputs;
};
//! Source file dependency information that the builder will send to the assetprocessor
//! It is important to note that the builder do not need to provide both the
sourceFileDependencyUUID or sourceFileDependencyPath info to the asset processor,
//! any one of them should be sufficient struct SourceFileDependency
{
//! Filepath on which the source file depends, it can be either be a relative or an
absolute path.
//! if it's relative, the asset processor will check every watch folder in the order
specified in the assetprocessor config file until it finds that file.
//! For example if the builder sends the sourcedependency info with
sourceFileDependencyPath = "texture/blah.tiff" to the asset processor,
//! it will check all watch folders for a file whose relative path with regard to it is
"texture/blah.tiff".
//! then "C:/dev/gamename/texture/blah.tiff" would be considered the source file
dependency, if "C:/dev/gamename" is only watchfolder that contains such a file.
//! You can also send absolute path to the asset processor in which case the asset
processor
//! will try to determine if there are any other file which overrides this file based
on the watch folder order specified in the assetprocessor config file
//! and if an overriding file is found, then that file will be considered as the source
dependency.
AZStd::string m_sourceFileDependencyPath;
//! UUID of the file on which the source file depends
AZ::Uuid m_sourceFileDependencyUUID = AZ::Uuid::CreateNull();
...
} void ExampleBuilderWorker::CreateJobs(const AssetBuilderSDK::CreateJobsRequest& request,
AssetBuilderSDK::CreateJobsResponse& response)
{
//Looping over all the available platforms to spawn jobs. note that source
dependencies are independent of jobs and platforms.
// This example shows how you would be able to declare source file dependencies on
source files inside a builder and forward the info to the asset processor
// Basically here we are creating source file dependencies as follows
// the source file .../test.examplesource depends on the source file .../ test.exampleinclude and
// the source file .../test.exampleinclude depends on the source file .../ common.exampleinclude
// the source file .../common.exampleinclude depends on the non-source file .../ common.examplefile
// Important to note that both file extensions "exampleinclude" and "examplesource" are
being handled by this builder.
Version 1.10
122
Lumberyard Developer Guide
Creating a Builder
// Also important to note is that files with extension "exampleinclude" are not
creating any jobdescriptor here, which imply they do not create any jobs.
AZStd::string fullPath;
AzFramework::StringFunc::Path::ConstructFull(request.m_watchFolder.c_str(),
request.m_sourceFile.c_str(), fullPath, false);
AzFramework::StringFunc::Path::Normalize(fullPath);
AZStd::string relPath = request.m_sourceFile;
AssetBuilderSDK::SourceFileDependency sourceFileDependencyInfo;
// source files in this example generate dependencies and also generate a job to
compile it for each platform:
if (AzFramework::StringFunc::Equal(ext.c_str(), "examplesource"))
{
AzFramework::StringFunc::Path::ReplaceExtension(relPath, "exampleinclude");
// declare and add the dependency on the .exampleinclude file:
sourceFileDependencyInfo.m_sourceFileDependencyPath = relPath;
response.m_sourceFileDependencyList.push_back(sourceFileDependencyInfo);
// since we're a source file, we also add a job to do the actual compilation:
for (size_t idx = 0; idx < request.GetEnabledPlatformsCount(); idx++)
{
AssetBuilderSDK::JobDescriptor descriptor;
descriptor.m_jobKey = "Compile Example";
descriptor.m_platform = request.GetEnabledPlatformAt(idx);
// you can also place whatever parameters you want to save for later into this
map, and it will be available in your process function
descriptor.m_jobParameters[AZ_CRC("hello", 0x3610a686)] = "World";
// add the job:
response.m_createJobOutputs.push_back(descriptor);
}
}
else if (AzFramework::StringFunc::Equal(ext.c_str(), "exampleinclude"))
{
// if we're processing an 'include file' then we still generate dependency
information but emit no actual compilation jobs
// similar to how CPP/H works.
if (AzFramework::StringFunc::Find(request.m_sourceFile.c_str(),
"common.exampleinclude") != AZStd::string::npos)
{
// Add any dependencies that common.exampleinclude would like to depend on
here, we can also add a non source file as a dependency like we are doing here
sourceFileDependencyInfo.m_sourceFileDependencyPath = "common.examplefile";
}
else
{
AzFramework::StringFunc::Path::ReplaceFullName(fullPath,
"common.exampleinclude");
// Assigning full path to sourceFileDependency path
sourceFileDependencyInfo.m_sourceFileDependencyPath = fullPath;
}
response.m_sourceFileDependencyList.push_back(sourceFileDependencyInfo);
}
response.m_result = AssetBuilderSDK::CreateJobsResultCode::Success;
}
CreateJobsRequest
provides helper functions for operations related to operating system platforms. The following code shows the helper functions provided by
CreateJobsRequest
.
//! Enum used by the builder for sending platform information.
enum Platform: AZ::u32
Version 1.10
123
Lumberyard Developer Guide
Creating a Builder
{
Platform_NONE = 0x00,
Platform_PC = 0x01,
Platform_ES3 = 0x02,
Platform_IOS = 0x04,
Platform_OSX = 0x08,
Platform_XBOXONE = 0x10,
Platform_PS4 = 0x20,
//! If you add a new platform entry to this enum, you must also add it to
AllPlatforms in order for the platform to be considered valid.
AllPlatforms = Platform_PC | Platform_ES3 | Platform_IOS | Platform_OSX |
Platform_XBOXONE | Platform_PS4
};
//! CreateJobsRequest contains input job data that is sent by the AssetProcessor to
the builder to create jobs.
struct CreateJobsRequest
{
...
//! Platform flags informs the builder about the platforms in which the
AssetProcessor is interested.
int m_platformFlags;
// Return the number of platforms that are enabled for the source file.
size_t GetEnabledPlatformsCount() const;
// Return the enabled platform by index. If no platform is found, then
Platform_NONE is returned.
AssetBuilderSDK::Platform GetEnabledPlatformAt(size_t index) const;
// Determine whether the inputted platform is enabled. Returns true if enabled,
otherwise false.
bool IsPlatformEnabled(AZ::u32 platform) const;
// Determine whether the inputted platform is valid. Returns true if valid,
otherwise false.
bool IsPlatformValid(AZ::u32 platform) const;
};
•
GetEnabledPlatformsCount()
– For the specified platform flags, returns the number of platforms that are enabled for the create jobs request.
•
IsPlatformEnabled(AZ::u32 platform)
– For the specified platform, returns whether the platform is enabled. True if the platform is enabled, false otherwise.
•
IsPlatformValid(AZ::u32 platform)
– For the specified platform value, checks whether it is a valid platform value in the platform enum. True if the platform value is valid, false otherwise.
The asset processor calls the
ProcessJob
function when it has a job for the builder to begin processing:
ProcessJob(const AssetBuilderSDK::ProcessJobRequest& request,
AssetBuilderSDK::ProcessJobResponse& response)
ProcessJob
is given a job request that contains the full job descriptor that
CreateJobs
emitted, as well as additional information such as a temporary directory for it to work in.
This message is sent on a worker thread, so the builder must not spawn threads to do the work. Be careful not to interact with other threads during this call.
Version 1.10
124
Lumberyard Developer Guide
Creating a Builder
Warning
Do not alter files other than those in the temporary directory while
ProcessJob
is running.
After your job indicates success, the asset processor copies your registered products to the asset cache, so be sure not to write to the cache. You can use the temporary directory in any way that you want.
After your builder has finished processing assets, your response structure should list all of the assets that you have created. Because only the assets that you list are added to the cache, you can use the temporary directory as a scratch space for processing.
The following code shows an example
ProcessJob
function.
// This function is called for jobs that need processing.
// The request contains the CreateJobResponse you constructed earlier, including the
// keys and values you placed into the hash table.
void ExampleBuilderWorker::
ProcessJob
(const AssetBuilderSDK::ProcessJobRequest& request,
AssetBuilderSDK::ProcessJobResponse& response)
{
// The following example shows how to listen for cancellation requests. You should
listen for cancellation requests and then cancel work if possible.
// You can derive from the job cancel listener and reimplement Cancel() if you need
to do more processing like signaling a
// semaphore or doing other threading work.
AssetBuilderSDK::JobCancelListener jobCancelListener(request.m_jobId);
AZ_TracePrintf(AssetBuilderSDK::InfoWindow, "Starting Job.");
AZStd::string fileName;
AzFramework::StringFunc::Path::GetFullFileName(request.m_fullPath.c_str(), fileName);
AzFramework::StringFunc::Path::ReplaceExtension(fileName, "example1");
AZStd::string destPath;
// Do all of your work inside the tempDirPath.
// Do not write outside of this path
AzFramework::StringFunc::Path::ConstructFull(request.m_tempDirPath.c_str(),
fileName.c_str(), destPath, true);
// Use AZ_TracePrintF to communicate job details. The logging system automatically
places the
// text in the appropriate log file and category.
AZ::IO::LocalFileIO fileIO;
if (!m_isShuttingDown && !jobCancelListener.IsCancelled() &&
fileIO.Copy(request.m_fullPath.c_str(), destPath.c_str()) == AZ::IO::ResultCode::Success)
{
// If assets were successfully built into the temporary directory, push them back
into the response's product list.
// The assets that you created in your temporary path can be specified using paths
relative to the temporary path.
// It is assumed that your code writes to the temporary path.
AZStd::string relPath = destPath;
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Success;
AssetBuilderSDK::JobProduct jobProduct(fileName);
response.m_outputProducts.push_back(jobProduct);
}
else
{
if (m_isShuttingDown)
{
AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Cancelled job %s because shutdown
was requested", request.m_fullPath.c_str());
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Cancelled;
}
Version 1.10
125
Lumberyard Developer Guide
Creating a Builder
else
{
AZ_TracePrintf(AssetBuilderSDK::ErrorWindow, "Error during processing job %s.",
request.m_fullPath.c_str());
response.m_resultCode = AssetBuilderSDK::ProcessJobResult_Failed;
}
}
}
Builders can use
JobCancelListener
to listen for job cancellation requests in their processJob
method.
You should listen for cancellation requests and then cancel work if possible. The address of this listener is the job ID of the job that can be found in processJobRequest
. You can derive from the
JobCancelListener
and reimplement
Cancel()
if you must do additional processing like signaling a semaphore or other threading work. The following code example shows the use of
JobCancelListener
.
//! JobCancelListener can be used by builders in their processJob method to listen for job
cancellation requests.
//! The address of this listener is the job ID that can be found in the process job
request.
class JobCancelListener : public JobCommandBus::Handler
{ public: explicit JobCancelListener(AZ::u64 jobId);
~JobCancelListener() override;
JobCancelListener(const JobCancelListener&) = delete;
//////////////////////////////////////////////////////////////////////////
//JobCommandBus::Handler overrides
//Note: This is called on a thread other than your processing job thread.
//You can derive from JobCancelListener and reimplement Cancel if you need to do something
special in order to cancel your job.
void Cancel() override;
/////////////////////////////////////////////////////////////////////// bool IsCancelled() const; private:
AZStd::atomic_bool m_cancelled;
};
• So that critical files are not missed, the editor is blocked until all jobs are created. For this reason, you should execute the code in
CreateJobs
as quickly as possible. We recommend that your code do minimal work during
CreateJobs
and save the heavy processing work for
ProcessJob
.
• In
CreateJobs
, you can place arbitrary key–value pairs into the descriptor's m_jobParameters
field.
They key–value pairs are copied back when
ProcessJob
executes, which removes the need for you to add them again.
• All of the outputs for your job should be placed into your temporary workspace. However, if you just need to copy an existing file into the asset cache as part of your job, you can emit as a product the full absolute source path of the file without copying it into your temporary directory first. The asset processor then copies the file into the cache and registers it as part of the output of your job. All other files are moved from your temporary directory into the asset cache in an attempt to perform an atomic cache update in case your job succeeds.
Version 1.10
126
Lumberyard Developer Guide
Message Loggging
You can use
BuilderLog(AZ:Uuid builderId, char* message, ...)
to log any general builder related messages or errors.
BuilderLog
cannot be used during job processing; use it during startup, shutdown, or registration.
For job related messages, use
AZ_TracePrintf(window, msg), AZ_Warning(...), AZ_Error(...),
AZ_Assert(...)
, and so on. . The function automatically records the messages in the log file for the job.
Version 1.10
127
Lumberyard Developer Guide
AZ Code Generator is in preview release and is subject to change.
AZ Code Generator is a command line utility that generates source code (or any data or text) from specially tagged source code. You can use it when the structure of the intended code is known in advance so that templates can be made for it. For example, you could generate boilerplate code for serialization or reflection.
AZ Code Generator parses a list of existing C++ source files and/or header files and generates intermediate data in JSON format. It passes the intermediate data to a series of templates.
The templates provide the format for the code that is generated. Templates make increased coding efficiency possible because they enable automatic updates of boilerplate code. When a template is updated, all related generated code is regenerated in the next build. This removes the need to update the glue code manually or to use error-prone find-and-replace operations.
Topics
•
•
•
•
Intermediate JSON Data (p. 130)
Version 1.10
128
Lumberyard Developer Guide
Workflow Summary
•
AZ Code Generator and Python (p. 131)
•
Template Drivers and Template Rendering (p. 131)
•
•
AZ Code Generator Integration with Waf (p. 133)
•
AZ Code Generator Parameters (p. 135)
•
Code Generation Templates (p. 139)
•
•
Custom Code Generator Annotations (p. 145)
•
Waf Debugging with AZ Code Generator (p. 150)
•
Template Driver Debugging (p. 156)
•
Debugging the AZ Code Generator Utility (p. 157)
•
Intermediate JSON Data Format (p. 159)
The following steps describe how AZ Code Generator works with Waf to generate code.
1. The Waf build system invokes AZ Code Generator for the
.h
and
.cpp
source files that are specified in the wscript
file.
2. AZ Code Generator runs one or more passes with the specified files.
3. Each pass includes the following: a. AZ Code Generator uses the Clang front-end compiler to produce an abstract syntax tree (AST) for each provided source file. The Clang parser attempts to compile the input. For increased speed,
Clang can be instructed to not follow
#include
statements and to suppress all errors.
b. The AST is translated into an intermediate JSON format.
c. The intermediate JSON object is passed into a template driver as a Python script and then into a
Jinja2 template. Each driver and template implements specific code generation tasks.
d. The template driver performs any preprocessing that you want on the intermediate JSON object.
e. The intermediate JSON is then passed to Jinja2 templates.
f. Each template driver can have an arbitrary number of templates, which can output to an arbitrary number of output files. Multiple templates can have the same output file or different output files as the template driver creator wants.
4. AZ Code Generator returns a list of generated files to the Waf build system.
5. The Waf build system completes the build process, including the generated code in the build.
The following sections provide more detail about this process.
The AZ Code Generator is fully integrated into the Waf build system . You can use the Waf az_code_gen feature to invoke the AZ Code Generator. We recommend that you use Waf rather than the command line to start the
AzCodeGenerator.exe
utility.
For examples and more information about the Waf integration, see
AZ Code Generator Integration with
.
Version 1.10
129
Lumberyard Developer Guide
Clang
The default front end of the AZ Code Generator is a Clang parser/compiler for C++ source code. AZ Code
Generator uses Clang to parse source code (which might include user-defined tags) and generate the intermediate JSON data object. AZ Code Generator fully controls Clang's parser and compilation phase so that it can selectively suppress or enable features such as diagnostics. This gives AZ Code Generator the flexibility to ignore source code that might fail to compile and still attempt to generate a complete intermediate object.
The Clang front end compiler outputs an intermediate JSON data structure that the generator passes to templates for further processing. An example intermediate JSON data object follows.
[
{
'name' : 'Component',
'qualified_name' : 'AZ::Component',
'fields' : [],
'bases' : [],
'meta' : {
'path' : 'D:\\Repo\\Ly\\branches\\AzComponents\\Code\\Tools\\AzCodeGenerator\
\CodeGenTest.h'
},
'type' : 'class',
'annotations' : {},
'methods' : []
},
{
'name' : 'TestingClass',
'qualified_name' : 'TheNamespace::TestingClass',
'fields' : [
{
'type' : 'float',
'name' : 'm_field2',
'qualified_name' : 'TheNamespace::TestingClass::m_field2',
'annotations' : {}
}
],
'bases' : [
{
'name' : 'Component',
'qualified_name' : 'AZ::Component'
}
],
'meta' : {
'path' : 'D:\\Repo\\Ly\\branches\\AzComponents\\Code\\Tools\\AzCodeGenerator\
\CodeGenTest.h'
},
'type' : 'class',
'annotations' : {},
'methods' : [
{
'params' : ['type', 'int', 'name', 'version'],
'name' : 'CreateArgumentAnnotation',
'qualified_name' : 'TheNamespace::TestingClass::CreateArgumentAnnotation',
'annotations' : {}
}
]
}
Version 1.10
130
Lumberyard Developer Guide
AZ Code Generator and Python
]
For complete syntax of the intermediate JSON data object, see
AZ Code Generator depends on Python 2.7 to run template drivers and render Jinja templates. The
Python C API is used to extend Python with methods in the azcg_extension
module that permit template drivers to report dependencies, errors, and useful informational output. In Windows, Python
2.7 is included in the Lumberyard dev/Tools/Python
directory. On macOS, AZ Code Generator uses the version of Python that is included with the operating system.
Note
To debug Python C API calls when using AZ Code Generator, you must download CPython . Then make a build for your intended debug platform.
You can use template drivers written in Python to alter the intermediate data structure before passing it to the template engine. After preprocessing, the template driver might direct the Jinja2 template engine to render one or many templates, depending on the generated code that you want.
AZ Code Generator uses the Jinja2 template engine, which is downloaded by the Python easy_install script in the
\dev\Tools\Python\2.7.11\windows\Scripts
directory. The engine is then copied into the
Lumberyard
3rdParty\jinja2
directory. Lumberyard also provides a jinja_extensions
module, which contains helper methods that you can use inside templates. These extensions are stored in the dev/Code/
Tools/AzCodeGenerator/Scripts/jinja_extensions/
directory. For examples and more information
about Jinja templates, see Code Generation Templates (p. 139)
.
The following sample output was generated from a serialization template. The reference JSON object has been formatted for readability.
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
// THIS CODE IS AUTOGENERATED, DO NOT MODIFY
/////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////
#include "stdafx.h"
#include <AZCore/Rtti/ReflectContext.h>
#include <AzCore/Rtti/Rtti.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Math/Vector3.h>
#include "D:/Repo/Ly/branches/AzComponents/Code/Tools/AzCodeGenerator/CodeGenTest.h" namespace Components
{
void TestingClassReflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext =
azrtti_cast<AZ::SerializeContext*>(reflection);
Version 1.10
131
Lumberyard Developer Guide
Generated Files
if (serializeContext)
{
serializeContext->Class<TestingClass>()
->SerializerForEmptyClass() ;
}
}
}
///////////////////////////////////////////////////////////////
/*
// Reference JSON object
[{
'name':'Component',
'qualified_name':'AZ::Component',
'fields':[
],
'bases':[
],
'meta':{
'path':'D:\\Repo\\Ly\\branches\\AzComponents\\Code\\Tools\\AzCodeGenerator\
\CodeGenTest.h'
},
'type':'class',
'annotations':{
},
'methods':[
]
},
{
'name':'TestingClass',
'qualified_name':'TheNamespace::TestingClass',
'fields':[
{
'type':'float',
'name':'m_field2',
'qualified_name':'TheNamespace::TestingClass::m_field2',
'annotations':{
}
}
],
'bases':[
{
'name':'Component',
'qualified_name':'AZ::Component'
}
],
'meta':{
'path':'D:\\Repo\\Ly\\branches\\AzComponents\\Code\\Tools\\AzCodeGenerator\
\CodeGenTest.h'
},
'type':'class',
'annotations':{
},
'methods':[
{
'params':[
'type',
'int',
'name',
'version'
],
Version 1.10
132
Lumberyard Developer Guide
AZ Code Generator Integration with Waf
'name':'CreateArgumentAnnotation',
'qualified_name':'TheNamespace::TestingClass::CreateArgumentAnnotation',
'annotations':{
}
}
]
}]
*/
AZ Code Generator is in preview release and is subject to change.
AZ Code Generator is fully accessible for any Waf target as the feature az_code_gen
. The dev\Tools
\Build\waf-
<version_number>
\lmbrwaflib\az_code_generator.py
file contains the core of the Waf integration code. It includes the az_code_gen
feature that can be used by any wscript
file.
The minimum required information is a list of the files to pass into the code generator and at least one template driver. This list feeds the code generator one file at a time and invokes the templates specified by the driver. The files output from the driver are added as dependencies of the build task. Output files also have the option to be reinjected back into the C++ build for compilation. Output file paths are automatically added as include paths both for the current target build and as export_header
entries.
This allows written source code to reference the generated source code from both internal and external targets.
Topics
•
•
•
•
•
Command Line Parameters (p. 135)
•
In the wscript
file for the target requiring generated code, add the az_code_gen
feature as follows.
features = ['az_code_gen'],
Next, specify the files to pass as input to the code generator, as in the following example.
az_code_gen = [
{
'files' : ['MySourceFile.h'],
'scripts' : ['MyTemplateDriver.py']
}
],
The paths given are relative to the target path in both cases.
Version 1.10
133
Lumberyard Developer Guide
Advanced Integration
Whenever the specified target is compiled, a code generation task passes in the
MySourceFile.h
file to the code generator. It also invokes the
MyTemplateDriver.py
file to control the output. For information
on how to write a template driver, see Template Drivers (p. 141) .
The AZ Code Generator Waf integration uses passes to define the code generator tasks that must be run during build time. Each pass determines the set of files, drivers, and environment settings with which to run the code generator. Currently, all passes are run in parallel without any dependency checking between passes.
The following example shows the configuration of multiple passes.
az_code_gen = [
{
'files' : ['MyCode/MySourceFile.h'],
'scripts' : ['MyCode/MyTemplateDriver.py']
},
{
'files' : ['MyOtherCode/MyOtherSourceFile.h'],
'scripts' : ['MyOtherCode/MyOtherTemplateDriver.py']
}
],
This example generates the following two code generation tasks.
1. Pass in the
MyCode/MySourceFile.h
file to the code generator and invoke the
MyCode/
MyTemplateDriver.py
file to control the output.
2. Pass in
MyOtherCode/MyOtherSourceFile.h
to the code generator and invoke
MyOtherCode/
MyOtherTemplateDriver.py
to control the output.
Each pass provides a list of files that will be used as input to the code generator. This list can also contain string paths, nodes, and lists. Top-level string paths and nodes are passed individually to the code generator. Note the following:
• If you provide a list, all files or nodes in that list are used by the code generator at the same time. This allows for maximum flexibility, but typical usage is one input per task.
• The overhead of the Waf task and AZ Code Generator bootstrapping can be significant. To improve performance, you can pass in multiple input files in one list.
• The code generator invokes the same Clang and template driver pipeline for each input file.
The following example shows several input file specifications.
# Finds this file relative to the build context source node
'files' : [bld.srcnode.find_or_declare('Code/Framework/AzCore/Tests/CodeGen.h')],
'files' : [
# Pass both MyClass.h and MyClass.cpp at the same time to code generator to get more
# information about MyClass than just the header. Note the nested lists.
['MyClass.h', 'MyClass.cpp']
]
'files' : [
Version 1.10
134
Lumberyard Developer Guide
Template Drivers
# Any and all variations are allowed, but because lists provide only one layer of
grouping,
# lists are allowed only at the top level.
'MySourceFile.h',
'MyOtherSourceFile.cpp',
bld.srcnode.find_or_declare('Code/Framework/AzCore/Tests/CodeGen.h'),
['MyClass.h', 'MyClass.cpp']
]
To specify template drivers to use for each code generation pass, provide a list of string paths, relative to the target path, as in the following example.
'scripts' : [
'../../../Framework/AzFramework/CodeGen/AzClassCpp.py',
'../../../Framework/AzFramework/CodeGen/AzEBusInline.py',
'../../../Framework/AzFramework/CodeGen/AzReflectionCpp.py',
'../../../Framework/AzFramework/CodeGen/AzClassInline.py'
],
All command line parameters for the code generation utility can be specified in each code generation pass. To do this, provide a list of arguments, as in the following example.
'arguments' : [
'-OnlyRunDiagnosticsOnMainFile=true',
'-SuppressDiagnostics=false',
'-SuppressErrorsAsWarnings=false',
'-output-redirection=file',
],
For a full list of parameters, see
AZ Code Generator Parameters (p. 135)
.
The Waf integration provides additional options that can be specified in a list for each code generation pass, as in the following example.
'options' : ['PrintOutputRedirectionFile'],
PrintOutputRedirectionFile
– This option, when used in combination with the
-outputredirection=file
parameter, directs Waf to provide AZ Code Generator a path to save extra output during code generation. The path to this file is listed for each task during the build if errors occur.
Profile
– This option enables profiler timings of clang parsing and script execution within the AZ Code
Generator tool.
AZ Code Generator is in preview release and is subject to change.
Version 1.10
135
Lumberyard Developer Guide
Waf Parameters
For best results, pass the options for AZ Code Generator in to the Waf build system. However, you can also specify the parameters for
AzCodeGenerator.exe
on the command line.
Topics
•
•
Clang Compilation Parameters (p. 136)
•
•
•
AZ Code Generator Parameter List (p. 136)
Most parameters for AZ Code Generator are specified by the Waf integration. Parameters such as input, output, and include paths are automatically detected and forwarded. Other AZ Code Generator parameters control how AZ Code Generator deals with the source code input and the intermediate data that is generated.
Specify any of these in the arguments
section of the az_code_gen
pass in the wscript
file.
The following
AzCodeGenerator.exe
parameters apply to Clang compilation.
Parameter Description
-
Suppresses unknown
SuppressIncludeNotFoundError
#include
statements at compile time.
-
Ignores build warnings and errors on all except the main file specified for
-SuppressDiagnostics
Ignores build warnings and errors on all files.
-
SuppressErrorsAsWarnings
Downgrades any build errors to warnings. Allows Clang to succeed even if there are errors.
To include information about code outside of the input file in the intermediate JSON data, use the following option.
-inclusion-filter=
<wildcard filter for files to allow>
You can choose the front end to use by specifying either the
-Clang
(the default) or
-JSON
option.
The following list shows all AZ Code Generator parameters.
Version 1.10
136
Lumberyard Developer Guide
AZ Code Generator Parameter List
Usage:
AzCodeGenerator.exe [options]
Option
-Clang
Category Description
General Uses the Clang compiler front end.
-clang-settingsfile=
<string>
-codegenscript=
<string>
Code parsing
The path to the file that contains Clang configuration settings.
Python The absolute path and file name of the code generation script to invoke.
General Enables debug output.
-debug
-debug-buffersize=
<uint>
General Buffers the last
n
characters of debug output until program termination. The default is
0
, which specifies immediate print out.
General Enables a specific type of debug output.
-debug-only=
<debug string>
-define=
<string>
Code parsing
Specifies a preprocessor definition.
-
DelayedTemplateParsing
AST traversal
Consumes and stores template tokens for parsing at the end of the translation unit.
-
AST Enables incremental processing.
-forceinclude=
<string>
-help
-help-hidden
Code parsing
List of headers to forcibly include in Clang parsing.
General Displays basic options in categorized format.
General Displays all available options in categorized format.
General Displays basic options in list format.
-help-list
-help-list-hidden
-includepath=
<string>
-inclusionfilter=
<string>
General Displays all available options in list format.
Code parsing
The header includes the path.
Code filtering
Specifies a wildcard filter so that files other than those specified by input-files
are parsed by Clang into intermediate data.
General File to which to append
-stats
output.
-info-outputfile=
<filename>
-input-file=
<string>
Code parsing
(Required) Path to input file relative to the value of input-path
.
-input-path=
<string>
-intermediatefile=
<string>
-JSON
-noscripts
Code parsing
Code parsing
(Required) The absolute path to input folder. All must be relative to this folder.
General Uses raw JSON input for the front end.
input-file
Path to a file that stores the JSON AST from Clang parsing.
paths
General Disables the running of code generation scripts.
Version 1.10
137
Lumberyard Developer Guide
AZ Code Generator Parameter List
Option
-
-outputpath=
<string>
-output-redirection
Category Description
Clang Runs diagnostics (error and warning checking) only on the main file that is compiled. Ignores errors and warnings from all other files.
Code parsing
(Required) The absolute path to the output folder.
Output Redirects output and error messages from Clang and Python internal utilities.
Options:
=none
– No output redirection. Clang and Python output to stdout and stderr
.
=null
– Redirect Clang and Python to null, effectively suppressing output.
-output-using-json
-print-all-options
-print-options
-profile
-python-debugpath=
<string>
-pythonhome=
<string>
=file
– Redirect Clang and Python to disk. Use redirect-outputfile
to specify the path.
Output Outputs using JSON objects instead of plain text. Use this option to ease parsing for calling applications.
General Prints all option values after command line parsing.
General Prints nondefault options after command line parsing.
General Enables AZ Code Generator's internal profiler and emits timings for
Clang parsing and script execution.
Python Path to Python debug libraries and scripts for
AzCodeGenerator.exe
to use in debugging.
Python (Required) The equivalent of the
PYTHONHOME
environment variable, which is ignored.
Python The equivalent of the debug Python
PYTHONHOME
environment variable, which is ignored.
Python The path to Python libraries and scripts for
AzCodeGenerator.exe
.
-python-homedebug=
<string>
-pythonpath=
<string>
-redirect-outputfile=
<string>
-resourcedir=
<string>
-stats
-SkipFunctionBodies
-SuppressDiagnostics
Output The file path for redirected output. Use in combination with the
-output-redirection=file
option. The default file name is output.log
.
Code parsing
The path to the resource directory for Clang.
General Enables statistics output from program (available with asserts). Use the
-info-output-file=
<filename>
option to specify the output file.
AST traversal
Does not traverse function bodies.
Clang Hides Clang compilation diagnostic information.
compilation
Version 1.10
138
Lumberyard Developer Guide
Code Generation Templates
Option
-
-
-track-memory
-v
-version
-view-background
Category Description
Clang Suppresses compilation errors during parsing by reporting them as warnings.
AST Suppresses
#include
not found errors.
General Enables
-time-passes
memory tracking. Performance might be slow when this option is used.
General Outputs verbose debug information.
General Displays the version of
AzCodeGenerator.exe
.
General Executes the graph viewer in the background. This option creates a
.tmp
file that must be deleted manually.
AZ Code Generator is in preview release and is subject to change.
AZ Code Generator uses the Jinja2 template engine for Python to render its output. The Jinja template engine outputs plain text with embedded variable and logic statements.
Jinja templates are designed to be highly readable and mimic the overall structure of the desired output.
They are processed top to bottom. Any text outside of the control block in the template is sent directly to the output.
The following are some example templates. For more information about creating Jinja templates, refer to the Jinja Template Designer Documentation .
Topics
•
•
•
A Jinja template can use text variables to replace text at predetermined locations in the output, as in the following example:
// Here's a {{ variable_name }} !!
int {{ variable_name }} = {{ variable_value }};
In this example, the Jinja template is given the following input.
{
'variable_name' = 'foo',
'variable_value' = 42
}
The following output results.
Version 1.10
139
Lumberyard Developer Guide
Complex Example
// Here's a foo !!
int foo = 42;
Jinja allows for fairly complicated logic, branching and looping control structures. The following example template generates a class that has the public and private variables specified by the input:
// This class is auto-generated!
class {{ class.name }}
{ public:
virtual ~{{ class.name }}() = default;
{% if class.members is defined %}
{% for member_var in class.members if member_var.visibility is 'public' -%}
{{ member_var.type }} m_{{ member_var.name }}{{ if member_var.value is defined }} =
{{ member_var.value }}{{ endif }};
{%- endfor %}
{% endif %} private:
{% if class.members is defined %}
{% for member_var in class.members if member_var.visibility is 'private' -%}
{{ member_var.type }} m_{{ member_var.name }}{{ if member_var.value is defined }} =
{{ member_var.value }}{{ endif }};
{%- endfor %}
{% endif %}
};
In this example, the Jinja template is given the following input.
{
'class' : {
'name' : 'MyClass',
'members' : [
{
'name' : 'foo',
'type' : 'int',
'visibility' : 'public'
},
{
'name' : 'bar',
'type' : 'long',
'visibility' : 'public',
},
{
'name' : 'secretSauce',
'type' : 'float',
'visibility' : 'private',
'value' : '98.6f'
}
]
}
}
The template produces the following output.
// This class is auto-generated!
class MyClass
{ public:
Version 1.10
140
Lumberyard Developer Guide
Template Data
virtual ~MyClass() = default;
int m_foo;
long m_bar; private:
float m_secretSauce = 98.6f;
};
The data that is available to the template is fully controlled by the Python
.
The following table lists the variables that are automatically added to the Jinja environment.
Variable
extra_data extra_str json_object json_str
Description
Python object that contains data returned by the
apply_transformations (p. 142)
method of the template driver.
String that contains the contents of extra_data
in JSON format.
Python object that contains the decoded intermediate JSON after it has been processed by the template driver.
String that contains the encoded intermediate JSON after it has been processed by the template driver.
For information about the intermediate output, see Intermediate JSON Data Format (p. 159)
.
Note
Because Jinja contains a limited feature set, attempting to do complex data transformations in Jinja templates produces overly complicated and generally unreadable templates. For this reason, we recommend that you perform any major data manipulation in the template driver before it is passed into the Jinja template engine. For more information, see
.
AZ Code Generator is in preview release and is subject to change.
Template drivers are Python scripts that process the intermediate JSON data and route it into the Jinja2 output templates. The scripts preprocess the data from the Clang front end, execute the template rendering, and control where the generated output is written to disk.
These scripts are usually called by one or more code generation passes in WAF wscript
files. Each Python script can reference multiple templates. This offers great flexibility in implementation, especially when multiple templates rely on the same preprocessed data.
Topics
•
Specifying Drivers in Waf (p. 142)
•
Creating a Template Driver in Python (p. 142)
•
Minimal Template Driver (p. 144)
•
Version 1.10
141
Lumberyard Developer Guide
Specifying Drivers in Waf
•
Configuring Automatic Build Injection (p. 144)
•
Preprocessing Intermediate Data (p. 145)
Drivers are specified by file name in each code generation pass. The file path is relative to the root of the wscript
target. All drivers are invoked on each input file.
The following shows the structure of a sample Waf entry.
'az_code_gen' = [
{
'files': [
<files to gen>
],
'scripts': [
<list of script file paths relative to current wscript folder>
]
}
]
For more details on how to specify passes, see AZ Code Generator Integration with Waf (p. 133) .
To create a template driver in Python, you must import the
TemplateDriver
base class and override its methods. The code for the class can be found in the dev/Code/Tools/AzCodeGenerator/Scripts/ az_code_gen/base.py
file.
This class is automatically injected into Python by AZ Code Generator and only needs to be imported as az_code_gen.base
, as in the following example.
from az_code_gen.base import *
To implement your template driver, override the following methods in the
TemplateDriver
class.
add_dependency
Call the add_dependency
method to manually add a dependency to the az_code_gen
task in Waf. The file path given should be absolute so that the render template can specify additional dependencies that
Waf does not automatically include. These dependencies might be external data files used to render the templates, or files that were used to generate the input data.
Syntax
add_dependency(self, dependency_file) apply_transformations
Override the apply_transformations
method to manipulate the raw JSON object, which is passed in as the obj
parameter. Manipulations are performed in place on the object. The object is then forwarded through the pipeline and is eventually passed to jinja_args
of render_templates
. Any object returned by this method is provided to the Jinja environment as extra_data
.
Syntax
apply_transformations(self, obj)
Version 1.10
142
Lumberyard Developer Guide
Creating a Template Driver in Python
For an example of this method, see
Preprocessing Intermediate Data (p. 145) .
get_expected_tags
Override the get_expected_tags
method to return a list of tags that must be found in any input file. If the required tags are not present, this driver is skipped.
Important
This method is deprecated as of Lumberyard v1.6. After Lumberyard v1.6, all scripts will be processed regardless of expected tags, and get_expected_tags
will not be invoked.
Syntax
get_expected_tags(self)
Renders a template to disk. This method also adds the value of output_file
as a dependency of the az_code_gen
task in Waf.
Syntax
render_template_to_file(self, template_file, template_kwargs, output_file,
should_add_to_build=False)
Parameters
Parameter
template_file template_kwargs output_file
Description
Specifies the path to a template relative to the directory that contains the template driver
.py
file.
Specifies a dictionary of key–value pairs to be passed to Jinja. Generally this should be treated as a passthrough variable for the jinja_args
given to render_templates
, but you can add additional key–value pairs.
Specifies the target file for the rendered Jinja output. The path is relative to the target output folder.
A Boolean value that specifies whether Waf should add this file to the C++ build and linker. The default is false.
Override render_templates
to invoke template rendering by calling render_template_to_file
.
Syntax
render_templates(self, input_file, **jinja_args)
Parameters
Parameter Description
input_file
The path relative to the input path that is used to invoke Clang.
Version 1.10
143
Lumberyard Developer Guide
Minimal Template Driver
Parameter Description
jinja_args
The raw data from the intermediate JSON object after the template driver performs preprocessing on the object.
The minimum code required for a template driver is to derive from the
TemplateDriver
base class and implement a factory function to construct the template driver.
from az_code_gen.base import * class MyTemplateDriver(TemplateDriver):
pass
# Factory function - called from launcher def create_drivers(env):
return [MyTemplateDriver(env)]
The az_code_gen
module is automatically provided by AZ Code Generator. It contains the
TemplateDriver
and other useful methods from the base.py
file.
The create_drivers
function simply forwards the Jinja environment that is used to render templates.
However, you can alter the function to perform other work when the driver is instantiated.
Note
The above bare-bones implementation works but does not generate any output.
To generate some output, you must implement the render_templates
method, as in the following example.
from az_code_gen.base import * class MyTemplateDriver(TemplateDriver):
def render_templates(self, input_file, **jinja_args):
self.render_template_to_file("MyTemplate.tpl", jinja_args, 'GeneratedCode.cpp')
# Factory function - called from launcher def create_drivers(env):
return [MyTemplateDriver(env)]
The render_templates
method takes the relative input_file
path and any arguments that were passed in from the
AZCodeGenerator.exe
utility. The input_file
path usually contains inputs such as the intermediate json_object
created by Clang.
Template drivers can extend this information by implementing the apply_transformations
method. For more information, see
Preprocessing Intermediate Data (p. 145) .
The render_template_to_file
method takes a template file and argument key–value pairs to pass into the template engine directly and an output path to write the template engine render output to disk.
At this point, the example generates a minimal
.cpp
file. The example above does not compile or link the
.cpp
file. This is appropriate if you intend to include the generated code manually using an
#include
in another file.
Version 1.10
144
Lumberyard Developer Guide
Preprocessing Intermediate Data
To inject the generated file automatically, add the should_add_to_build
parameter to the render_template_to_file
method and pass the parameter the value of true
. The should_add_to_build parameter informs Waf that the generated file needs to be built and linked into the current target.
Note
Using the should_add_to_build
parameter is not recommended for header files or other generated files that are not C++ code that must be compiled and linked.
The following example shows some build injected output.
from az_code_gen.base import * class MyTemplateDriver(TemplateDriver):
def render_templates(self, input_file, **jinja_args):
self.render_template_to_file("MyTemplate.tpl", jinja_args, 'GeneratedCode.cpp',
should_add_to_build=True)
# Factory function - called from launcher def create_drivers(env):
return [MyTemplateDriver(env)]
Some cases require preprocessing of the intermediate data for easier consumption by the template engine. To do this, implement the apply_transformations
method in your template driver. You can use this method to access the intermediate JSON data object directly before it gets passed to render_templates
. An example follows.
from az_code_gen.base import * class MyTemplateDriver(TemplateDriver):
def render_templates(self, input_file, **jinja_args):
self.render_template_to_file("MyTemplate.tpl", jinja_args, 'GeneratedCode.cpp')
def apply_transformations(self, obj):
obj['my_custom_data'] = 42
# Factory function - called from launcher def create_drivers(env):
return [MyTemplateDriver(env)]
For information on the contents of the obj
variable, see
Intermediate JSON Data Format (p. 159) .
AZ Code Generator is in preview release and is subject to change.
You can provide additional data to your template driver by attaching annotations and tags to your source code.
Topics
•
Reference Annotations (p. 146)
•
•
Version 1.10
145
Lumberyard Developer Guide
Reference Annotations
When you create custom code generator annotations, it is a good idea to refer for examples to the existing annotations in the dev/Code/Framework/AZCore/AZCore/Preprocessor/CodeGen.h
file. The existing annotations use macros extensively as a workaround for the lack of proper annotations in C++.
Clang provides an annotate
attribute that can be read at parse time. You can use the helper macros provided to create new annotations, as in the following example.
__attribute__((annotate("
<Some string here>
")))
This attribute is wrapped with a macro that converts its contents into strings that can be parsed by the
AZ Code Generator utility.
AZ Code Generator has two helper macros for annotations:
AZCG_CreateAnnotation
and
AZCG_CreateArgumentAnnotation
.
AZCG_CreateAnnotation
is the core macro that exposes the underlying Clang annotate
attribute. The macro definition follows.
// AZCG_CreateAnnotation
#define AZCG_CreateAnnotation(annotation) __attribute__((annotate(annotation)))
Any argument passed to
AZCG_CreateAnnotation
must be a string.
The
AZCG_CreateArgumentAnnotation
macro is commonly used for annotation macros. The macro definition follows.
// AZCG_CreateArgumentAnnotation
#define AZCG_CreateArgumentAnnotation AZCG_CreateAnnotation(AZ_STRINGIZE(annotation_name)
"(" AZ_STRINGIZE((__VA_ARGS__)) ")")
The
AZCG_CreateArgumentAnnotation
macro takes an annotation_name
argument and a number of variable arguments. The values passed to the variable arguments are collapsed into a single string for parsing by the AZ Code Generator.
This section provides example annotations. One example forwards arguments to the underlying macro, one places an annotation inside a class, and one injects code back into the originating file.
The following example creates a new annotation called
AzExample
that forwards its arguments to the underlying macro.
//Sample Annotation
#define AzExample(...) AZCG_CreateArgumentAnnotation(AzExample, __VA_ARGS__)
Version 1.10
146
Lumberyard Developer Guide
Example Annotations
In this example, the private and public names of the annotation are the same. However, the external and internal names do not have to match.
You can attach the
AzExample
annotation to most items in C++, as in the following example.
// Sample Tag Usage class ExampleClass
{
AzExample(description("I am data!"))
int m_myData;
}
The tags inside the annotation are placed in JSON format in the generated intermediate data object, as in the following example. Some data has been removed for readability.
// Sample Tag JSON
{
"type": "class",
"name": " ExampleClass",
"annotations" : {},
"fields": [
{
"name": "m_myData",
"annotations" : {
"description" : "I am data!"
}
}
}
]
}
The following example directs the AZ Code Generator utility to attach a free-floating annotation to a class.
// Class Tag Macro
#define AzExampleClass(...) AZCG_CreateArgumentAnnotation(AzExampleClass, Class_Attribute,
__VA_ARGS__) int AZ_JOIN(m_azCodeGenInternal, __COUNTER__);
AzExampleClass
– Specifies the annotation name
AzExampleClass
(instead of
AzExample
, as in the previous example).
Class_Attribute
– Causes the AZ Code Generator utility to attach the attribute to the class that contains the annotation. The annotation belongs to the annotations
property of the class object.
__VA_ARGS__
– Specifies additional parameters that are converted into a single string and passed into the
AZ Code Generator utility for parsing.
int AZ_JOIN(m_azCodeGenInternal, __COUNTER__)
–
AZ_JOIN
is a helper macro that takes two macrolevel entries and joins them together without converting them to strings. Because Clang requires annotation attributes be attached to a function or variable, this example uses
AZ_JOIN
and a temporary integer member variable to do this. The temporary integer member variable is then ignored.
Adding the new tag to the previous example produces the following code:
//Class Tag Example class ExampleClass
{
AzExampleClass(MyExampleClassTags::description("I am an example class!"));
Version 1.10
147
Lumberyard Developer Guide
Example Annotations
AzExample(MyExamplePropertyTags::description("I am data!"))
int m_myData;
}
This produces the following intermediate JSON object. Some data has been removed for ease of comprehension.
// Class Tag JSON
"type": "class",
"name": "SampleClass",
"annotations" : {
"MyExampleClassTags::description" : "I am an example class!"
},
"fields": [
{
"name": "m_myData",
"annotations" : {
"MyExamplePropertyTags::description" : "I am data!"
}
}
]
Notice that the above JSON does not look exactly like the JSON in the intermediate files provided as part of AZ framework. This is because Lumberyard uses namespaces on its tags to also provide a hierarchy for the tags on its drivers and templates. We recommend that you import the clang_cpp.py
file and run the format_cpp_annotations(json_object)
function on the intermediate JSON. When you do, you can use all of the convenient patterns and functions in our drivers and scripts.
The following example shows the same intermediate JSON object after processing by format_cpp_annotations()
.
// Output of format_cpp_annotations()
"type": "class",
"name": "SampleClass",
"annotations" : {
"MyExampleClassTags": {
"description" : "I am an example class!"
}
},
"fields": [
{
"name": "m_myData",
"annotations" : {
"MyExamplePropertyTags": {
"description" : "I am data!"
}
}
}
]
The following example shows how to automatically inject generated code back into the original file. The example extends the previously created
AzExampleClass
annotation by injecting code into the example class.
// Code Injection Macro
#if defined(AZ_CODE_GENERATOR)
# define AzExampleClass(ClassName, ...) AZCG_CreateArgumentAnnotation(AzExampleClass,
Class_Attribute, identifier(ClassName), __VA_ARGS__) int AZ_JOIN(m_azCodeGenInternal,
__COUNTER__);
Version 1.10
148
Lumberyard Developer Guide
Example Annotations
#else
# define AzExampleClass(ClassName, ...) AZ_JOIN(AZ_GENERATED_CODE_,ClassName)
#endif // AZ_CODE_GENERATOR
The updated annotation adds a new required parameter called
ClassName
, which is an identifier that is used to inject the code. The identifier is passed in to Clang as identifier(ClassName)
, and the data is provided to the intermediate JSON.
Up until this point, the annotation macro outside of
AZ_CODE_GENERATOR
has been blank. The next step is to have it expand to the identifier of the code-generated macro. This causes the generated code to replace the macro annotation when the generated file is put in an
#include
statement.
To implement this, the example sets the macro to become
AZ_JOIN(AZ_GENERATED_,ClassName)
. As before,
AZ_JOIN
in this example renders this as
AZ_GENERATED_CODE_ExampleClass
. The
ClassName parameter provides a name at compile time for the generated macro.
Note
It is not required that
ClassName
be the actual name of the class where the tag is used. Other tags that use this mechanism can simply require any unique identifier.
When the previous example code is updated, the following code is produced:
// Generated Injection Code class ExampleClass
{
AzExampleClass(ExampleClass, description("I am an example class!"));
AzExample(description("I am data!"))
int m_myData;
}
This code produces the following intermediate JSON. Note the new identifier annotation on the class.
Some data has been removed for readability.
// Generated Code Injection JSON
"type": "class",
"name": "SampleClass",
"annotations" : {
"AzExampleClass" : {
"identifier" : "ExampleClass",
"description" : "I am an example class!"
}
},
"fields": [
{
"name": "m_myData",
"annotations" : {
"AzExample" : {
"description" : "I am data!"
}
}
}
]
This result doesn't compile until the following template code used with the annotation produces the intended macro.
// Template Code
{% if class.annotations.identifier is defined %}
#define AZ_GENERATED_CODE_{{ asStringIdentifier(class.annotations.identifier) }}\ public: \
{# This method is injected for all classes with the AzExampleClass tag #}
Version 1.10
149
Lumberyard Developer Guide
Waf Debugging with AZ Code Generator bool IsExampleClass(void) { return true; }
{% endif %}
This code generates the following code for injection:
// Generated Code for Injection
#define AZ_GENERATED_CODE_ExampleClass \
bool IsExampleClass(void) { return true; }
If the generated header is placed in an
#include
statement in the original code, any code in this macro will be injected into
ExampleClass
.
AZ Code Generator is in preview release and is subject to change.
You can debug the integration output of Waf's Python scripts by using PyCharm and a few key debugging entry points. For more information about Waf integration itself, see
Integration with Waf (p. 133) .
Topics
•
•
Identifying and Configuring Debug Output (p. 150)
•
Setting Up PyCharm for Debugging Waf (p. 151)
Before you start, follow the instructions for
Setting Up PyCharm for Debugging Waf (p. 151)
. The
PyCharm debugger must be set up to debug lmbr_waf
before you can continue.
All AZ Code Generator Waf integration output is prefixed with az_code_gen
. To see additional output from both task creation and task execution, add
--zones=az_code_gen
to the Waf command line. This exposes the commands that invoke AZ Code Generator and are useful for debugging the AZ Code
To debug most configuration problems, it is best to set a breakpoint in the create_code_generator_tasks
method in dev\Tools\Build\waf-
<version>
\lmbrwaflib
\az_code_generator.py
. This method is called for each wscript
file that uses the az_code_gen
feature.
It directly interprets the given passes and generates an az_code_gen
task for each input file in each pass.
az_code_gen
The create_az_code_generator_task
feature creates az_code_gen
tasks. It gathers most information and inserts it into the task. Each task gets added to the az_code_gen_group
Waf task to ensure it is executed prior to other tasks.
Version 1.10
150
Lumberyard Developer Guide
Setting Up PyCharm for Debugging Waf
The run
and handle_code_generator_output
commands are important points in task execution.
The run
command takes the available information and generates a Clang-style arguments file prefixed with the
@
symbol. The arguments file is passed on the command line to the AZ Code Generator utility.
handle_code_generator_output
- The AZ Code Generator utility returns a JSON object with one or more entries that are parsed by handle_code_generator_output
. If the AZ Code Generator utility returns an invalid, non-JSON response due to errors during execution, the Waf task returns the error message
No JSON-Object could be decoded
. To discover the return value that could not be handled, run the command outside of Waf.
AZ Code Generator is in preview release and is subject to change.
PyCharm is an integrated development environment for Python which includes a graphical debugger that is useful for debugging Waf.
To set up PyCharm and Waf for debugging
1. Download PyCharm Community Edition .
2. Start PyCharm.
3. At the welcome screen, choose
Open Directory
.
4. From the Lumberyard root directory, navigate to any branch that contains a
_WAF_
or dev
directory.
There should be a file called wscript
and waf_branch_spec.py
under this folder.
5. Configure the Python interpreter.
a. Choose
File
,
Settings
,
Project:dev
,
Project Interpreter
to open the project interpreter page.
b. Click the gear icon on the right of the
Project Interpreter
and choose
Add Local
.
Version 1.10
151
Lumberyard Developer Guide
Setting Up PyCharm for Debugging Waf c.
Navigate to the folder where python.exe
resides. The Python executable file must be in the same folder as the project or you may have issues running Waf.
6. Set up a debugging profile for Waf.
a. To set up Waf for debugging, use the project explorer in the left pane. If you don't see the project explorer, press
Alt+1
). Navigate to the
\dev\Tools\Build\waf-
<version>
node and expand it. You should see a file called lmbr_waf
inside this node.
Version 1.10
152
Lumberyard Developer Guide
Setting Up PyCharm for Debugging Waf b. Right-click
lmbr_waf
and choose
Create lmbr_waf
Note
The
Indexing...
operation must finish before the option appears. You can verify status in the bar at the bottom.
c.
In the
Create Run/Debug Configuration
dialog, ensure that the following values are configured correctly:
•
Single instance only
should be selected.
•
Script Parameters
is the command to use to run Waf for the run/debug session.
•
Python Interpreter
should be the interpreter that you specified earlier.
• The
Working directory
must be the root of the project (for example, the dev
directory).
Version 1.10
153
Lumberyard Developer Guide
Setting Up PyCharm for Debugging Waf
Next, you must to set up wscript
files as debuggable Python files. Waf uses files called wscript to define the build rules per project. These are dynamically loaded Python modules that can be debugged like any other Python module. d. Choose
File
,
Settings
,
Editor
,
File Types
,
Python
.
e. To add a registered pattern for
wscript
, choose
Python
in
Recognized File Types
.
Version 1.10
154
Lumberyard Developer Guide
Setting Up PyCharm for Debugging Waf f.
Under
Registered Patterns
, click the green plus sign (
+
).
g. In the
Add Wildcard
dialog box, type in
wscript
.
7. Make sure
IncrediBuild
is turned off.
a. Open the
_WAF_/usersettings.options
file.
b. Verify that use_incredibuild
is set to false, as in the following example. use_incredibuild =
False
8. (Optional) Enable file outlining.
By default, file outlining is switched off in PyCharm. This feature facilitates navigation in the source files, as the following image shows.
Version 1.10
155
Lumberyard Developer Guide
Template Driver Debugging
To enable file outlining, right-click the
Project
tab and choose
Show Members
.
AZ Code Generator is in preview release and is subject to change.
Because template drivers are run from the AZ Code Generator executable using Python, you can't debug them directly. However, you can debug your driver and template code (and even Jinja2 itself) by using the debug.py
file included with AZ Code Generator.
To debug a template driver with a Python debugger like PyCharm or Visual Studio
1. Set the debugger to execute the
Bin64\azcg\debug.py
file. This file launches the utility to generate input JSON and emulates a code-generation pass in Python so that you can debug as if you were attached to the utility.
2. Set the working directory to
Bin64\azcg
.
3. Type the arguments for
AzCodeGenerator.exe
into a file with one argument per line. Or use a Waf-
generated arguments file as described in Waf Debugging with AZ Code Generator (p. 150) .
4. Set the arguments file, prefixed with
@
, as the argument to the script.
The following arguments are required:
•
-codegen-script
– Absolute path to the driver script that you want to debug.
•
-input-path
– Absolute path on which source file paths are based. Usually this path is the same as the location of the wscript for a given target.
•
-input-file
– Relative path from input path to the source file that is used for input.
•
-output-file
– Absolute path where generated code will be written.
After you have completed the preceding steps, you should be able to launch your debugger and set breakpoints in your driver script.
Version 1.10
156
Lumberyard Developer Guide
Debugging the AZ Code Generator Utility
For complete AZ Code Generator parameter information, see AZ Code Generator Parameters (p. 135)
.
AZ Code Generator is in preview release and is subject to change.
and your template drivers (p. 156) . You can also debug the AZ Code Generator utility
itself, although it is less likely to be necessary. You can debug the AZ Code Generator utility by using
Visual Studio in Windows or Xcode in macOS.
Topics
•
•
Debugging the AZ Code Generator Utility from the Waf build (p. 158)
•
Setting Visual Studio Debug Arguments (p. 158)
•
Setting Xcode Debug Arguments (p. 158)
The required preliminary steps depend on your operating system.
To debug AZ Code Generator using Visual Studio in Windows, you must generate a Visual Studio
HostTools solution (
.sln
) file.
To generate a Visual Studio HostTools solution file
1. Run the following command line from the dev
folder.
lmbr_waf.bat configure --enabled-game-projects= --specs-to-include-in-projectgeneration=host_tools --visual-studio-solution-name=HostTools
2. In Visual Studio, open the dev/Solutions/HostTools.sln
file.
To enable Waf support for Xcode, perform the following steps to generate an Xcode project.
To generate an Xcode project
1. Open the dev/_WAF_/specs/all.json
file.
2. Temporarily add
AzCodeGenerator
to modules
.
3. Run
./lmbr_waf.sh configure
to regenerate the Xcode project.
4. Open the dev/Solutions/LumberyardSDK.xcodeproj
file.
Version 1.10
157
Lumberyard Developer Guide
Debugging the AZ Code Generator
Utility from the Waf build
To debug the AZ Code Generator Utility from the Waf build, you must find the arguments file generated by Waf.
Waf generates an arguments file that is passed to AZ Code Generator as a command line parameter. All command line parameters from Waf for AZ Code Generator are contained inside the arguments file. This file is useful for debugging specific Waf AZ Code Generator invocations. To make the arguments file that you use available to Waf, add the
--zones=az_code_gen
option to the Waf command line.
When you use the
--zones=az_code_gen
option, the output looks like the following.
lmbr_waf build_win_x64_vs_2013_release -p all --zones=az_code_gen
[ 1/3150] az_code_gen (win_x64|release): BinTemp\win_x64_release\Code\Launcher
\WindowsLauncher\GameSDKWindowsLauncherStaticModules.json
14:24:17 az_code_gen Invoking code generator with command: g:\lyengine\Systems\dev
\Bin64\azcg\AzCodeGenerator.exe @g:\lyengine\Systems\dev\BinTemp\win_x64_release
\CodeGenArguments\arguments_file_ee625f9186107e30ab3126cc30cc9b49.args
In this example Waf output, the following is the arguments file.
@g:\lyengine\Systems\dev\BinTemp\win_x64_release\CodeGenArguments
\arguments_file_ee625f9186107e30ab3126cc30cc9b49.args
To set up debugging of AZ Code Generator from Visual Studio, perform the following steps.
To debug AZ Code Generator from Visual Studio
1. Perform the steps to set up Windows debugging as described in Prerequisites (p. 157) .
2. In the
Visual Studio Solution Explorer
, right-click
AzCodeGenerator
, and then select
Properties
.
3. Under
Debugging
, paste the path to the arguments file into
Command Arguments
.
4. Click
OK
to close the
Property
window.
5. Right-click
AzCodeGenerator
and then click
Set as StartUp Project
.
6. Press
F5
to launch the debugger.
To set up debugging of AZ Code Generator from Xcode, perform the following steps.
To debug AZ Code Generator from Xcode
1. Perform the steps to set up macOS debugging as described in
.
2. In Xcode, under the
Product
,
Scheme
menu, choose
AzCodeGenerator
.
3. At the bottom of the
Product
,
Scheme
menu, choose
Edit Scheme
.
4. Under
Arguments,
add a new entry to
Arguments Passed On Launch
that contains your debug arguments.
5. Under
Info
, from the
Executable
drop down, select
Other
.
a. Navigate to the directory dev/BinMac64.Debug/azcg/AzCodeGenerator
.
Version 1.10
158
Lumberyard Developer Guide
Intermediate JSON Data Format b. Click
Choose
.
6.
Close
the scheme editor.
7. Choose
Product, Run
to launch the debugger.
AZ Code Generator is in preview release and is subject to change.
The following JSON shows the intermediate data format consumed by Jinja2 user-defined templates.
{
"meta": {
"path": "
<Path/To/Code/Generator/Input/File.ext>
"
},
"objects": [
{
"name": "
<Name of class/struct>
",
"qualified_name": "
<Fully qualified name of class or struct>
",
"fields": [
{
"type": "
<member variable type>
",
"canonical_type": "
<member variable canonical type>
",
"name": "
<member variable name>
",
"qualified_name": "
<fully qualified member variable name>
",
"annotations": {
"<annotation name>": {
"
<annotation variable name>
": "
<annotation variable value (can
be empty string)>
",
...
},
...
}
},
...
],
"traits": {
"isAbstract":
<true if abstract class, false if concrete>
,
"isPOD":
<true of plain old data type; otherwise, false>
,
"isPolymorphic":
<true if polymorphic type; otherwise, false>
},
"bases" : [
{
"name" : "
<Base Class Name>
",
"qualified_name" : "
<Fully qualified name of base class>
"
},
...
],
"meta": {
"path": "
<Path/To/File/Containing/This/Object.ext>
"
},
"type":
<"class" or "struct">
,
"annotations": {
"
<annotation name>
": {
"
<annotation variable name>
": "
<annotation variable value (can be empty
string)>
",
...
},
...
},
Version 1.10
159
Lumberyard Developer Guide
Intermediate JSON Data Format
"methods": [
{
"name" : "
<method_name>
",
"qualified_name": "
<Fully qualified name of method>
",
"is_virtual":
<true if virtual method; otherwise, false>
,
"annotations": {
"<annotation name>": {
"
<annotation variable name>
": "
<annotation variable value (can
be empty string)>
",
...
},
"access": "
<Access level of method, one of: public, private,
protected>
",
"params" : [
{
"type" : "
<parameter type>
",
"canonical_type" : "
<parameter canonical type>
",
"name" : "
<parameter name>
"
},
...
],
"uses_override":
<true if override keyword is present; otherwise,
false>
,
"return_type": "
<return type of method>
"
},
...
]
},
...
]
}
Version 1.10
160
Lumberyard Developer Guide
Comparing AZ Modules to Legacy Modules
AZ modules are code libraries designed to plug into Lumberyard games and tools. An AZ module is a collection of C++ code built as a static or dynamic library (
.lib
or
.dll
file) that implements specific initialization functions. When a Lumberyard application starts, it loads each module and calls these initialization functions. These initialization functions allow the module to connect to core technologies
such as reflection, serialization, event buses (p. 576) , and the
Component Entity System (p. 455) .
Modules are not a new concept in Lumberyard. In fact, the Lumberyard game engine is a collection of older style modules. These legacy modules have served the game engine well, but they have a number of shortcomings which are addressed by AZ modules, as presented in the next section.
Lumberyard currently supports both legacy modules and AZ modules but going forward will use AZ modules. Beginning in Lumberyard 1.5, a gem can contain AZ module code. Creating a new gem is the easiest way to get up a new AZ module up and running.
Note
AZ is the namespace of the AZCore C++ library upon which AZ modules are built. The letters
AZ
refer to Amazon; the term is a preview name that has nothing to do with Amazon Availability
Zones and may be subject to change.
AZ modules have significant advantages over legacy modules, as the following table shows:
Topic
Compatibility
Legacy Modules
Modules can be converted to
AZ modules with no loss of functionality.
AZ Modules
Anything that can be done in a legacy module can also be done in an AZ module. Most
AZ module code could live within a legacy module, but legacy modules are not likely to be compatible with future
Version 1.10
161
Ease of adding services
Ease of use for low-level application features
Exposure of properties
Game engine dependency
Initialization functions
Order of initialization
Lumberyard Developer Guide
A Self-Aware Method of Initialization
(singleton classes) to modules
Adding services usually requires editing files in
CryCommon
. A file for the singleton's class interface must exist in the
CryCommon directory, and a variable to hold the singleton in gEnv must exist.
Modules load late, which prevents them from contributing low-level features to an application. All critical features must be in a single module that loads before others.
Modules have no uniform way to let users control settings for their service. Some services read settings from
.xml
assets directory, which must be edited by hand.
files in the
Modules must run in the game engine and are difficult to extend for use in tools that do not have game code.
Function parameters are specific to CryEngine.
AZ module–based Lumberyard tools.
Modules create components and attach them to the system entity. No editing of game engine files is required.
Modules load early in the application's startup sequence and are initialized in discrete stages. This allows
any
module to provide a low-level feature at an early stage that other modules can take advantage of later.
AZ modules expose the properties of system components to the Lumberyard reflection system. The reflection system makes information about these properties available to all other components.
Modules are not specific to the game engine and can be used outside it.
Singleton code often depends on services offered by other singletons, so modules must be initialized in a very particular order. However, the order is not obvious. If someone is unfamiliar with the code in the modules, their loading order is difficult to ascertain.
Function parameters are specific to the AZ framework; for more information, see the following section.
Each module explicitly states its dependencies on system components. After all system components are examined, they are sorted according to these dependencies and initialized in the appropriate order. Each module is a first-class citizen.
Legacy modules are loaded in a particular order. Because
CrySystem
is loaded and initialized before the game module, it must provide all low-level systems such as logging and file I/O that a subsequent module might depend on. The game module itself cannot provide such low-level systems because it’s initialized too late.
AZ modules, on the other hand, are all loaded as early as possible, and then initialized in stages.
Because each module explicitly states its dependencies on system components, all system components can be examined beforehand, sorted according to dependencies, and
initialized in the appropriate
Version 1.10
162
Lumberyard Developer Guide
Relationship with the AZ Framework
. This makes it possible for low-level functionality (like a custom logging system) to be implemented from a game module. For more information about the initialization order of components,
see The AZ Bootstrapping Process (p. 179) .
AZ modules are designed to work with the AZ framework, which is a collection of Lumberyard technologies such as reflection, serialization,
, and the component entity system . The AZ framework supports game development but can also be used outside it. For example,
Lumberyard tools like the Setup Assistant, Asset Processor and the component entity system use the
AZ framework and AZ modules, but contain no game code. When the Resource Compiler builds slices, it loads AZ modules to extract reflection information about components within them.
AZ modules are code libraries that are built to use the AZ framework. When an AZ framework application loads an AZ module, the AZ module knows how to perform tasks such as gathering reflection information about the data types defined within that library.
AZ modules build their services (which are singleton classes) by using the same component entity system that Lumberyard uses to build in-game entities. A module simply places a system component on the system entity. This solves many of the problems associated with singletons in legacy modules.
The GUI in Lumberyard Editor uses the reflection system to expose the properties of entities (gameplay components) to designers. In the same way, Lumberyard uses the reflection system to expose the properties of system components so that you can customize your settings for a particular game.
Because system components are really no different from gameplay components, you can
game components.
The
provided with Lumberyard are all built as AZ modules. In addition, there are two AZ modules that are not built as gems.
LmbrCentral
contains components that wrap functionality from legacy modules. For example, the
MeshComponent
utilizes
IRenderNode
under the hood.
LmbrCentral
is used by game applications.
Components can have editor-specific implementations that integrate with technology not available in the game runtime environment. Therefore, a separate module,
LmbrCentralEditor
, is used by
Lumberyard Editor. This module contains all the code from
LmbrCentral
, plus code that is only for use in tools. The
LmbrCentralEditor
module is not for use in standalone game applications.
An AZ module has three key components: a class that inherits from
AZ::Module
, one or more public facing event buses, and a system component class.
Version 1.10
163
Lumberyard Developer Guide
The Module Class
This page describes module initialization, the use of system components as singletons, how EBus calls communicate with this singleton, and how to call the module externally after you have created it.
Each AZ module must contain a class that inherits from
AZ::Module
. When the module is loaded by an application, an instance of the class is created very early in the application's lifetime and its
. This class
reflects (p. 458) the components declared in the module and adds critical
components to the system entity (p. 174)
.
Note
At its core, every Lumberyard application has a single system entity. When a Lumberyard application starts, it creates the system entity. This entity's components, known as system components, power major systems within Lumberyard. The system entity always has the ID
AZ::SystemEntityId (0)
.
The following skeleton code shows the basic structure of an
AZ::Module
class.
namespace AZ
{
/**
* AZ::Module enables static and dynamic modules (aka LIBs and DLLs) to
* connect with the running \ref AZ::ComponentApplication.
*
* Each module should contain a class which inherits from AZ::Module.
* This class must perform tasks such as reflecting the classes within
* the module and adding critical components to the system entity.
*/
class Module
{
public:
Module();
virtual ~Module();
/// Override to require specific components on the system entity.
virtual ComponentTypeList GetRequiredSystemComponents() const;
};
}
The
AZ::Module
class exposes all points of integration with the AZ framework as virtual functions. These points of integration have been created as virtual functions on a class so that, whether initialization code is in a static or dynamic library, it’s written the same way as much as possible. The very first actual initialization calls do need to be different for static and dynamic libraries. Lumberyard provides a macro to define this uninteresting glue code and let you write the interesting initialization code within your
AZ::Module
class.
We recommend that your
AZ::Module
class contain as little implementation code as possible. When the
AZ::Module
class is created, the application is just starting up and many systems are unavailable. If the
AZ::Module
class spawns a singleton or manager class, there is no guarantee that the systems on which this singleton relies will be ready for use. Instead, you should build your singletons as Lumberyard
system components (p. 168) , which can control their initialization order.
Beginning in Lumberyard 1.5, gems are built using AZ modules. The following example "HelloWorld" AZ module was made by creating a new gem . The
CryHooksModule
class in this example is a helper wrapper around
AZ::Module
and provides your entire module access to gEnv
.
// dev/Gems/HelloWorld/Code/Source/HelloWorldModule.cpp
#include "StdAfx.h"
#include <platform_impl.h>
Version 1.10
164
Lumberyard Developer Guide
The EBus
#include "HelloWorldSystemComponent.h"
#include <IGem.h> namespace HelloWorld
{
class HelloWorldModule
: public CryHooksModule
{
public:
AZ_RTTI(HelloWorldModule, "{39C21561-D456-413F-8C83-4214F6DBC5A5}",
CryHooksModule);
HelloWorldModule()
: CryHooksModule()
{
// Create descriptors for components declared within this module.
m_descriptors.insert(m_descriptors.end(), {
HelloWorldSystemComponent::CreateDescriptor(),
});
}
// Add required system components to the system entity.
AZ::
ComponentTypeList GetRequiredSystemComponents
() const override
{
return AZ::ComponentTypeList{
azrtti_typeid<HelloWorldSystemComponent>(),
};
}
};
}
// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM
// The first parameter should be GemName_GemIdLower
// The second should be the fully qualified name of the class above
AZ_DECLARE_MODULE_CLASS(HelloWorld_010c14ae7f0f4eb1939405d439a9481a,
HelloWorld::HelloWorldModule)
External code can call into your module, and receive events from your module, through the module's public
(EBus). The EBus allows simple and safe function calls between different modules of code.
A new gem comes with one EBus by default, as shown in the following example.
// dev/Gems/HelloWorld/Code/Include/HelloWorld/HelloWorldBus.h
#pragma once
#include <AzCore/EBus/EBus.h> namespace HelloWorld
{
class HelloWorldRequests
: public AZ::EBusTraits
{
public:
//////////////////////////////////////////////////////////////////////////
// EBusTraits overrides
// These settings are for a "singleton" pattern.
// A single handler can connect to the EBus.
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
// A single address exists on the EBus.
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
Version 1.10
165
Lumberyard Developer Guide
The System Component Class
//////////////////////////////////////////////////////////////////////////
// Put your public methods here
virtual void
SayHello
(const char* name) = 0;
};
using HelloWorldRequestBus = AZ::EBus<HelloWorldRequests>;
} // namespace HelloWorld
Calls to this EBus are handled by the system component, as described in the following section.
Any major systems in your module that require a singleton should be built as system components. New gems come with a system component by default. The system component class is created during application startup and attached to the system entity (see
GetRequiredSystemComponents()
in
HelloWorldModule.cpp
).
In the current example, the system component class handles calls to the public EBus declared in
HelloWorldBus.h
. The following code shows the
HelloWorldSystemComponent
class.
// dev/Gems/HelloWorld/Code/Source/HelloWorldSystemComponent.h
#pragma once
#include <AzCore/Component/Component.h>
#include <HelloWorld/HelloWorldBus.h> namespace HelloWorld
{
// The HelloWorldSystemComponent is placed on the system entity
// and handles calls to the HelloWorldRequestBus.
class HelloWorldSystemComponent
: public AZ::Component
, protected HelloWorldRequestBus::Handler
{
public:
// Every component definition must contain the AZ_COMPONENT macro,
// specifying the type name and a unique UUID.
AZ_COMPONENT(HelloWorldSystemComponent, "{72DFB0EE-7422-4CEB-9A40-426F26530A92}");
static void Reflect(AZ::ReflectContext* context);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType&
provided);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType&
incompatible);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType&
required);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType&
dependent);
protected:
////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Init() override;
void Activate() override;
void Deactivate() override;
////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////
// HelloWorldRequestBus interface implementation
void SayHello(const char* name) override;
////////////////////////////////////////////////////////////////////////
};
}
Version 1.10
166
Lumberyard Developer Guide
The System Component Class
// dev/Gems/HelloWorld/Code/Source/HelloWorldSystemComponent.cpp
#include "StdAfx.h"
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/Serialization/EditContext.h>
#include "HelloWorldSystemComponent.h" namespace HelloWorld
{
void HelloWorldSystemComponent::Reflect(AZ::ReflectContext* context)
{
// Reflect properties that developers may want to customize.
if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
{
serialize->Class<HelloWorldSystemComponent, AZ::Component>()
->Version(0)
->SerializerForEmptyClass();
if (AZ::EditContext* ec = serialize->GetEditContext())
{
ec->Class<HelloWorldSystemComponent>("HelloWorld", "Says hello")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu,
AZ_CRC("System"))
->Attribute(AZ::Edit::Attributes::AutoExpand, true)
;
}
}
}
void
HelloWorldSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType&
provided)
{
provided.push_back(AZ_CRC("HelloWorldService"));
}
void
HelloWorldSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType&
incompatible)
{
// Enforce singleton behavior by forbidding further components
// which provide this same service from being added to an entity.
incompatible.push_back(AZ_CRC("HelloWorldService"));
}
void
HelloWorldSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType&
required)
{
// This component does not depend upon any other services.
(void)required;
}
void
HelloWorldSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType&
dependent)
{
// This component does not depend upon any other services.
(void)dependent;
}
void HelloWorldSystemComponent::Init()
{
}
void HelloWorldSystemComponent::Activate()
Version 1.10
167
Lumberyard Developer Guide
Calling the Module from External Code
{
// Activate() is where the component "turns on".
// Begin handling calls to HelloWorldRequestBus
HelloWorldRequestBus::Handler::BusConnect();
}
void HelloWorldSystemComponent::Deactivate()
{
// Deactivate() is where the component "turns off".
// Stop handling calls to HelloWorldRequestBus
HelloWorldRequestBus::Handler::BusDisconnect();
}
void HelloWorldSystemComponent::SayHello(const char* name)
{
AZ_Printf("HelloWorld", "Hello %s, you certainly look smashing tonight.", name);
}
}
For more information about system components, see
.
To call your module, invoke your public function through EBus. This example uses the
SayHello
function.
#include <HelloWorld/HelloWorldBus.h> void InSomeFunctionSomewhere()
{
// ...
// Invoke the call through EBus.
EBUS_EVENT(HelloWorld::HelloWorldRequestBus, SayHello, "Bruce");
// ...
}
A traditional game engine contains many singleton classes, each in charge of a major system. In
Lumberyard, these singletons are built using the same component entity system that powers gameplay entities. When an application is starting up, a
system entity
is created. Any components placed on this entity are known as
system components
. The system entity always has the ID
AZ::SystemEntityId (0)
.
When you build singletons as Lumberyard system components, you are using a powerful suite of complementary technologies that facilitate problem resolution through established patterns. This topic describes system components in detail.
As a game engine grows in size, it tends to develop many singleton classes. A singleton class often requires communication with other singletons to function. This means that the order in which singletons are initialized is very important. Lumberyard solves this by building singletons as components.
A component can declare which services it provides, and it can declare which other services it depends on. When components are activated, they are sorted according to these declared dependencies, ensuring proper initialization order.
The following example shows two components that Lumberyard has ordered for initialization.
Version 1.10
168
Lumberyard Developer Guide
Easily Configurable Components class
AssetDatabaseComponent
: public Component
{
...
static void GetProvidedServices(ComponentDescriptor::DependencyArrayType& provided)
{
provided.push_back(AZ_CRC("AssetDatabaseService"));
}
...
}; class
AssetCatalogComponent
: public AZ::Component
{
...
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("AssetDatabaseService"));
}
...
};
The example shows how
AssetDatabaseComponent
is activated before
AssetCatalogComponent
. In the
AssetDatabaseComponent
class, the
GetProvidedServices
function reveals that the class provides a service called
AssetDatabaseService
. In the
AssetCatalogComponent
class, the
GetRequiredServices function reveals that
AssetCatalogComponent
depends on
AssetDatabaseService
. Lumberyard understands this dependency and orders the initialization order accordingly.
For more information about the initialization order of components, see The AZ Bootstrapping
.
Often, a singleton has settings that are configurable for each game. It can be difficult for a low-level singleton to access configuration data because the system used to process this data hasn't yet started.
Therefore, low-level singletons often rely on simple data sources such as command line parsers or
.ini
files.
A system component can expose its configuration through AZ reflection
. The Advanced Settings dialog box in the Project Configurator (p. 174)
uses this feature to enable you to configure system components on a per-game basis. The Project Configurator saves an
application descriptor file (p. 178)
that contains the settings for each system component, and this file is used to bootstrap the application and configure each component before it is activated. This is the same technology that the Entity
Inspector uses to configure gameplay entities in the Lumberyard Editor. For more information, see
Configuring System Entities (p. 174)
.
To designate a component as a system component, rather than a gameplay component, you must set the
AppearsInAddComponentMenu
field to
System
when you reflect to the
EditContext
.
The following example code designates the
MemoryComponent
as a system component.
void MemoryComponent::Reflect(ReflectContext* context)
{
if (SerializeContext* serializeContext = azrtti_cast<SerializeContext*>(context))
{
...
if (EditContext* editContext = serializeContext->GetEditContext())
Version 1.10
169
Lumberyard Developer Guide
Required System Components
{
editContext
->Class<MemoryComponent>("Memory System", "Manages memory
allocators")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::
AppearsInAddComponentMenu
,
AZ_CRC("
System
"))
...
}
}
}
Often, a module requires the existence of a system component. This requirement can be established through the module's
GetRequiredSystemComponents()
function. Any component type declared here is guaranteed to exist when the application starts.
In the following example, the
OculusDevice
component is required by the Oculus Gem.
AZ::ComponentTypeList OculusGem::GetRequiredSystemComponents() const override
{
return AZ::ComponentTypeList{
azrtti_typeid<OculusDevice>(),
};
}
If a system component is optional, you can add it from
Advanced Settings in the Project
The gems system was developed to make it easy to share code between projects. Gems are reusable packages of module code and/or assets which can be easily added to or removed from a Lumberyard game. Gems also promote writing code in a way that is more modular than that found in legacy libraries.
For example, each gem has its own include folder for its public interface code files. Gems also come with package management metadata such as semantic versioning and the ability to state dependencies on other gems.
A gem's directory contents are organized as follows:
GemDirectory/
Assets/
(assets usable to projects)
Code/
Include/
(public interface code files)
Source/
(private implementation code files)
Tests/
(code files for tests)
wscript (waf build info)
gem.json (gem metadata)
Version 1.10
170
Lumberyard Developer Guide
Waf Integration
Each game project must explicitly list the gems that it uses. When the Waf build system runs, it builds only those gems which are actively in use. Waf also makes a gem’s include/
directory accessible to any gems or projects that explicitly depend upon the gem.
Beginning with Lumberyard 1.5, all gems that ship with Lumberyard are built as AZ modules. When you build a gem as an AZ module, the gem uses the initialization functions expected by the AZ framework.
An AZ module gem has public interfaces that are event buses (p. 576) and is better integrated with
the new component entity system . Although legacy gems are still supported, it is highly recommended that you use gems based on AZ modules going forward. For information on migrating a legacy gem, see
Converting Your Gems .
When you use the Project Configurator to enable or disable a gem, Lumberyard updates the
application descriptor file (p. 178)
accordingly to ensure it references all AZ modules. If you edit the dev
\<project_asset_directory>\gems.json
list of gems by hand, you can use the following command to bring the application descriptor file up to date: dev\Bin64\lmbr.exe projects populate-appdescriptors
The
GemFormatVersion
value is versioning for how a gem is built. Gem version numbers like
0.1.0
refer to the gem's API version.
Gems from Lumberyard 1.4 and earlier (legacy gems) all have a
GemFormatVersion
value of
2
. Starting in
Lumberyard 1.5, all the gems included with Lumberyard are AZ modules and have a
GemFormatVersion value of
3
. This tells Lumberyard that the gem is an AZ module and that it should be loaded accordingly.
A gem may also have an API version number like
0.1.0
. This is independent of the
GemFormatVersion
.
The API version alerts your users to API changes. If the API version number changes, then users of the gem may need to make changes to their code. For example, the Rain Gem will stay at version
0.1.0
until its API changes. If you were using the Rain Gem from Lumberyard 1.4, you can still use the Rain Gem from Lumberyard 1.5 without changing any of your data or code.
For more information about gems, see Gems in the Amazon Lumberyard User Guide .
AZ modules are in preview release and subject to change.
Beginning with Lumberyard 1.5, gems are AZ modules, so the preferred way to build an AZ module is to simply create a new gem. However, if your project requires an AZ module that must not be built as a gem, follow the steps provided here.
Because gems have all the required code for an AZ module, it's easier to create a gem first and then modify it not to be a gem. As an added convenience, the new gem names the code for you in an
intuitive way. For an explanation of the code that you get in a new gem, see Parts of an AZ Module,
Version 1.10
171
Lumberyard Developer Guide
B. Modify the AZ Module Declaration
To create and modify a gem
1. First, create a gem by performing the following steps: a. Go to your Lumberyard
\dev\Bin64\ directory, then run
ProjectConfigurator.exe
.
b. Select your project (the default is
SamplesProject
).
c.
Click
Enable Gems
.
d. Click
Create a New Gem
.
e. Type the name for your new module. (The example on this page uses the name "HelloWorld".) f.
Click
Ok
.
2. Move and rename the code
directory from the new gem to your desired location. For example, move the directory dev/Gems/HelloWorld/Code to dev/Code/
<optional subfolder>
/HelloWorld
3. To remove the remaining noncode pieces of the gem, delete the directory dev/Gems/HelloWorld
.
AZ modules that are not gems must not have UUIDs in their names, so you must modify the gem's
.cpp
file accordingly.
To modify the
.cpp
file
1. Remove the code that looks like the following:
// DO NOT MODIFY THIS LINE UNLESS YOU RENAME THE GEM
// The first parameter should be GemName_GemIdLower
// The second should be the fully qualified name of the class above
AZ_DECLARE_MODULE_CLASS(HelloWorld_010c14ae7f0f4eb1939405d439a9481a,
HelloWorld::HelloWorldModule)
2. Replace the
AZ_DECLARE_MODULE_CLASS
declaration with one that follows this syntax:
AZ_DECLARE_MODULE_CLASS(HelloWorld, HelloWorld::HelloWorldModule)
The first argument (
HelloWorld
) is a unique identifier to be included in your project.json
file, and should match the target
field of your wscript. You will do these steps later. The second argument is the same fully qualified name of the class already defined in your
.cpp
file.
If your module does not access code from CryEngine (for example, it does not access gEnv
), perform these additional steps.
To remove CryEngine references
1. Make the following changes to your
.cpp
file (in this example,
HelloWorldModule.cpp
).
a. Remove
#include <platform_impl.h> b. Remove
#include <IGem.h>
Version 1.10
172
Lumberyard Developer Guide
D. Modify the Wscript and Waf Spec Files c.
Add
#include <AzCore/Module/Module.h> d. Change
HelloWorldModule
to inherit directly from
AZ::Module
instead of from
CryHooksModule
.
2. Remove the following include statement from the
StdAfx.h
file:
#include <platform.h> // Many CryCommon files require that this be included first.
Next, you must modify the default wscript file to remove gem-specific commands, add your module directory to the wscript file, and add your module to the appropriate waf spec files .
To modify the wscript and waf spec files
1. Modify the wscript contents to resemble the following: def build(bld):
bld.CryEngineModule(
target = 'HelloWorld',
vs_filter = 'Game', # visual studio filter path
file_list = 'HelloWorld.waf_files',
platforms = ['all'],
configurations = ['all'],
pch = ['source/StdAfx.h'],
use = ['AzFramework'],
includes = ['include', 'source'],
)
2. Modify the wscript in a parent directory so that waf recurses your module's directory, as in the following example.
# ...
SUBFOLDERS = [
# ...,
'HelloWorld'
]
# ...
3. To enable waf to build your module, add the module to the appropriate waf spec files in your
Lumberyard directory ( dev\_WAF_\specs\*.json
), as in the following example:
{
// ...
"modules":
{
// ...
"HelloWorld"
}
// ...
}
When your project launches, it loads the modules listed in the dev/
<project_assets>
/Config/
Game.xml
file (the
Editor.xml
file is used when the Lumberyard Editor is launched). These files are automatically generated and should not be edited by hand.
Version 1.10
173
Lumberyard Developer Guide
F. Add the Module's Public Interfaces to Your Project's Include Paths
To configure your project to load your AZ module
1. To ensure your non-gem module is included in these automatically generated lists, add the following lines to your project.json
file (path location dev/
<project_asset_folder>
/ project.json
):
{
// ...
"flavors": {
"Game": {
"modules": [
"LmbrCentral",
"HelloWorld"
]
},
"Editor": {
"modules": [
"LmbrCentralEditor",
"HelloWorld"
]
}
}
}
Note
The flavors section may be missing from your project. If it is not present,
Lumberyard assumes that the
LmbrCentral
module is used for
Game
, and that the
LmbrCentralEditor
module is used for
Editor
.
2. From the dev directory, run the following command from a command prompt.
Bin64\lmbr.exe projects populate-appdescriptors
This command modifies the
Game.xml
and
Editor.xml
files to list the
HelloWorld
module.
Finally, to make your AZ module's public interfaces available to the rest of your project, you must inform them project of your module's include
directory.
To make your AZ modules public interfaces available to your project
• In your project's wscript file, edit the includes
line to point to your project's include directory, as in the following example.
# ...
includes = [..., bld.Path('Code/Engine/HelloWorld/include')],
# ...
A single
system entity
lives at the heart of every Lumberyard application. This entity's components,
known as system components (p. 168)
, power major systems within Lumberyard. You can use the
Version 1.10
174
Lumberyard Developer Guide
Configuring System Entities
Advanced Settings
dialog of the Project Configurator to choose the components for your project and configure them. Editing a system entity is like editing an entity in the Entity Inspector .
To configure system entities
1. Compile a profile build of your project so that the Project Configurator can load your project's compiled code.
2. Go to your Lumberyard
\dev\Bin64\
directory, and then launch
ProjectConfigurator.exe
3. In Project Configurator, select your project.
4. Click
Advanced Settings
.
The first time a system entity configuration is loaded, you are prompted to add any required components that are missing from the system entity.
Some system components are optional, and some are required. Both the Lumberyard engine and the gems used by your project may require certain components.
5. Click
Yes
. Even if you decline, the required components are created at run time.
6. Use the
Project
option at the top of the
Advanced Settings
dialog box to select the project that you want to edit. For the
Configuration
option, choose
Game
if you want to make changes to the
Game
(launcher) system entity, or
Editor
to modify the
Editor
system entity.
Version 1.10
175
Lumberyard Developer Guide
Configuring System Entities
The
System Entity
tab lists components that have been added.
7. Click
Add Component
to select from a variety of components to add.
Version 1.10
176
Lumberyard Developer Guide
Configuring System Entities
8. To remove a component, right-click the component in the list and choose
Remove Component
"
<ComponentName>
"
.
9. On the
Memory Settings
tab, expand
System memory settings
to configure system memory options.
10. Click
Save
to save your changes to disk. The changes are saved to an application descriptor file, described next.
Version 1.10
177
Lumberyard Developer Guide
Application Descriptor Files
When you edit a system entity's configuration by using the
Advanced Settings
dialog box of Project
Configurator, you are actually editing an application descriptor file.
Application descriptor files are new to Lumberyard 1.5 and list all modules that a project uses. Currently, each project requires two application descriptor files in its asset directory: dev/<project_asset_directory>/Config/Game.xml
dev/<project_asset_directory>/Config/Editor.xml
In the Project Configurator
Advanced Settings
dialog box, these files correspond to the
Game
and
Editor
options in the
Configuration
menu.
The following example shows the beginning of a
Game.xml
file. Both the
Game.xml
file and the
Editor.xml
file have the same structure.
<ObjectStream version="1">
<Class name="ComponentApplication::Descriptor"
type="{70277A3E-2AF5-4309-9BBF-6161AFBDE792}">
<Class name="bool" field="useExistingAllocator" value="false" type="{A0CA880C-
AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="grabAllMemory" value="false" type="{A0CA880C-
AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="allocationRecords" value="true" type="{A0CA880C-
AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="autoIntegrityCheck" value="false" type="{A0CA880C-
AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="markUnallocatedMemory" value="true" type="{A0CA880C-
AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="doNotUsePools" value="false" type="{A0CA880C-
AFE4-43CB-926C-59AC48496112}"/>
<Class name="bool" field="enableScriptReflection" value="true" type="{A0CA880C-
AFE4-43CB-926C-59AC48496112}"/>
<Class name="unsigned int" field="pageSize" value="65536"
type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="poolPageSize" value="4096"
type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="unsigned int" field="blockAlignment" value="65536"
type="{43DA906B-7DEF-4CA8-9790-854106D3F983}"/>
<Class name="AZ::u64" field="blockSize" value="0" type="{D6597933-47CD-4FC8-
B911-63F3E2B0993A}"/>
<Class name="AZ::u64" field="reservedOS" value="0" type="{D6597933-47CD-4FC8-
B911-63F3E2B0993A}"/>
<Class name="AZ::u64" field="reservedDebug" value="0" type="{D6597933-47CD-4FC8-
B911-63F3E2B0993A}"/>
<Class name="char" field="recordsMode" value="2" type="{3AB0037F-AF8D-48CE-BCA0-
A170D18B2C03}"/>
<Class name="unsigned char" field="stackRecordLevels" value="5"
type="{72B9409A-7D1A-4831-9CFE-FCB3FADD3426}"/>
<Class name="bool" field="enableDrilling" value="true" type="{A0CA880C-
AFE4-43CB-926C-59AC48496112}"/>
<Class name="AZStd::vector" field="modules" type="{2BADE35A-6F1B-4698-
B2BC-3373D010020C}">
<Class name="DynamicModuleDescriptor" field="element" type="{D2932FA3-9942-4FD2-
A703-2E750F57C003}">
<Class name="AZStd::string" field="dynamicLibraryPath" value="LmbrCentral"
type="{EF8FF807-DDEE-4EB0-B678-4CA3A2C490A4}"/>
</Class>
[...]
Version 1.10
178
Lumberyard Developer Guide
The AZ Bootstrapping Process
The list of system components in the application descriptor file corresponds to the list of components on the
System Entity
tab in the
Advanced Settings
dialog box. Each component can have its own settings.
The application descriptor file also contains properties that determine how to allocate memory. These correspond to the settings on the
Memory Settings
tab in the
Advanced Settings
dialog box.
An AZ framework application initializes modules based on the dynamic libraries listed in the
application descriptor file (p. 178)
, and the static libraries referenced from the
CreateStaticModules()
function.
When an
AzFramework::Application
starts, the following order of events takes place:
1. The executable starts.
2. The
AzFramework::Application
class is initialized. It takes a path to an application descriptor file and a pointer to a function that will create the
AZ::Modules
from static libraries.
3. The application bootstraps itself just enough to read the application descriptor file.
4. The application descriptor file is read to get memory allocator settings and the list of dynamic libraries to load. Lumberyard is not yet able to read the system entity from the file.
5. Lumberyard shuts down the bootstrapped systems, configures them according to the settings it just loaded, and starts these systems back up.
6. Each dynamic library is loaded.
7. Each dynamic library’s
InitializeDynamicModule()
function is run, which attaches the DLL to the global
AZ::Environment
.
8. Each static library’s
AZ::Module
instance is created using the function pointer passed in during step 2.
9. Each dynamic library’s
AZ::Module
instance is created by its
CreateModuleClass()
function.
10.Each AZ module's
RegisterComponentDescriptors()
function is called. Now the application knows how to serialize any components defined within a library.
11.The application descriptor file is read again to extract the system entity along with its components and their settings.
12.Each AZ module's
GetRequiredSystemComponents()
function is called. If any components are missing from the system entity, they are added.
13.The system entity is activated, and all of its system components are activated in the proper order.
At this point, initialization has been completed and the game is running.
Version 1.10
179
Lumberyard Developer Guide
Features
Deeply integrated with AWS, Cloud Canvas is a suite of tools and solutions (cloud gems, resource groups, flow nodes) designed to achieve two main goals:
1. Make it easy for you to build cloud-connected features, so you can focus on innovation rather than on undifferentiated backend infrastructure.
2. Make it possible for you to create fantastic new experiences made possible by the availability of the on-demand, global storage and compute provided by AWS.
With Cloud Canvas, you can add a cloud-connected feature to your game in as little as 30 minutes.
A single engineer can do this, freeing up the rest of your team to think about innovation and player experience.
Cloud Canvas offers a wide range of helpful components:
• The Cloud Gems Framework, on top of which cloud gems are built, allows you to add pre-packaged, cloud-connected features in a few clicks.
• Tools to enable a team to build a game with cloud-connected features.
• Flow graph nodes to communicate directly from within the client to AWS services such as Amazon S3,
Amazon DynamoDB, Amazon Cognito, AWS Lambda, Amazon SQS, and Amazon SNS.
• Tools to manage AWS resources and permissions that determine how developers and players access them.
• Management of AWS deployments so that development, test, and live resources are maintained separately.
• Methods for players to be authenticated (anonymous and authenticated). Players can be authenticated from a variety of devices and access their game data by logging in with an Amazon, Facebook, or
Google account.
Consider the many ways you can use Amazon Web Services for connected games:
Version 1.10
180
Lumberyard Developer Guide
Tools
• Store and query game data such as player state, high scores, or world dynamic content: Amazon S3 and DynamoDB
• Trigger events in real time and queue data for background processing: Amazon SQS and Amazon SNS
• Execute custom game logic in the cloud without having to set up or manage servers: AWS Lambda
• Employ a daily gift system that tracks user visits and rewards frequent visits: Amazon Cognito , Amazon
S3 , DynamoDB , AWS Lambda
• Present a message of the day or news ticker that provides updates on in-game events: Amazon
Cognito , Amazon S3 , AWS Lambda
For tutorials on Cloud Canvas, see
Tutorial: Getting Started with Cloud Canvas (p. 190) and
Lumberyard
Tutorials .
You can access Cloud Canvas functionality by using any of the following:
•
– Fully fledged cloud-connected features such as Message of the Day,
Leaderboards, and Dynamic Content that can be used in a few clicks as is, or as samples to fuel your custom developments and ideas.
•
– A web application that makes backend administration and management accessible to everyone.
•
Flow Nodes
– For designers to leverage the AWS cloud. For detailed information on the Cloud Canvas
flow graph nodes, see the Cloud Canvas Flow Graph Node Reference (p. 273)
.
•
Cloud Canvas C++ APIs
– For software development.
•
Using the Cloud Canvas Command Line (p. 435)
– For managing resource groups, mappings,
deployments, and projects.
•
Cloud Canvas Tools in Lumberyard Editor (p. 199)
– For managing AWS resources, deployments,
and credentials, and for navigating directly to the AWS consoles supported by Cloud Canvas.
You need the following to take advantage of Cloud Canvas:
•
An understanding of AWS CloudFormation Templates
– Cloud Canvas uses the AWS CloudFormation service to create and manage AWS resources. Our goal is for Cloud Canvas to minimize what you need to know about AWS CloudFormation and AWS in general.
•
Familiarity with JSON
– Cloud Canvas leverages JSON for storing configuration data, including AWS
CloudFormation Templates. Currently, you'll need to be familiar with this text format to work with the
Cloud Canvas resource management system. A JSON tutorial can be found here .
Topics
•
Cloud Canvas Overview (p. 182)
•
Cloud Canvas Game Play Design and Engineering Guide (p. 199)
•
Cloud Canvas Software Engineering Guide (p. 295)
•
Administering Cloud Canvas (p. 408)
•
Using the Cloud Canvas Command Line (p. 435)
Version 1.10
181
Lumberyard Developer Guide
Overview
Cloud Canvas helps you manage cloud resources and connect your game with the AWS cloud.
Understanding its concepts will benefit anyone on your team who interacts with the cloud-connected components of your game, including designers, programmers, and testers.
This section covers the following:
• What Cloud Canvas is and how it relates to your AWS account
• The Amazon Web Services that Cloud Canvas supports
• How Cloud Canvas helps you manage your resources
• How your game can communicate with the cloud through the flow graph visual scripting system
Before reading this topic, you should have a basic understanding of the Lumberyard engine and the flow graph system .
Amazon Web Services (AWS) is an extensive and powerful collection of cloud-based services. You can use these services to upload or download files, access databases, execute code in the cloud, and perform many other operations. A cloud service saves you the trouble of maintaining the infrastructure that it relies on.
When you want to use an AWS cloud service, you do so through a resource, a cloud-based entity that is available for your use, help, or support. Resources include a database, a location for storing files, the code that a service runs, and more.
When you create a resource, it exists in the cloud, but you can use it and manage its content. You also specify the permissions that individuals or groups have to access or use the resource. For example, you might allow anyone in the public to read from your database but not write to it or modify it.
In order to create a connected game feature such as a high score table, you create a resource group in
Cloud Canvas. The resource group defines the AWS resources that your feature requires. Each connected game feature therefore is implemented as a resource group in Cloud Canvas.
Your resources are owned by an AWS account. The AWS account allows you and your team to share access to the same resources. For example, your team’s AWS account might own a database resource so that you and your teammate can both work with the same database.
You, or someone on your team, is an administrator. The administrator creates the AWS account for your team and gives individuals on the team access to the account's resources.
Cloud Canvas is a Lumberyard Gem (extension) that enables your Lumberyard games to communicate with AWS resources. To integrate the communication with Amazon Web Services directly into your game logic, you use Lumberyard's flow graph visual scripting system.
Version 1.10
182
Lumberyard Developer Guide
Amazon Web Services Supported by Cloud Canvas
The flow graph nodes that you create use Cloud Canvas to make the actual calls from your game to
AWS resources. For example, when a player’s game ends, you can add flow graph nodes to submit the player's score to a high score table in the cloud. Later, you can use flow graph to call the high score table to request the top 10 scores.
Several AWS offerings are available through Cloud Canvas that can enhance your game.
For storing files in the cloud, Cloud Canvas supports Amazon Simple Storage Service (Amazon S3).
Amazon S3 offers a storage resource called a bucket, which you can think of as a large folder. You can build a directory structure in an Amazon S3 bucket just like a directory on a local computer. Amazon S3 buckets have a number of uses in games, including the following:
• Storing files that your game can download. These files can be levels, characters, or other extensions for your game. You can add new files after your game has shipped. Because your game uses Cloud
Canvas to download and integrate this content, your customers do not need to download a new client.
• Your game can upload user-generated content. For example, your game might take a screenshot whenever a player beats the last boss. Cloud Canvas uploads the screenshot to your bucket, and your game makes the screenshot available on a website or to other players of the game.
For storing data like a person’s name, phone number, and address in the cloud, Cloud Canvas supports the Amazon DynamoDB database service. Amazon DynamoDB operates on resources called tables. These tables grow and adapt as you build and iterate your game.
Here are some ways in which you can use Amazon DynamoDB table resources in your game:
• Track account details and statistics for a player. Give each player a unique ID so that you can look up a player's hit points, inventory, gold, and friends.
• Add or remove fields to accommodate new resource groups in your game.
• Perform data analyses. For example, you can run complex queries to find out how many players have unlocked a particular achievement.
• Manage game-wide resource groups or events such as a querying a high score table or retrieving a message of the day.
For executing code in the cloud, Cloud Canvas supports the AWS Lambda service. AWS Lambda executes resources called functions. You provide the code for a Lambda function, and your game calls the Lambda service through Cloud Canvas to run the function. The Lambda service returns the data from the function to the game.
Your Lambda functions can even call other Amazon Web Services like Amazon DynamoDB and perform operations on their resources. Following are some examples:
•
Submit a high score
– A Lambda function can accept a player's ID and new score, look up the player ID in the database, compare the score with existing scores, and update the highest score if necessary.
•
Sanitize your data
– A Lambda function can check for malicious or unusual input. For example, if a player tries to upload a new high score of 999,999,999 when the best players can't reach 1,000, your
Lambda function can intercept the submission and either reject it or flag it for review.
Version 1.10
183
Lumberyard Developer Guide
Understanding Cloud Canvas Resource Manager
•
Perform server-side authoritative actions
– Cloud Canvas can call your Lambda functions to control in-game economies. For example, when a player tries to purchase an item, your Lambda function can check a database to verify that the player has enough money to pay for the item. The function can then deduct the amount from the player's account, and add the item to the player’s inventory.
For managing the identity of the player and controlling access to AWS resources in the cloud, Cloud
Canvas supports the Amazon Cognito service.
Amazon Cognito can create unique anonymous identities for your users tied to a particular device. It can also authenticate identities from identity providers like Login with Amazon, Facebook, or Google. This provides your game with a consistent user IDs that can seamlessly transition from anonymous use on a single device to authenticated use across multiple devices. Consider these examples:
• Players start playing your game anonymously and store their progress locally on their device. Later, to "upgrade" their experience, you ask them to be authenticated through one of the login providers mentioned. After players provide an authenticated ID, you can store their progress in the cloud, and they can access their progress across multiple devices.
• You can specify which AWS resources players are allowed to access. For example, you can enable the
"Get the Latest High Scores" Lambda function to be called not only by your game, but by anyone, including external websites. But you could specify that the "Submit High Scores" function only be called by players of your game so that your high score table remains secure. You can use Cloud Canvas to manage these permissions.
Game development is an inherently local activity. You have a local copy of your game code, assets, and other resources. You build, test, and tweak over and over on your local computer.
The cloud is different. It is an alien environment. You put resources "out there" that the game depends on. But those resources don’t live on your computer system. The process of using and modifying the resources in the cloud isn’t the same as for resources that are local.
Cloud Canvas Resource Manager
bridges this gap. It lets you have local
descriptions
of the AWS resources in the cloud that your game needs and provides ways to create and interact with the actual instances of those resources in AWS. Your resource could be a database table, a file storage bucket, or code that runs in response to an event.
For team projects, the source code and assets that you are using likely come from a source control system. The changes you make are shared with other people who work on the project through that source control system. Different people can be working at the same time with different versions
(“branches”) of the code and with different versions of assets without interfering with each other.
When you develop a game that uses cloud resources in AWS, those resources may be shared by different people who work on the game at the same time. Sometimes you need different versions of those resources to exist in the cloud. You also want to ensure that the people developing the game use the version of the resources in the cloud that matches the version of the code and assets they are working with.
Version 1.10
184
Lumberyard Developer Guide
Understanding Cloud Canvas Resource Manager
After the game is released, the players will use a production copy while your team uses another, private copy to work on bug fixes and new content.
You'll also want to do the following:
• Be sure that players cannot access the development versions of game resources
• Prevent the development team from making changes that could break the released game
• Protect player information like e-mail addresses from unauthorized access by team members
The
Cloud Canvas Resource Manager
provides the tools you need to do the following:
• Maintain descriptions of the AWS resources that your game depends on
• Create as many copies of the AWS resources as needed for your releases and development teams
• Help you secure access to those resources
The
Cloud Canvas Resource Manager
integrates the use of AWS CloudFormation into the Lumberyard game development environment. With AWS CloudFormation you can maintain descriptions of the AWS resources you need in text file templates that you can check into your source control system. These descriptions can be branched and merged along with the rest of your game code and assets. When you need actual instances of the resources to be created in AWS,
Cloud Canvas Resource Manager
passes the descriptions to AWS CloudFormation, which uses the template files to create, update, or delete resources in AWS to match the descriptions.
Version 1.10
185
Lumberyard Developer Guide
Understanding Cloud Canvas Resource Manager
You can use resource manager to organize your descriptions into any number of
resource groups
. Each group can describe all the resources needed by a game feature, such as a high score tracking system. For details, see Resource Definitions .
With resource manager you can create as many
deployments
of the resources as you need. You could have a deployment for the dev team, another for the QA team, and another for the released game, or any other arrangement that suits your needs. Each deployment contains a complete and independent instance of all of the project's resources. Deployments are implemented using AWS CloudFormation
stack
resources. For details, see Resource Deployments .
You can choose the deployment that you want to work with in Lumberyard Editor. For example, if you create a "QA" deployment and use it to test your game, Lumberyard Editor automatically maps the references to resources in your game code and Flow Graphs to the "QA" instance of those resources.
Similarly, you can also specify the deployment to be used for release builds of the game. For details, see
Resource Mappings .
Each deployment comes with an AWS managed policy and an AWS role that you can use to grant specific
AWS users and groups access to that deployment. For example, players are granted access to specific resources within a deployment. For details, see
Controlling Access to Resources (p. 420)
.
A Closer Look at AWS CloudFormation Stacks
A Cloud Canvas Resource manager project consists of one or more AWS CloudFormation stacks. All stack templates are stored as files in the project's source control system.
• A single
project stack
that contains the resources that support Cloud Canvas Resource Manager itself.
The project stack template is stored as a file in the project's source control system.
• Any number of
deployment stacks
. A deployment represents a complete and independent set of all the resources needed by the game. Each deployment stack contains a child stack for each resource group.
All deployment stacks are defined using a single AWS CloudFormation stack template.
• One
deployment access stack
per deployment stack. A deployment's access stack defines the resources used to grant access to a deployment, including IAM Roles and Amazon Cognito Identity Pools. They are distinct from deployment stacks because developers need to be able to update deployment stacks while not being able to change the permissions associated with the deployment.
• Any number of
resource group stacks
. Each resource group represents a set of resources related to an arbitrary game feature. Resource group stacks exists only as children of deployment stacks. Each resource group has its own stack template, which defines the that resource group's stack for each deployment.
So, if there are 3 deployments and 4 resource groups, you have a total of 12 resource group stacks, 3 deployment stacks, 3 deployment access stacks, and 1 project stack (19 stacks total). You'll also have a total of 7 stack templates, one for the project stack, one for all the deployment stacks, one for all the deployment access stacks, and one each for each resource group. The following image illustrates this scenario.
Version 1.10
186
Lumberyard Developer Guide
Understanding Cloud Canvas Resource Manager
In addition to communicating with Amazon Web Services, Cloud Canvas can also help you manage your resources. Amazon Web Services can help create and manage any cloud resources that a game resource group needs. Once you implement the resource group you can use Cloud Canvas deployments to manage the resources for development, test, and live versions of your game.
Defining the Resources
You can create cloud resources by using AWS CloudFormation templates. AWS CloudFormation is an
Amazon Web Service with which you can define, create, and manage AWS resources predictably and repeatedly by using templates. The templates are JSON-formatted text files that you use to specify the collection of resources that you want to create together as a single unit (a stack).
In a template, each resource gets its own AWS CloudFormation definition in which you specify the parameters that govern the resource. AWS CloudFormation templates are beyond the scope of this topic, but for now it’s enough to understand that you can define (for example) a template with an Amazon
DynamoDB table and two AWS Lambda functions. For an example AWS CloudFormation template that creates an Amazon DynamoDB table, see the AWS CloudFormation User Guide .
Deployments
While you are working on a new resource group, your quality assurance team might have to test it.
You want to provide a version of your resource group that the test team can use while you continue to work on your own version. To keep the corresponding resources of the different versions distinct, Cloud
Canvas gives you the ability to create separate deployments. Deployments are distinct instances of your product’s features.
Version 1.10
187
Lumberyard Developer Guide
Understanding Cloud Canvas Resource Manager
In a scenario like the one described, you might create three deployments: one for the development team, one for the test team, and one for live players. Each deployment's resources are independent of each other and can contain different data because (for example) you don’t want the data entered by the test team to be visible to players.
With Cloud Canvas you can manage each of these deployments independently of one another, and you can switch between deployments at will. After making changes, you can use Cloud Canvas to update your feature or deployment and update the corresponding AWS resources.
Team Workflow Using Deployments
The following workflow example illustrates how Cloud Canvas deployments work:
1. The test team finds a bug. You fix the bug in your Lambda code.
2. You switch to the dev deployment and upload the new version of the Lambda function. The Lambda code in the test and live deployments remain untouched for now, and they continue working as is.
3. After you are satisfied that the bug has been fixed, you update the Lambda code in the test deployment. The test team can now test your fix. The live deployment continues unchanged.
4. After the test team approves the fix, you update the live deployment, propagating the fix to your live players without requiring them to download a new version of the game.
Communicating with Cloud Resources using Flow Graph
As your game communicates with its AWS resources, you can use Lumberyard's flow graph system to implement the interaction between your game and AWS. Cloud Canvas-specific flow graph nodes function just like other flow graph nodes, but they make calls to AWS services. For example, if your feature uses two Lambda functions that are needed in different situations, you can use the Lumberyard flow graph system to specify that the functions get called under the appropriate conditions in your game.
You can also use flow graph to take appropriate actions depending on the success or failure of a function. For example, your function might return failure when no Internet connection exists, or when the function lacks sufficient permissions to contact the resource. Your game can parse any failures and handle them appropriately, such as asking the user to retry or skip retrying.
When you have multiple deployments, Cloud Canvas keeps an internal mapping of friendly names to
AWS instances so that your game knows which AWS resources to use. Cloud Canvas maps the currently selected deployment to the corresponding set of resources.
Thus, when you release your game to customers, you use a deployment specifically set aside for live players. If you are using the dev version of one feature and switch your deployment to test, your game calls the Lambda function associated with the test deployment.
Managing Permissions Using Cloud Canvas
Managing permissions is an important part of building a secure cloud-connected game. Maintaining separate and distinct permissions is important in the phases of development, testing, and production.
You can apply permissions to your development and test teams, to the AWS resources that your game uses, and to the players of your game. A key objective is to secure your game’s AWS resources against hackers and other forms of abuse.
You can use permissions to specify exactly who is allowed to do what to the AWS resources that are part of your game. For example, if you have a game feature that uploads screenshots, you can create an
Amazon S3 bucket to store the screenshots. You can set permissions for the game to be able to write
(send files) to the bucket, but not read from the bucket. This prevents inquisitive users from examining the files that have been uploaded. On the other hand, you can give your team members permissions to read files from the bucket so that they can review and approve them. With Cloud Canvas you can also set
Version 1.10
188
Lumberyard Developer Guide
Cloud Gems Overview the permissions for individual deployments. For example, live and test deployments can have different permission sets.
Like features, you can define permissions through AWS CloudFormation templates. The permissions are applied any time that you update your cloud resources using the Cloud Canvas resource management tools.
For more information, see
Controlling Access to Resources (p. 420)
.
A Lumberyard gem is an individual package of specific functionality and assets. The gem includes everything required for you to include that functionality in your project.
Lumberyard
cloud
gems are Lumberyard gems that provide AWS functionality for a game. A more complete definition of a cloud gem might be the following:
A
cloud
gem is an individual package of specific
cloud-connected
functionality, assets and
AWS resource definitions
. A
cloud
gem includes everything required for you to include that
cloud-connected
functionality in your project.
Lumberyard includes the following cloud gems. To enable them in a project, use the Lumberyard Project
Configurator tool.
•
– Schedules the delivery of messages (for example, new product announcements or holiday greetings) to game clients.
•
– Stores a player's high scores and provides leader boards that show player rankings.
•
Dynamic Content (p. 226) – Ensures that your clients have the latest game content by automatically
downloading new and updated game assets that you upload to the cloud.
•
– Provides a standalone player authentication and management solution for your game that you can customize to fit your needs.
The Cloud Gem Portal provides webpages that can be used to configure the cloud gem and perform maintenance operations. The Cloud Gem Portal also provides access to Cloud Canvas Resource Manager
functionality, such as deployment management. For more information, see Cloud Gem Portal (p. 202) .
The Cloud Gem Framework is a software development kit (SDK) that is included with Lumberyard. You can use the framework to implement the cloud gems that come with Lumberyard, as well as your own
cloud gems. For more information, see Cloud Gem Framework (p. 325) .
Cloud Canvas uses AWS CloudFormation templates to deploy AWS resources to your account. Although there is no additional charge for Cloud Canvas or AWS CloudFormation, charges may accrue for using the associated AWS services. You pay for the AWS resources created by Cloud Canvas and AWS
CloudFormation as if you created them manually. You only pay for what you use as you use it. There are no minimum fees and no required upfront commitments, and most services include a free tier.
For pricing information on the AWS services that Cloud Canvas supports, visit the following links.
Version 1.10
189
Lumberyard Developer Guide
Tutorial: Getting Started with Cloud Canvas
Amazon Cognito Pricing
Amazon DynamoDB Pricing
AWS Lambda Pricing
Amazon S3 Pricing
Amazon SNS Pricing
Amazon SQS Pricing
To see pricing for all AWS services, visit the Cloud Services Pricing page.
This tutorial walks you through the steps of getting started with Cloud Canvas, including signing up for an Amazon Web Services (AWS) account, providing your AWS credentials, and using the command line tools to initialize Cloud Canvas. At the end of the tutorial you will have used your AWS credentials to administer a Cloud Canvas-enabled Lumberyard project.
Specifically, this tutorial guides you through the following tasks:
• Obtain an Amazon Web Services account.
• Navigate the AWS Management Console.
• Create an AWS Identity and Access Management (IAM) user with suitable permissions to administer a
Cloud Canvas project.
• Get credentials from your IAM user and type them into the Cloud Canvas tools.
• Use the command line tool to initialize a Lumberyard project for use with Cloud Canvas.
• Dismantle the project, removing all AWS resources that were allocated by Cloud Canvas.
Before starting this tutorial, you must complete the following:
• Install a working version of Lumberyard Editor.
• Set up a Lumberyard project with the Cloud Canvas Gem (extension) enabled.
• Read through the Cloud Canvas introduction and Cloud Canvas concepts.
When you sign up for Amazon Web Services (AWS), you can access all its cloud capabilities. Cloud Canvas creates resources in your AWS account to make these services accessible through Lumberyard. You are charged only for the services that you use. If you are a new AWS customer, you can get started with
Cloud Canvas for free. For more information, see AWS Free Tier .
If you or your team already have an AWS account, skip to
To create an AWS account
1. Open https://aws.amazon.com/ and then choose
Create an AWS Account
.
2. Follow the instructions to create a new account.
Note
• As part of the sign-up procedure, you will receive a phone call and enter a PIN using your phone.
Version 1.10
190
Lumberyard Developer Guide
Tutorial: Getting Started with Cloud Canvas
• You must provide a payment method in order to create your account. Although the tutorials here fall within the AWS Free Tier , be aware that you can incur costs.
3. Wait until you receive confirmation that your account has been created before proceeding to the next step.
4. Make a note of your AWS account number, which you will use in the next step.
You now have an AWS account. Be sure to have your AWS account number ready.
After you confirm that you have an AWS account, you need an AWS Identity and Access Management
(IAM) user with adequate permissions to administer a Cloud Canvas project. IAM allows you to manage access to your AWS account.
AWS services require that you provide credentials when you access them to verify that you have the appropriate permissions to use them. You type these credentials into Lumberyard Editor as part of setting up your project.
The IAM user that you will create will belong to a group that has administrator permissions to install the Cloud Canvas resources and make them accessible through Lumberyard. Administrative users in this group will have special permissions beyond the scope of a normal Cloud Canvas user.
In a team environment, you—as a member of the administrator's group—can create IAM users for each member of your team. With IAM you can set permissions specifically for each person’s role in a project.
For example, you might specify that only designers may edit a database, or prevent team members from accidentally writing to resources with which your players interact.
For more information on IAM and permissions, see the IAM User Guide .
This section guides you through IAM best practices by creating an IAM user and an administrator group in your account to which the IAM user belongs.
Create an IAM User and an Administrator Group
It's time to create your IAM administrative user.
To create an IAM user in your account
1. Sign into the AWS Management Console and open the IAM console at https:// console.aws.amazon.com/iam/ .
2. In the navigation pane, click
Users
.
3. Click
Add user
.
4. For
User name
, type a user name. This tutorial uses the name
CloudCanvasAdmin
. The name can consist of letters, digits, and the following characters: plus (+), equal (=), comma (,), period (.), at
(@), underscore (_), and hyphen (-). The name is not case sensitive and can be a maximum of 64 characters in length.
5. Select the check box next to
Programmatic access
.
6. Select the check box next to
AWS Management Console access
, select
Custom password
, and then type the new password in the text box.
Note
When you create a user for someone other than yourself, you can select
Require password reset
to force the user to create a new password when first signing in.
7. Click
Next: Permissions
.
8. Click
Create group
.
Version 1.10
191
Lumberyard Developer Guide
Tutorial: Getting Started with Cloud Canvas
9. In the
Create group
dialog box, type the name for the new group. The name can consist of letters, digits, and the following characters: plus (+), equal (=), comma (,), period (.), at (@), underscore (_), and hyphen (-). The name is not case sensitive and can be a maximum of 128 characters in length.
This tutorial uses the name
CloudCanvasAdministrators
.
10. In the
Policy name
list, select the check box next to
AdministratorAccess
. This policy provides the necessary permissions for creating and administering a Cloud Canvas project.
Warning
The
AdministratorAccess
policy allows almost all permissions within the AWS account and should be attached only to the administrator of the account. Otherwise, other team members could perform actions that incur unwanted charges in your AWS account.
11. Click
Create group
.
12. Back in the list of groups, select the check box for your new group if it is not already selected. If necessary, click
Refresh
to see the group in the list.
13.
Click Next: Review
to review your choices. When you are ready to proceed, choose
Create user
.
Your IAM user is created along with two important credentials: an access key and a secret access key.
Later, you will enter these credentials into Cloud Canvas in order to access the AWS resources in your project.
14. Click
Show
to view your secret access key and password, or click
Download .csv
to download the credentials in a
.csv
file. You can also click
Send email
to receive login instructions by email. Make sure you preserve the credentials in a safe place before you proceed. After this point, you cannot view the secret access key from the AWS Management Console.
Important
Do not share your credentials with anyone. Anyone with access to these credentials can access your AWS account, incur charges, or perform malicious acts.
15. You have now created an IAM user called
CloudCanvasAdmin
and a
CloudCanvasAdministrators
administrator group to which the user belongs. To confirm this, click
Groups
in the navigation pane.
Under
Group Name
, click
CloudCanvasAdministrators
. The
CloudCanvasAdmin
user appears in the list of users for the group.
In this tutorial, you add only one IAM user to the administrator group, but you can add more if required.
Now you're ready to try out your new user.
To sign in as your IAM user
1. Get the AWS account ID that you received when you created your AWS account. To sign in as your
CloudCanvasAdmin
IAM user, use this AWS account ID.
2. In a web browser, type the URL https://
<your_aws_account_id>
.signin.aws.amazon.com/ console/
, where
<your_aws_account_id>
is your AWS account number without the hyphens.
For example, if your AWS account number is
1234-5678-9012
, your AWS account ID would be
123456789012
, and you would visit https://
123456789012
.signin.aws.amazon.com/console/
.
For convenience, you might want to bookmark your URL for future use.
3. Type the
CloudCanvasAdmin
IAM user name you created earlier.
4. Type the password for the user and choose
Sign In
.
You are now successfully signed into the AWS Management Console.
Note
Throughout the tutorial, you must be signed into the AWS Management Console. If you are signed out, follow the preceding steps to sign back in.
Version 1.10
192
Lumberyard Developer Guide
Tutorial: Getting Started with Cloud Canvas
Cloud Canvas functionality is enabled in Lumberyard through a Gem package . Gem packages, or Gems, are extensions that share code and assets among Lumberyard projects. You access and manage Gems through the Project Configurator .
This section of the tutorial shows you how to enable the Cloud Canvas Gem package in a new project.
Enable Cloud Canvas in a New Project
If you are working on a new project, follow these steps to enable Cloud Canvas functionality.
Note
Adding the Cloud Canvas Gem package to a project that is not already configured requires rebuilding the project in Visual Studio.
To enable Cloud Canvas in a new project
1. Launch
ProjectConfigurator.exe
from your Lumberyard dev\Bin64\
binary directory.
2. Click
Enable packages
to navigate to the Gems packages screen.
3. Ensure that the check box for the
Cloud Canvas (AWS)
Gem package is checked. If it is already checked, close the
ProjectConfigurator
and go to Step 5: Add Administrator Credentials to
.
4. Click
Save
, and then close the
ProjectConfigurator
.
5. If you had to add the Cloud Canvas (AWS) Gem to the project, open a command line window and run
lmbr_waf configure
to configure your new project.
6. Recompile and build the resulting Visual Studio solution file. Your Lumberyard project is now ready for Cloud Canvas.
In order to begin managing a Cloud Canvas project, you add the IAM user credentials that you generated earlier to a profile that Cloud Canvas can easily reference. To do this, you can use either Lumberyard
Editor or a command line prompt.
To enter your credentials in Lumberyard Editor
1. In Lumberyard Editor, click
AWS
,
Credentials manager
.
2. In the
Credentials Manager
dialog, click
Add profile
.
3. In the
Add profile
dialog box, enter the information requested. For
Profile name
, type a name of your choice (for example,
CloudCanvasAdminProfile
). For
AWS access key
and
AWS secret key
, type the secret key and access key that you generated in
Version 1.10
193
Lumberyard Developer Guide
Tutorial: Getting Started with Cloud Canvas
4. Click
Save
.
5. In
Credentials Manager
, click
OK
.
To add your credentials by using the command line
1. Open a command line window and change to the root Lumberyard directory, which is the dev subdirectory of your Lumberyard installation directory (for example,
C:\lumberyard\dev
).
2. Type the following at the command prompt, and then press
Enter
. Replace
<profile-name>
with a name of your choice (for example,
CloudCanvasAdminProfile
). Replace
<secret-key>
and
<accesskey>
with the secret key and access key that you generated in Step 2 (p. 191)
.
lmbr_aws profile add --profile
<profile-name>
--make-default --aws-secret-key
<secretkey>
--aws-access-key
<access-key>
The profile name is now associated with your credentials, and saved locally on your machine in your
AWS credentials file. This file is normally located in your
C:\Users\
<user name>
\.aws\
directory. As a convenience, other tools such as the AWS Command Line Interface or the AWS Toolkit for Visual Studio can access these credentials.
The profile has also been established as your default profile for Cloud Canvas. The default profile eliminates the need to specify the profile each time you use Lumberyard Editor or run an lmbr_aws command.
Important
Do not share these credentials with anyone, and do not check them into source control. These grant control over your AWS account, and a malicious user could incur charges.
You have now created a profile for administering a Cloud Canvas project.
In this step, you configure your Lumberyard project to use Cloud Canvas capabilities. It sets up all of the initial AWS resources required by Cloud Canvas. You perform this step only once for any project.
To initialize Cloud Canvas
1. Open a command line window and change to your Lumberyard
\dev
directory.
2. You must provide Cloud Canvas with the region to which AWS resources will be deployed. Cloud
Canvas requires selecting a region that is supported by the Amazon Cognito service. You can check the availability of this service by visiting the Region Table . This tutorial deploys resources to US East
(Ohio), which supports Amazon Cognito.
Type the following command: lmbr_aws project create --region us-east-2
Version 1.10
194
Lumberyard Developer Guide
Tutorial: Getting Started with Cloud Canvas
The command initializes the contents of the
<root>
\
<game>
\AWS
directory, including a projectsettings.json
file, and creates the resources Cloud Canvas needs in order to manage your project in your AWS account.
Wait until the initialization process is complete before you proceed. The initialization process can take several minutes.
Note
The initialization process has to be done only once for a given Lumberyard project.
3. You can see the resources created in your AWS account by typing the following command: lmbr_aws project list-resources
4. If you are using source control, check in the contents of the
<root>
\
<game>
\AWS
directory so that other users on your team can access the AWS resources.
Your Lumberyard project is now ready to use Cloud Canvas.
Cloud Canvas lets you organize the AWS resources required by your Lumberyard project into any number of separate resource groups. This step shows you how to add a resource group and optionally add some example resources to your project.
Adding a Resource Group to a New Project
To add a resource group to a new project
1. If you have checked your Lumberyard project into source control, ensure that the
<root>
\
<game>
\AWS\deployment-template.json
file has been checked out and is writeable.
2. Add a new resource group definition by typing the following command: lmbr_aws resource-group add --resource-group
Example
--include-example-resources
After executing this command, the resource definitions for the resource group can be found in the
<root>
\
<game>
\AWS\resource-group\
Example
\resource-template.json
file. This file is an AWS
CloudFormation template. It will be used to create the AWS resources required by your project in the next step of this tutorial.
3. You can see that the resource group is part of the Lumberyard project by typing the following command: lmbr_aws resource-group list
To create the AWS resources in your AWS account for a project resource group, you create a Cloud Canvas deployment. Cloud Canvas allows you to create any number of deployments. Each deployment will have a complete and independent set of the resources needed by your Lumberyard project. This can be useful when you want to have (for example) separate development, test, and production resources for your game. This step shows you how to create a deployment for a project.
Note
Only project administrators (anyone with full AWS account permissions) can add or remove deployments.
Version 1.10
195
Lumberyard Developer Guide
Tutorial: Getting Started with Cloud Canvas
Create a deployment from Cloud Canvas Resource Manager
1. If you have checked your Lumberyard project into source control, ensure that the
<root>
\
<game>
\AWS\project-settings.json
file has been checked out and is writeable.
2. In Lumberyard Editor, click
AWS
,
Cloud Canvas
,
Cloud Canvas Resource Manager
.
3. In the
Cloud Canvas configuration
navigation pane, expand
Administration (advanced)
, and then select
Deployments
.
4. In the details pane, click
Create deployment
.
5. In the
Create deployment
dialog, provide a name for the deployment.
Lumberyard appends the name that you provide to the project stack name to create an AWS
CloudFormation stack for the deployment.
6. Click
OK
to start the deployment creation process.
In the Resource Manager navigation tree, a node for the deployment appears under
Deployments
.
In the detail pane, the
Viewing the Cloud Canvas Progress Log (p. 298)
provides details about the creation process.
7. To make the deployment the default, see
Making a Deployment the Default (p. 416)
.
Create a deployment from the command line
1. If you have checked your Lumberyard project into source control, ensure that the
<root>
\
<game>
\AWS\project-settings.json
file has been checked out and is writeable.
2. Create a deployment by typing the following command: lmbr_aws deployment create --deployment TestDeployment
Version 1.10
196
Lumberyard Developer Guide
Tutorial: Getting Started with Cloud Canvas
3. You can see that the deployment is now part of the Lumberyard project by typing the following command: lmbr_aws deployment list
4. To make the deployment that you created the default deployment in Lumberyard Editor, type the following command: lmbr_aws deployment default --set TestDeployment
5. You can see the resources created with the deployment by typing the following command: lmbr_aws deployment list-resources --deployment TestDeployment
This step in the tutorial shows you the AWS CloudFormation stacks that the previous steps of this tutorial created for you.
To inspect your resources in AWS
1. In a web browser, use your IAM credentials to sign in to the AWS Management Console (see Step
).
2. Ensure the AWS region, which appears on the upper right of the console screen, is set to the one
that you specified when you had Cloud Canvas deploy its resources in Step 6 (p. 194)
. If you selected the region in this tutorial, you will see
N. Virginia
.
3. Click
Services
,
CloudFormation
.
4. Note that a number of other stacks have been created as a result of the previous tutorial steps. If a stack update operation is still under way, the stack will show the status
UPDATE_IN_PROGRESS
.
Otherwise, the status shows
CREATE_COMPLETE
. You may need to click
Refresh
to update the status.
The next step shows how, as an administrator, you can grant your team members access to Cloud Canvas.
In this step, you create Cloud Canvas IAM users for your team, create a group for your users, attach a
Cloud Canvas managed policy to the group, and then add the users to the group. This helps you manage your users' access to AWS resources.
The policies that Cloud Canvas creates for your IAM users are much more restrictive than those for an administrator. This is so that your team members don't inadvertently incur charges without administrator approval.
As you add new resource groups and AWS resources to your project, Cloud Canvas automatically updates these managed policies to reflect the updated permissions.
Create IAM users
You start by creating one or more IAM users.
To create IAM users
1. Sign in to the AWS Management Console using your
CloudCanvasAdmin
credentials (see
).
Version 1.10
197
Lumberyard Developer Guide
Tutorial: Getting Started with Cloud Canvas
2. Click
Services
,
IAM
.
3. In the navigation pane, click
Users
.
4. Click
Create New Users
.
5. Type IAM user names for each team member.
6. Be sure that the
Generate an access key for each user
check box is checked.
7. Click
Create
.
8. Choose the option to download the access key and secret access key for each user. The keys for all users that you created are downloaded in a single
.csv
file. Make sure you preserve the credentials in a safe place now. After this point, you cannot view the secret access key from the AWS
Management Console. You must deliver each user his or her keys securely.
9. Click
Close
.
Create a group
Next, you create an IAM group for the newly created users.
To create a group for the Cloud Canvas IAM users
1. In the left navigation pane of the IAM console, click
Groups
.
2. Click
Create New Group
.
3. Give the group a name. This tutorial uses the name
CloudCanvasDevelopers
.
4. Click
Next Step
.
5. To find the IAM managed policy that Cloud Canvas created for you, click the link next to
Filter
and click
Customer Managed Policies
.
6. Select the check box next to the policy that includes your project name.
7. Click
Next Step
.
8. Review the proposed group that you are about to create.
9. Click
Create Group
.
Add IAM users to a group
Finally, you add your IAM users to the group you just created.
To add your Cloud Canvas IAM users to the group
1. If it is not already selected, click
Groups
in the left navigation pane.
2. Click the name of the newly created
CloudCanvasDevelopers
group (not the check box adjacent to it).
3. If it is not already active, click the
Users
tab.
4. Choose
Add Users to Group
.
5. Select the check boxes next to the IAM users that you want to belong to the
CloudCanvasDevelopers
group.
6. Click
Add Users
. The team's user names now appear in the list of users for the group.
7. Open the credentials.csv
file that you downloaded earlier. Securely deliver the secret and access keys to each user in the group. Stress the importance to each user of keeping the keys secure and not sharing them.
8. Have each user in the
CloudCanvasDevelopers
group perform the following steps: a. In Lumberyard Editor, click
AWS
,
Cloud Canvas
,
Permissions and Deployments
.
b. Type a new profile name and his or her access and secret access keys.
Version 1.10
198
Lumberyard Developer Guide
Game Play Design and Engineering Guide
Important
As an administrator, it is your responsibility to keep your team and your AWS account secure.
Amazon provides some best practices and options for how to manage your team’s access keys on the Managing Access Keys for IAM Users page. You are encouraged to read this thoroughly.
For information regarding limits on the number of groups and users in an AWS account, see Limitations on IAM Entities and Objects in the IAM User Guide .
To remove the Cloud Canvas functionality and AWS resources from your project, see
Canvas Deployments and Their Resources (p. 419)
.
You can use Cloud Canvas's deployments, resource groups, and cloud gems (provided by yourself or others) to design and engineer the cloud connected features of your game.
Topics
•
Cloud Canvas Tools in Lumberyard Editor (p. 199)
•
Managing Cloud Canvas Profiles (p. 200)
•
Using Resource Manager in Game Design (p. 202)
•
•
Cloud Canvas Flow Graph Node Reference (p. 273)
The tools in Lumberyard Editor make it easy for you to connect your game to AWS. To get started, click
AWS
in the Lumberyard Editor menu bar:
The
AWS
menu has the following options:
•
Credentials manager
– Select or manage one or more AWS profiles that provide credentials to access your AWS account. For more information, see
Managing Cloud Canvas Profiles (p. 200)
.
•
Cloud Canvas
– Choose from among the following options:
Version 1.10
199
Lumberyard Developer Guide
Managing Cloud Canvas Profiles
•
Select a Deployment
– Specify the set of AWS resources for the project that you want Lumberyard
Editor to work with. For more information, see
Making a Cloud Canvas Deployment Active (p. 415) .
•
Cloud Canvas Resource Manager
– Define and manage the AWS resources for your Lumberyard
project. For a conceptual introduction to resource manager, see Understanding Cloud Canvas
•
Dynamic Content Manager
– Manage dynamic content updates for your game through AWS. For more information, see
Using Dynamic Content Manager (p. 226) .
•
Commerce
– Choose from among the following options for monetizing your game:
•
Merch by Amazon
– Create themed T-shirts for your game.
•
Publishing on Amazon
– Distribute your Windows and macOS applications to customers.
•
GameLift
– Use the Amazon GameLift service to rapidly deploy and scale session-based multiplayer games with no upfront costs. For more information, see Amazon GameLift . The
GameLift
menu itself also has links to more information.
•
Open AWS Console
– Get quick access to the main AWS Management Console and to the consoles for
Amazon Cognito, DynamoDB, Amazon S3, and Lambda:
These links use your currently active AWS profile to connect to AWS. You can use
Credentials Manager
to select which profile is active.
•
Open Cloud Gem Portal
– Manage cloud-connected game features that you implement from a
. For more information, see
Use the
Credentials Manager
in Lumberyard Editor or the command line to manage one or more AWS profiles that provide the credentials required to access your AWS account.
The profile is saved locally on your machine in your AWS credentials file. This file is normally located in your
C:\Users\
<user name>
\.aws\
directory. The AWS Command Line Interface and the AWS Toolkit for
Visual Studio can access these credentials.
Important
Do not share these credentials with anyone, and do not check them into source control. These grant control over your AWS account, and a malicious user could incur charges.
Version 1.10
200
Lumberyard Developer Guide
Managing Cloud Canvas Profiles
For more information, see
AWS Security Credentials
.
To open Credentials Manager
• To open
Credentials Manager
, do one of the following:
• In Lumberyard Editor, click
AWS
,
Credentials manager
.
• In
Cloud Canvas Resource Manager
, click the name of the current profile in the Resource Manager toolbar:
You can use the
Credentials Manager
to select an existing AWS profile, edit an AWS profile, or add a new
AWS profile.
To edit an existing AWS profile, click
Edited selected profile
. To add an AWS profile, click
Add profile
.
When adding or editing a profile, Lumberyard prompts you for the following:
Profile name
– The name used for the profile.
AWS Secret Key
– The AWS secret key needed to access the account.
AWS Access Key
– The AWS access key needed to access the account.
To add your credentials by using the command line
1. Open a command line window and change to the root Lumberyard directory, which is the dev subdirectory of your Lumberyard installation directory (for example,
C:\lumberyard\dev
).
2. Type the following at the command prompt, and then press
Enter
. Replace
<profile-name>
with a name of your choice (for example,
CloudCanvasAdminProfile
). Replace
<secret-key>
and
<accesskey>
with the secret key and access key of your AWS account.
lmbr_aws profile add --profile
<profile-name>
--make-default --aws-secret-key
<secretkey>
--aws-access-key
<access-key>
Version 1.10
201
Lumberyard Developer Guide
Using Resource Manager in Game Design
The
--make-default
option establishes the profile as your default profile for Cloud Canvas. The default profile eliminates the need to specify the profile each time you use Lumberyard Editor or run an lmbr_aws command
.
You can use Cloud Canvas Resource Manager to make deployments active, test mappings, use protected deployments, and to delete deployments and resources.
For information, see the following links in the Working with Deployments (p. 412)
section of the Cloud
Canvas documentation.
•
Making a Cloud Canvas Deployment Active (p. 415)
•
Testing Different Mappings (p. 417)
•
Using Protected Deployments (p. 418)
•
Deleting Cloud Canvas Deployments and Their Resources (p. 419)
A cloud gem is an individual package of specific cloud-connected functionality, assets, and AWS resource definitions. A cloud gem includes everything required for you to add cloud-connected functionality to your project.
Lumberyard includes the following cloud gems. You can enable them in a project from the Lumberyard
Project Configurator tool.
•
– Schedules the delivery of messages (for example, new product announcements or holiday greetings) to game clients.
•
– Stores a player's high scores and provides leader boards that show player rankings.
•
Dynamic Content (p. 226) – Allows Lumberyard
.pak
files that contain new and updated game assets to be uploaded to the cloud for later automatic downloading to the game client.
•
– Provides a standalone player authentication and management solution that uses Amazon Cognito.
Topics
•
•
Setting Up and Accessing the Cloud Gem Portal (p. 204)
•
User Management in the Cloud Gem Portal (p. 206)
•
Message Of The Day Cloud Gem Portal (p. 209)
•
Leaderboard Cloud Gem Portal (p. 218)
•
Using Dynamic Content Manager (p. 226)
•
Player Account Cloud Gem Portal (p. 250)
A cloud gem (p. 189) is a gem in Lumberyard whose scripts and assets use AWS resources to implement
cloud-connected game features. A cloud gem creates a Cloud Gem Portal (CGP) that you can use to
manage the cloud data for your game. For example, the Leaderboard Cloud Gem Portal (p. 218) can
Version 1.10
202
Lumberyard Developer Guide
Cloud Gems provide a way for a support person to remove fraudulent high scores. The Cloud Gem Portal is hosted in your AWS account and is a website that you own. The Cloud Gem Portal is part of the
Framework (p. 325) and can be customized.
How a Cloud Gem Portal Works
Cloud gem portals use Amazon Web Services to implement their functionality, as shown in the following diagram.
Amazon S3 stores a Cloud Gem Portal as a web application. AWS Lambda functions implement the required server-side logic. JavaScript code that runs in the web browser accesses the Lambda functions through the Amazon API Gateway . The configuration for the API Gateway is handled by the Cloud Canvas
Cloud Gem Framework Service API (p. 373)
.
Cloud Gem Workflow
A cloud gem provides content (for example, HTML, JavaScript, or images) from its
/dev/Gems/
<gem>
/
AWS/cgp-resource-code
subdirectory. When you deploy a cloud gem, the
uploads this content to the project’s configuration bucket. To determine which cloud gems are available to it, the Cloud Gem Portal page uses the Cloud Gem Portal service API to call the
Cloud Gem Portal Lambda function. When you select a cloud gem, its content is loaded into the Cloud
Gem Portal webpage. To query the state of the cloud gem or perform other operations, JavaScript code can use a service API defined for the cloud gem. The service API calls the cloud gem's Lambda function that implements the cloud gem's functionality.
Version 1.10
203
Lumberyard Developer Guide
Cloud Gems
Before you can use a Cloud Gem Portal, you must install one or more cloud gems.
To add a cloud gem to your project
1. Open the Project Configurator . In Lumberyard Editor, click
File
,
Project Settings
,
Configure Gems
.
2. In Project Configurator, click
Enable Gems
next to the project for which you want to enable the new gems. In this example, the
CloudGemSamples
project is selected.
3. Select the cloud gems that you want to enable. In this example, the
Cloud Gem Leaderboard
and
Cloud Gem Message of the Day
gems are selected.
Note
If you are using the
CloudGemSamples
project, the cloud gem sample gems are already enabled for you.
4. After you have enabled a cloud gem, you must build the project so that the
.dll
libraries for the gem are included. For information on building your project, see Compiling Game Code .
If you don't have an AWS account and have not set up any project or deployment stacks, follow the
steps in Tutorial: Getting Started with Cloud Canvas (p. 190)
to enable AWS in your project.
Version 1.10
204
Lumberyard Developer Guide
Cloud Gems
Accessing the Cloud Gem Portal
To access the Cloud Gem Portal, you can use either Lumberyard Editor or a shared link.
To open the Cloud Gem Portal
1. Do one of the following:
• In Lumberyard Editor, click
AWS
,
Open Cloud Gem Portal
.
• If you have been given a shareable link to the Cloud Gem Portal (for example, by another team member), open the link in a browser. Lumberyard does not have to be installed on your computer.
2. Type your user name and password at the sign-in page.
3. The first time that you open the Cloud Gem Portal, the launcher checks whether an administrator account exists for your Cloud Gem Portal. If an account does not exist, a new Cloud Gem Portal administrator account is created for you, and Lumberyard Editor provides you with a temporary password. If you launch the Cloud Gem Portal from Lumberyard Editor, the credentials are displayed in a dialog box. If you launch the Cloud Gem Portal from the command line interface, the credentials are displayed in the Lumberyard console.
Make a note of the password. Immediately after you use the temporary password to sign in, you are required to update it.
Version 1.10
205
Lumberyard Developer Guide
Cloud Gems
Note
If you have been given a set of account credentials from someone who has access through
Cloud Gem Portal user management (p. 206)
, use those credentials instead.
4. After you sign in, the
Cloud Gems
page shows the list of cloud gems that are available in your current project and deployment.
Click a gem to see its details.
At this point, you can visit one or more of the following links to explore the gems that you are interested in.
• To create and manage a message of the day, see Message Of The Day Cloud Gem Portal (p. 209) .
• To integrate your game with a leaderboard, see Leaderboard Cloud Gem Portal (p. 218) .
• To add dynamic content on the Cloud Gem Portal, see Using Dynamic Content Manager (p. 226)
.
• To add a standalone player authentication and management solution that you can customize, see
Player Account Cloud Gem Portal (p. 250)
To further manage and customize the Cloud Gem Portal, visit the following links.
• To manage users on the Cloud Gem Portal, see
User Management in the Cloud Gem Portal (p. 206) .
• To modify the cloud gem portal and create your own cloud gems, see Getting Started With
Development on the Cloud Gem Portal (p. 328)
.
Starting in Lumberyard 1.10, the Cloud Gem Portal authentication API requires all Cloud Gem Portal users to have a valid Cloud Gem Portal account to sign in. You can use the new
User Administration
page in the Cloud Gem Portal for your project to create and manage these accounts. User accounts can have one of two roles:
Portal Admin
or
User
. Only users with the
Portal Admin
role can access the
User
Administration
page and manage other users. User names must be unique, and new users are required to change their password the first time that they sign in.
Note
This feature is not related to the Login with Amazon feature that Lumberyard itself uses.
Because your Cloud Gem Portal does not exist publicly and is not registered with Login with
Amazon, you cannot use your Login with Amazon account with the Cloud Gem Portal.
Version 1.10
206
Lumberyard Developer Guide
Cloud Gems
Prerequisites
This tutorial assumes the following:
• You are using a Lumberyard project that has the Cloud Gem Framework Gem enabled (in Project
Configurator, select
Cloud Gem Player Framework
).
• You have created a project stack in Cloud Canvas Resource Manager (p. 184) .
If you don't meet the prerequisites, follow the steps in
Setting Up and Accessing the Cloud Gem
Cloud Gem Framework
in Project Configurator and in
Resource Manager (p. 408) to create a project stack.
Legal Restrictions
You are responsible for (a) providing legally adequate privacy notices to your end users; (b) obtaining any necessary consent from the end user for the collection, use, transfer, and storage of any name, password, other login information, or personally identifiable information or personal data of any end user that you
(or any third-party plug-in or service provider you use) may access; (c) using and authorizing others to access and use the information only for the purposes permitted by the end user; and (d) ensuring the information is collected, used, transferred, and stored in accordance with all laws, rules, and regulations applicable in jurisdictions in which your applications are used.
Managing Users
To manage users of your Cloud Gem Portal, use the
User Administration
page.
To open the User Administration page
1. In Lumberyard Editor, choose
AWS
,
Open Cloud Gem Portal
. If this is your first time, follow the steps in Accessing the Cloud Gem Portal to sign in with your temporary administrator account credentials. You must change your password immediately after you sign in.
2. Click
Admin
at the top navigation of the Cloud Gem Portal to open the
User Administration
page.
The page shows the current list of users that have access to your project's portal. The Cloud Gem Portal has two roles:
Portal Admin
and
User
. Administrators have access to the
Admin
page and can add and remove users. Nonadministrative users do not see the
Admin
page but have access to cloud gems.
Adding Users
To add a user to your project, you can use the
Admin
page or the Amazon Cognito management console.
Using the
Admin
page is easier and ensures that the permissions are correct.
Version 1.10
207
Lumberyard Developer Guide
Cloud Gems
To add a user to the Cloud Gem Portal
1. Click
Add New User
.
2. Fill in the fields, which have the restrictions noted.
•
Username
– The user name is case sensitive and must not contain spaces. It cannot be changed after it is assigned. Each user name must be unique.
•
– Because new users are sent temporary passwords by email, you must provide a valid email address.
•
Temporary Password
– A random temporary password is provided by default, but you can change this. The password must have eight characters and include at least one uppercase letter, one lowercase letter, one number, and one special (nonalphanumeric) character.
•
Roles
– Choose
Admin
to grant the user access to the
Admin
page and give them permissions to and remove users. Choose
User
for other users.
After you create the user, the user is sent an email with the temporary password. After the new user signs in, the user is required to change passwords.
Version 1.10
208
Lumberyard Developer Guide
Cloud Gems
Deleting Users
To delete a user, click the delete icon for the user on the
User Administrator
page.
After you confirm the deletion at the confirmation prompt, the user account is removed and the user is no longer able to sign in.
Resetting User Passwords
To reset a user's password, click the arrow next to the delete icon for the user, and then click
Reset
Password
.
You can use the Message of the Day Cloud Gem to schedule messages that you game consumes. You can customize your project's message of the day using the Cloud Gem Portal.
Prerequisites
This tutorial assumes the following:
• You are using a Lumberyard project that has the Message of the Day Cloud Gem enabled (in Project
Configurator, select
Cloud Gem Message of the Day
).
• You have created a project stack in Cloud Canvas Resource Manager (p. 184) .
• You have created a deployment stack in resource manager.
• You have opened the cloud gem portal. In Lumberyard Editor, click
AWS
,
Open Cloud Gem Portal
.
If you don't meet the prerequisites, follow the steps in
Setting Up and Accessing the Cloud Gem
Cloud Gem Message of the Day
in the Project Configurator.
Accessing and Using the Message of the Day Cloud Cloud Gem
To customize the Message of the Day Cloud Gem
1. To view the cloud gems in the Cloud Gem Portal, click
View all Cloud Gems
in the banner, or click
Cloud Gems
on the upper right.
Version 1.10
209
2. Click
Message of the day
.
Lumberyard Developer Guide
Cloud Gems
3. Click
Add Message of the Day
to create a new message.
4. In the
Add Message
dialog box, provide the following information:
Version 1.10
210
Lumberyard Developer Guide
Cloud Gems
• For
Message Content
, type a message that to be displayed to the players of your game.
• For
Scheduling
, clear the
No Start
and/or
No End
check boxes and specify the
Start
and/or
End
time during which players see the message. Currently, all times are in UTC.
The message is shown to players that have a game clock that is between –12 hours or +12 hours of the set UTC time.
• To make the message permanent, specify both
No Start
and
No End
.
• If you have more than one message, you can use the
Priority
option to specify the priority of each.
By default, 0 is the highest priority. The game client determines how to use the priority value. If you have only one active message, the priority has no effect.
5. Click
Save
. The portal shows your new message in the
Active
category.
Version 1.10
211
Lumberyard Developer Guide
Cloud Gems
The message of the day dashboard has three categories:
Active Messages
,
Planned Messages
, and
Expired Messages
.
•
Active Messages
– The currently active messages that are returned by the game client.
•
Planned Messages
– Messages that are not currently active but will be active at the planned start date and time.
•
Expired Messages
– Outdated messages, which are stored in the
History
tab so that you can edit and reuse them if you want.
You can now use the message in your game.
Other Cloud Gems
Visit the following links for other cloud gems that might interest you.
• Leaderboard Cloud Gem:
Leaderboard Cloud Gem Portal (p. 218)
• Dynamic Content Cloud Gem:
Using Dynamic Content Manager (p. 226)
Topics
•
Testing the Message of the Day Sample Level (p. 212)
•
Cloud Gem Message of the Day Implementation Details (p. 213)
•
Cloud Gem Message of the Day API Calls (p. 215)
Testing the Message of the Day Sample Level
A sample level for testing is located in the
\dev\CloudGemSamples\Levels\MsgOfTheDaySample
directory.
The
MsgOfTheDaySample
level contains a one-button UI for retrieving and displaying successive messages of the day.
To test the Message of the Day sample level
1. Use the Cloud Canvas Resource Manager to upload all the resources that you need to have an updated stack.
2. Open the Cloud Gem Portal and add some messages that are scheduled for today. If you set no scheduling information for a message, the message is always current.
3. To display the messages in a specific order, set the priority field.
0
signifies highest priority.
4. Press
Ctrl+G
to start the level. The test user interface appears.
Version 1.10
212
Lumberyard Developer Guide
Cloud Gems
5. Click
Get Messages
.
With each click, the messages are displayed in succession.
Cloud Gem Message of the Day Implementation Details
This section describes the entity, component, Lua script, and resources used by the Message of the Day
Cloud Gem.
Entity and Component
The Message of the Day sample uses an entity called
MOTDMenu
that contains the
CloudGemMessageOfTheDayClientComponent
.
The
CloudGemMessageOfTheDayClientComponent
component gives the entity access to the game client
API operations so that it can receive callback results.
Version 1.10
213
Lumberyard Developer Guide
Cloud Gems
The motdmainmenu.lua Script
The
MOTDmenu
entity also contains a Lua script component that executes the dev\CloudGemSamples
\Scripts\motdmainmenu.lua
script.
The following code from the script shows how
CloudGemMessageOfTheDayRequestBus
is used to call
GetPlayerMessages
.
function motdmainmenu:OnAction(entityId, actionName)
Debug.Log(tostring(entityId) .. ": " .. actionName)
if actionName == "GetMessages" then
if CloudGemMessageOfTheDayRequestBus.Event == nil then
Debug.Log("No Message Request Event found")
return
end
local timeVal = os.date("%b %d %Y %H:%M")
local lang = "Eng"
Debug.Log(timeVal);
CloudGemMessageOfTheDayRequestBus
.
Event
.
GetPlayerMessages
(self.entityId, timeVal,
lang, nil)
end end
The following code from the script shows the
CloudGemMessageOfTheDayNotificationBus and the result callback functions
OnGetPlayerMessagesRequestSuccess(response)
and
OnGetPlayerMessagesRequestError(errorMsg)
that it connects to.
function motdmainmenu:OnActivate()
...
self.notificationHandler =
CloudGemMessageOfTheDayNotificationBus
.Connect(self,
self.entityId) end
...
function motdmainmenu:
OnGetPlayerMessagesRequestSuccess
(response)
Debug.Log("GetPlayerMessages succeeded")
self.messageQueue = {}
self.displayTimer = 0.0
Debug.Log("Response messages: "..tostring(#response.list));
--This is a callback from C++ with an object containing a vector called list.
--Therefore we cannot treat it as a regular Lua table and must rely on the reflected
methods and operators of the reflected vector class
--for msgCount = 1, table.getn(response) do
-- Debug.Log(response[msgCount])
-- table.insert(self.messageQueue, response[msgCount])
for msgCount = 1, #response.list do
Debug.Log(tostring(response.list[msgCount].message))
table.insert(self.messageQueue, response.list[msgCount])
end end function motdmainmenu:
OnGetPlayerMessagesRequestError
(errorMsg)
Debug.Log("GetPlayerMessages Error") end
Version 1.10
214
Lumberyard Developer Guide
Cloud Gems
Cloud Gem Message of the Day Resources
The Cloud Canvas Message of the Day sample has a resource group that contains an Amazon DynamoDB table called Main Table, which is the database for the messages. Table entries are keyed on a servergenerated unique message ID. Each entry has the following attributes.
Main Table Attributes
Attribute Type
UniqueMsgID string startTime
Description
The server-generated unique message ID.
datetime
Time when the message should start appearing.
endTime priority message datetime
Time when the message expires.
integer
Relative priority of the message. 0 is the highest priority.
string
The message body. The string size is limited to 768 characters.
Cloud Gem Message of the Day API Calls
The game client and Cloud Gem Portal use Amazon API Gateway to securely invoke service API Lambda functions. The game client can read messages while the Cloud Gem Portal can add, list, edit, and delete messages.
The Game Client Service API Calls: /player/messages
The game client read-message functionality is implemented by the player_messages.py
file located in the
\dev\Gems\CloudGemMessageOfTheDay\AWS\lambda-function-code\api
directory.
get (Read Messages)
The get
function reads messages for the player.
Version 1.10
215
Lumberyard Developer Guide
Cloud Gems
Parameters
The get
function has the following parameters.
{
"clientTime" : datetime as string : Opt [default UTC] : The datetime value used to
retrieve the messages. The default is UTC.
"clientLanguage" : String : Opt [default "Eng"] : The language used for localization.
}
Description
The get
function returns a list of messages whose startTime
<= clientTime
<= endTime
.
Return Value
The get
function returns a list of messages of the day.
{
"list" : a list of objects
{
"message": string
"priority": integer,
"startTime": datetime,
"endTime": datetime
}
}
Cloud Gem Portal Admin Service API Calls: /admin/messages
The Cloud Gem Portal message functionality is implemented by code in the admin_messages.py
file located in the
\dev\Gems\CloudGemMessageOfTheDay\AWS\lambda-function-code\api
directory.
post (Add Message)
The post
function adds a message of the day.
Parameters
The post
function has the following parameters.
{
"message": String: Required
"priority": Integer, : Opt [default 0]
"startTime": datetime: Opt [default Jan 01 1900 00:00 ]
"endTime": datetime: Opt [default Dec 31 2100 23:59 ]
}
Description
The post
function adds a message entry to the main table in DynamoDB and returns a
UniqueMsgID string.
put (Edit Message)
The put
function edits an existing message.
Parameters
The put
function has the following parameters.
Version 1.10
216
Lumberyard Developer Guide
Cloud Gems
{
"UniqueMsgID": String: Required
"message": String: Opt [default leaves current message unchanged]
"priority": Integer, : Opt [default 0]
"startTime": datetime: Opt [default Jan 01 1900 00:00 ]
"endTime": datetime: Opt [default Dec 31 2100 23:59 ]
}
Description
The put
function updates the message in the main table that matches the specified message ID.
To update the message, the function overwrites its attributes. You can also use the put
function to reschedule and reprioritize a message by updating the start time, end time, and priority values.
Return Value
The put
function returns a string that indicates the result status of the operation.
delete (Delete Message)
The delete
function deletes the specified message.
Parameters
The delete
function has the following parameters.
{
"UniqueMsgID": String: Required
}
Description
Deletes the message from the main table that matches the specified message ID.
Return Value
The delete
function returns a string that indicates the result status of the operation.
get (List Messages)
The get
function retrieves a list of messages of the day.
Parameters
The get
function has the following parameters.
{
"index": Integer: Opt [default 0]
"count": Integer: Opt [default 9999999]
"filter": Opt [default all] Can be one of the following: "active", "expired", "planned"
or "all"
}
Description
The get
function returns the filtered count of entries in the table, including all fields starting at the specified index.
Version 1.10
217
Lumberyard Developer Guide
Cloud Gems
Return Value
The get
function returns a list of messages of the day in the following format.
{
"list" : a list of objects
{
"UniqueMsgID": String
"message": String
"priority": Integer,
"startTime": datetime,
"endTime": datetime
}
}
You can use the Leaderboard cloud gem portal to create, view, and customize leaderboards by deleting scores, banning players, and removing bans.
Prerequisites
This tutorial assumes the following:
• You are using a Lumberyard project that has the Leaderboard Cloud Gem enabled (in Project
Configurator, select
Cloud Gem Leaderboard
).
• You have created a project stack in Cloud Canvas Resource Manager (p. 184) .
• You have created a deployment stack in Cloud Canvas Resource Manager.
If you don't meet the prerequisites, follow the steps in
Setting Up and Accessing the Cloud Gem
Cloud Gem Leaderboard
in Project Configurator.
Accessing and Using the Leaderboard Cloud Gem Portal
You use Lumberyard Editor to work with the Leaderboard Cloud Gem Portal.
To access and use the Leaderboard Cloud Gem Portal
1.
Opening the Cloud Gem Portal
In Lumberyard Editor, click
AWS
,
Open Cloud Gem Portal
and then choose the
Leaderboard
cloud gem.
2.
Creating a Leaderboard
You must create a leaderboard for your game before you can start posting scores to it. In the
Leaderboard Cloud Gem, click
Add Leaderboard
to create a leaderboard so that your game can use it. If your game tries to send data to a leaderboard that doesn't exist, the data is not be sent or saved anywhere.
Version 1.10
218
Lumberyard Developer Guide
Cloud Gems
A leaderboard has the following four options:
•
Leaderboard ID –
This is the identifier for your leaderboard. The game client uses this ID to send data to the leaderboard. Currently, this ID does not support spaces. If you're creating a leaderboard for a particular region or language, it's good to put that information in the ID. For example, you could designate scores for North America with the ID "scores-NA" instead of just
"scores".
•
Mode –
At launch, leaderboards have two modes:
Overwrite
and
Increment
. Overwrite mode overwrites a previous score for a user. Increment mode adds the value passed in from the game client to the previous value to keep a running total of a particular statistic. For example, you might use increment mode to track career statistics in a game.
•
Minimum Value Allowed –
The minimum value for the leaderboard. If the game client sends scores below the minimum value allowed, the scores are not recorded.
•
Maximum Value Allowed –
The maximum value for the leaderboard. If the game client sends scores above the maximum value allowed, the scores are not recorded.
3.
Editing a Leaderboard
To edit all options (except for
Leaderboard ID
), click the settings icon on the right side of the leaderboard. If you want to change the value for
Leaderboard ID
, you must delete and recreate the leaderboard. When you delete a leaderboard, its data is also deleted.
Version 1.10
219
Lumberyard Developer Guide
Cloud Gems
4.
Viewing Leaderboards
To view a leaderboard, click its name. This shows you a list of players and their scores in the leaderboard. You can also delete a player's scores or ban a player from all leaderboards.
5.
Deleting Scores
To delete a score, click the delete icon the confirmation window.
on the right of the player's score. Then click
Delete
in
Version 1.10
220
Lumberyard Developer Guide
Cloud Gems
6.
Banning a Player
To ban a player, click the ban icon on the right side of the player table next to the delete icon.
When you ban a player, the player's scores are removed from all leaderboards, and the player is prevented from posting on other leaderboards. This is a reversible action; you can remove a ban if done by mistake.
Version 1.10
221
Lumberyard Developer Guide
Cloud Gems
7.
Removing a Ban
To remove a ban, click the
Banned Players
tab. The tab displays a list of banned players in all your leaderboards. Click the ban icon again, and then click
Save
in the confirmation window.
Topics
•
Testing the Leaderboard Sample Level (p. 222)
•
Leaderboard Sample Level Implementation Details (p. 223)
•
Leaderboard Cloud Gem Resources (p. 224)
•
Leaderboard Cloud Gem Service API (p. 225)
Testing the Leaderboard Sample Level
The
CloudGemLeaderboard
Cloud Gem is included in the LeaderboardSample level, which is located in the dev\CloudGemSamples\Levels\LeaderboardSample
directory. The LeaderboardSample level contains a UI canvas with multiple buttons that you can use to test the Leaderboard system.
Note
By default, the Lambda function that processes score records is on a 10-minute timer. This timer avoids possible consistency issues and costs that might occur because of reduced throughput capacity. The configuration for the timer is located in the resource-template.json
file for the gem. When you test the gem, you might want to reduce the timer value in the template file.
Alternatively,you can use the AWS Lambda console to disable the timer trigger, and then trigger it manually by using the
Test
button.
To test the Leaderboard using the sample level
1. Using the
Cloud Canvas Resource Manager
, upload all resources to ensure that you have an updated stack.
2. Open the Cloud Gem Portal (CGP) and add a statistic to the leaderboard. This creates a description of a statistic to track (if no definitions exist, you cannot submit a score). The default properties in the test level expect a statistic called score
.
3. Press
Ctrl+G
to start the level. The test user interface appears.
Version 1.10
222
Lumberyard Developer Guide
Cloud Gems
4. Click
Submit Batch
to populate the leaderboard with data. You can click the button multiple times to simulate a larger population. Messages in the editor logs show whether the submissions were successful.
5. Click
Get Leaderboard
to see the top five scores in the sample.
6. Click
User Score 10
to submit a score for the
LocalPlayer
user.
7. To verify the submission, click the leaderboard in the Cloud Gem Portal. A score with the value of
10
should appear under the name
LocalPlayer
.
8. Click
User Score 50
to submit another score for
LocalPlayer
. Because the new score is higher, it should overwrite the earlier score. To verify the submission, click the leaderboard in the Cloud Gem
Portal again.
Note
There is a caching mechanism on the backend, so the scores might not be updated immediately.
Leaderboard Sample Level Implementation Details
An entity named
Leaderboard
contains the
CloudGemLeaderboardClientComponent
.
Version 1.10
223
Lumberyard Developer Guide
Cloud Gems
The
CloudGemLeaderboardClientComponent
enables the gem's API to be called from other components on that entity and receives notifications for those calls.
The
Leaderboard
entity also contains a Lua script component that uses the leaderboardmainmenu.lua
script. The script creates the testing user interface and calls the following APIs through the attached client component:
•
PostScore
(to submit scores)
•
PostLeaderboard
(to request a leaderboard for a stat)
The script also implements the notification methods for these API calls:
•
OnPostScoreRequestSuccess
•
OnPostScoreRequestError
•
OnPostLeaderboardRequestSuccess
•
OnPostLeaderboardRequestError
Leaderboard Cloud Gem Resources
The following table lists the resources used by the Leaderboard Cloud Gem.
Resource
BannedPlayerTable
LeaderboardInfo
LeaderboardTable
Description
A list of players that are no longer allowed to submit scores.
Information for each statistic about the state of the leaderboard, including population and maximum sample size.
A table that contains a set of scores for each statistic. The set is a sample gathered using a reservoir sampling method . The sets are used to estimate where an arbitrary user's score sits within the entire population. This allows the cloud gem to estimate global rankings.
Version 1.10
224
Lumberyard Developer Guide
Cloud Gems
Resource
MainTable
RecordsBucket
RecordSetProcessor
RecordSetStatus
ScoreStreamReader
StatsSettings
UserIdentityMap
Description
The main database for scores. Entries are keyed on userID
with a score attribute for each metric. This table allows you to gather the most up-to-date information on a specified set of players.
An Amazon S3 bucket that holds all the records written by
ScoreStreamReader
.
A Lambda function that reads through all pending records and decides whether the samples on
LeaderboardTable
need to be updated. This Lambda function is triggered by the timer
RecordSetProcessorSchedulerRule
that has a default of
10 minutes.
A table that keeps track of the status of all record sets. Sets can be
OPEN
(accepting new records),
PENDING
(not accepting records, to be processed soon), or
CLOSED
(processed, waiting for cleanup). The information in
RecordSetStatus determines which record set
RecordSetProcessor
processes and where
ScoreStreamReader
puts its next record.
A Lambda function triggered by DynamoDB updates to
MainTable
. Writes records to the Amazon S3
RecordsBucket
for later processing.
A table that specifies how to process specific statistics from submissions. Holds minimum and maximum values for each statistic and specifies whether it is to be overwritten or incremented on submission.
Maps user IDs to Amazon Cognito IDs to ensure that scores can't be submitted on another player's behalf. After an ID is used for the first time, it is maintained by the Amazon Cognito ID.
Leaderboard Cloud Gem Service API
The following table lists the service API calls for the Leaderboard Cloud Gem.
API
/score POST
/score/{stat}/
{user}
GET
/score/{stat}/
{user}
DELETE
/scores
/{user}
GET
/stats GET
/stats POST
Description
Submits a new score. Expects a payload including user
, value
, and stat fields. Returns the updated score for that statistic. The updated score returned is not necessarily the score that was submitted. This operation is player callable.
Note
The leaderboard can store integer scores up to the maximum integer value or decimal scores up to
1e+20
.
Gets a specific score for the provided user. This operation is player callable.
Deletes a specific score for the provided user.
Gets all scores (multiple statistics) for the provided user. This operation is player callable.
Lists all valid statistics that are registered with the leaderboard.
Register a new statistic. Expects a payload with name
, and mode
fields. The min
and max
fields are optional. Returns the list of all valid statistics.
Version 1.10
225
Lumberyard Developer Guide
Cloud Gems
API
/stats/
{stat_name}
DELETE
/player/ban_list GET
/player/ban/
{user}
POST
/player/ban/
{user}
DELETE
/leaderboard/
{stat}
POST
Description
Deletes the specified statistic definition. Returns the list of all valid stats.
Lists all the banned players.
Bans the specified player.
Lifts the ban on the specified player.
Takes an optional payload that expects a users
field. The users
fields is a list of the user IDs to include in the leaderboard sample. Returns a leaderboard sample for the provided statistic with estimated ranks. This operation is player callable.
You can use the Dynamic Content Cloud Gem and its Dynamic Content Manger to manage dynamic content updates for your game through AWS. You can use Dynamic Content Manger to create manifests and packages, add files to the packages, and upload the manifest and packages to the AWS Cloud. This ensures that your clients have the latest content for your game.
Topics
•
Managing Dynamic Content Packages (p. 235)
•
Using lmbr_aws for Dynamic Content (p. 241)
•
Testing the Dynamic Content System (p. 245)
•
Dynamic Content Engineering Details (p. 248)
Prerequisites
This tutorial assumes the following:
• You are using a Lumberyard project that has the Dynamic Cloud Gem enabled (in Project Configurator , choose
Cloud Gem Dynamic Content
).
• You have created a project stack and deployment stack in Cloud Canvas Resource Manager (p. 184)
with the
CloudGemDynamicContent
resource group.
Note
If you do not have a deployment with the
CloudGemDynamicContent
resource group, the
Dynamic Content Manager
interface is disabled.
To use the Dynamic Content Manager to upload dynamic content
1. In Lumberyard Editor, choose
AWS
,
Cloud Canvas
,
Dynamic Content Manager
.
Version 1.10
226
Lumberyard Developer Guide
Cloud Gems
2. In
Dynamic Content Manager
, click
Create a new manifest
.
A manifest is a file that keeps track of the dynamic content files that you deliver to customers. A manifest records the following information:
• The content files that have changed locally
• The files that are included in any file packages
• Differences between the local packages and the packages in the cloud that are staged for delivery to customers
• The target platforms for this manifest
You can create as many manifests as you require. For example, you can create specialized manifests for different types of assets.
3. Choose a name for the manifest. The name should reflect the purpose of the manifest.
4. Select the target platforms that you prefer to work on for this manifest.
5. When you create a manifest, the manifest is empty and has no files or packages.
Version 1.10
227
Lumberyard Developer Guide
Cloud Gems
Click
Add Files
or
Add Folder
and choose one of the target platforms.
6. In the file browser, choose the files that you want to add to the manifest.
Version 1.10
228
Lumberyard Developer Guide
Cloud Gems
Because the original assets might not be in a form that your game can consume, the file browser opens to the location of your game projects asset cache. For example, your game platform might require textures to be in
.dds
format, but the original asset for a texture might be a
.png
file. The
Asset Processor converts the files to the appropriate format and stores them in the asset cache, so the asset cache is your safest choice. However, if you have processed assets elsewhere in your file system, you are free to include them.
File Warnings
If the files that you selected are not supported by the current manifest or not supported by the platform that you selected, you are warned accordingly.
If the files that you selected are not in your game projects asset cache (and have therefore not been processed by the Asset Processor), you are notified of the error.
7. The left pane of
Dynamic Content Manager
shows the files that you added to the manifest. You can add files for different target platforms and sort the files by their name, platform, or status. After you have some files in the file manager, you can select one or more files and remove them. You can remove the files by right-clicking them or by clicking
Remove Files
.
Version 1.10
229
Lumberyard Developer Guide
Cloud Gems
Now you are ready to add a package to the manifest.
Click
New Package
.
8. Type a name for the package and choose the platform type for it.
9. The new package appears in the right pane of
Dynamic Content Manager
. You can sort the packages by column.
Version 1.10
230
Lumberyard Developer Guide
Cloud Gems
Each package is stored in a
.pak
file, which is the archived file format that Lumberyard uses for its released game assets. You can have one or more packages per manifest, and you can assign the same file to multiple packages. This is useful when you have common files and platform-specific files that you need to deliver in one package. It is also useful if you want to create bundles of items that might share assets.
10. To add files to the package that you created, drag the files from the manifest on the left to the package on the right. You can drag multiple files into the same
.pak
file.
You can drag platform-specific files to a package with that platform type only. If you drag multiple files to a package and the platform type of these files does not match that of the package,
Lumberyard warns you about the incompatible files.
Version 1.10
231
Lumberyard Developer Guide
Cloud Gems
The icons that appear in the
Packages
pane are described as follows.
Icon Description
A file in a package has been updated in the asset cache. The contents of the package have been updated, so you might want to upload the package again.
The package is not in the cloud. This can occur when the package has not yet been uploaded.
A package has changed with respect to its copy in the cloud. The contents of the package have been updated, so you might want to upload the package again.
The local package matches the package in the cloud. No action is necessary.
Notes
• You can remove individual files from a package, but to help prevent inadvertent removal, this action is limited to one file at a time.
• You can also use
Dynamic Content Manager
to delete packages, but deleting a package does not delete the staged packages in the cloud. To delete staged packages in the cloud, you must use the web-based Cloud Gem Portal that manages the service side of a cloud gem.
11. You can change the target platforms for the current manifest at any time.
a. Click the settings button and choose
Change Target Platforms
.
b. Choose the platforms that you want. If no target platforms are selected, all supported platforms are added.
Version 1.10
232
Lumberyard Developer Guide
Cloud Gems
After you update the target platforms,
Dynamic Content Manager
lists only the files and packages for the platforms that you selected. You can add files and folders only for the selected target platform.
12. When you are ready, click
Upload Packages
.
13. (Optional) To sign your packages, select
Sign packages with security key
.
14. If you haven't yet generated key pairs, click
Next
to generate a new key pair, and then click
Continue
.
Version 1.10
233
Lumberyard Developer Guide
Cloud Gems
You can also use the file menu to generate a new key pair at any time.
15. After the new key pair is generated, click
Upload
. This action both creates the package files locally and uploads them to your private staging bucket in the AWS Cloud.
The status bar of the main window shows upload process messages.
Version 1.10
234
Lumberyard Developer Guide
Cloud Gems
An animation in the
S3 Status
column indicates the package that is being uploaded.
The packages appear in the
Dynamic Content
section of the Cloud Gem Portal. By default,
Lumberyard marks them as
Private
. When you are ready, you can move the packages to the
Public
stage to make them available for download by game clients. For more information on this step, see
Managing Dynamic Content Packages (p. 235)
.
Managing Dynamic Content Packages
The Dynamic Content Cloud Gem provides an easy way for you to update your game content for your customers. After a release, you can update content without an app submission or traditional patch process. The Dynamic Content Cloud Gem provides a framework for you to group outdated assets into manifests. You can assign groups of assets together into
.pak
files (
.zip
files), and distribute these files to customers according to your own rules or schedules.
Prerequisites
To use the Dynamic Content Cloud Gem, you must meet these requirements:
• You must be using a Lumberyard Editor project that has the Dynamic Content Cloud Gem enabled (in
Project Configurator, select
Cloud Gem Dynamic Content
).
• You have a project stack created in Cloud Canvas Resource Manager (p. 184) .
• You have created a deployment stack in Cloud Canvas Resource Manager.
Dynamic Content Manager (p. 226)
.
• You have the Cloud Gem Portal open. In Lumberyard Editor, click
AWS
,
Open Cloud Gem Portal
.
To view packages in the Dynamic Content Gem Portal
1. On the welcome page of the Cloud Gem Portal, click
Cloud Gems
or
View all Cloud Gems
.
Version 1.10
235
Lumberyard Developer Guide
Cloud Gems
2. In the list of enabled cloud gems, pause on the thumbnail for the Dynamic Content Gem.
The thumbnail shows the number of files in the gem and the status of the cloud API (
Online
or
Offline
). The online status comes from an API Gateway call to the Dynamic Content Cloud Gem.
3. Click the thumbnail. The dynamic content might take a few seconds to appear as AWS resources load.
The loaded page shows the packages (
.pak
files) that you added when you used
Dynamic Content
Manager
.
Version 1.10
236
Lumberyard Developer Guide
Cloud Gems
Dynamic Content Package Stages
You can use separate deployment stacks to handle different release workflows. For this purpose, the
Dynamic Content Cloud Gem currently supports the following publishing stages.
•
Private
– The packages are never downloaded by the game client. When you upload new or altered content to the cloud from
Dynamic Content Manager
, your packages and manifest are always put in the
Private
stage. This empowers you to choose when and how your changes are released to customers.
•
Scheduled
– The packages are conditionally downloaded by the game client based on a specific date and time.
•
Public
– The packages are available to everyone that uses the deployment.
You can use these stages to add an additional layer of protection against inadvertent deployments of dynamic content to your players.
Package Nesting
Each stage includes entries for your manifests and packages. Packages are nested according to the hierarchy that you determine when you create them. In the following example, the two root-level manifest packages highlighted in yellow have one child asset package each, which are highlighted in gold.
Version 1.10
237
Lumberyard Developer Guide
Cloud Gems
The icons next to the package names show the actions available for the packages.
Icon Description
You can edit or delete root level packages.
You can only delete child packages.
Editing Packages
Editing is triggered when you drag and drop a root-level package from one stage to another.
When you edit a package, you can alter its
Transition
,
Scheduling
, and
Package Children
, as the following image shows.
Version 1.10
238
Lumberyard Developer Guide
Cloud Gems
•
Transition
– Choose the target stage that you want to move the package to.
•
Scheduling
– Set packages to scheduled
or indefinite
. Packages that you place in the public stage cannot have a date; they are always indefinite.
•
Package Children
– Select which children of the root package you would like to include in this transition.
By default all children move with the root package. If you clear the selection for some children, they become orphans in the current stage and no longer visible to the game client.
Deleting Packages
Deleting a root package causes its child packages to become orphans that are no longer visible to the game client. Accordingly, when you delete a package, the following confirmation message appears.
Version 1.10
239
Lumberyard Developer Guide
Cloud Gems
Displaying Package Metadata
To display the metadata for a package, click the space next to the package name. The metadata for the package appears at the bottom of the browser.
Version 1.10
240
Lumberyard Developer Guide
Cloud Gems
Using lmbr_aws for Dynamic Content
When you enable the Dynamic Content Cloud Gem, associated commands become available in the lmbr_aws
CLI. You can use these commands to update dynamic content and perform operations on manifest files and buckets.
Updating Dynamic Content with lmbr_aws
To perform dynamic content updates, type the following command.
lmbr_aws dynamic-content upload-manifest-content --manifest-path
<manifest name>
--stagingstatus
<PUBLIC|PRIVATE>
•
<manifest name>
– specifies the name of the manifest in the manifests
directory (for example,
DynamicContentTest.json
).
•
<PUBLIC|PRIVATE>
– (Optional) Specify PUBLIC to release the content immediately. The default is
PRIVATE.
Note
For information on using the Lumberyard user interface to upload content, see Using Dynamic
and Managing Dynamic Content Packages (p. 235) .
lmbr_aws Extensions
The following lmbr_aws
CLI commands are enabled by the Dynamic Content Cloud Gem.
add-file-to-pak
Add a given file to the specified
.pak
file.
In addition to the Common Arguments (p. 436) , this command accepts the following arguments:
•
--file-name
<file_name>
– File entry to add.
•
--manifest-path
<manifest_path>
– Path to the manifest file to use.
•
--pak-file
<pak_file>
– Pak file to add the file to.
•
--platform-type
<platform_type>
– Platform of the file entry to add.
add-manifest-file
Adds a file to the content manifest for the project.
In addition to the Common Arguments (p. 436) , this command accepts the following arguments:
•
--file-name
<filename>
– (Required) The name of the file, including the local directory (for example, staticdata/csv/gameproperties.csv
, where local directory is staticdata/csv/
.
•
--cache-root
<cache directory>
– The reference for the local cache directory (for example,
@assets@
). The default is
@assets@
.
•
--bucket-prefix
<prefix>
– The bucket prefix under which to store the file in the content bucket.
•
--manifest-path
<path>
– The path of a manifest file other than the default.
Version 1.10
241
Lumberyard Developer Guide
Cloud Gems
•
--output-root
<default directory path>
– The path of the default directory to which to write. The default is
@user@
.
•
--platform-type
<platform type>
– The type of platform type to which the asset belongs. The value defaults to the current platform.
add-pak
Add a new pak entry to the manifest..
In addition to the Common Arguments (p. 436) , this command accepts the following arguments:
•
--manifest-path
<manifest_path>
– Path to the manifest file to use.
•
--pak-name
<pak_name>
– Name of the pak (the final filename will be
<pak-name>
.
<platform>
.pak).
•
--platform-type
<platform_type>
– The platform type for the
.pak
file.
build-new-paks
Create
.pak
files based on manifest files which have changed.
In addition to the Common Arguments (p. 436) , this command accepts the following arguments:
•
--all
– Upload all
.pak
files regardless of the results of the file check.
•
--manifest-path
<manifest_path>
– The path of the manifest file to use.
clear-dynamic-content
Empty the bucket and table content.
In addition to the Common Arguments (p. 436) , this command accepts the following argument:
•
--manifest-path
<manifest_path>
– Path to the manifest file to use.
compare-bucket-content
Compares manifest content to the bucket contents.
In addition to the Common Arguments (p. 436) , this command accepts the following argument:
•
--manifest-path
<path>
– The path of a manifest file other than the default.
create-new-manifest
Create a new manifest.
In addition to the Common Arguments (p. 436) , this command accepts the following arguments:
•
--manifest-name
<manifest_name>
– Name of the new manifest.
•
--manifest-path
<manifest_path>
– Path to the new manifest.
•
--target-platforms
<target_platforms> [<target_platforms> ...]
– Target platforms for this new manifest (the default is all supported platforms).
empty-content-bucket
Empties the content bucket contents.
Version 1.10
242
Lumberyard Developer Guide
Cloud Gems
In addition to the Common Arguments (p. 436) , this command accepts the following argument:
•
--manifest-path
<path>
– The path of a manifest file other than the default.
generate-keys
Generate a new public/private key pair for use by the dynamic content system.
In addition to the Common Arguments (p. 436) , this command accepts the following argument:
•
--key-name
<key_name>
– The name of the key file to use.
list-bucket-content
Lists the manifest files in the content bucket.
In addition to the Common Arguments (p. 436) , this command accepts the following argument:
•
--manifest-path
<path>
– The path of a manifest file other than the default.
remove-manifest-file
Removes a file from the content manifest for the project.
In addition to the Common Arguments (p. 436) , this command accepts the following arguments:
•
--file-name
<filename>
– (Required) Removes a file from the content manifest for the project. The file removed matches the value for
--file-name
that is specified in the add-manifest-file
command.
•
--manifest-path
<path>
– The path of a manifest file other than the default.
request-url
Requests a URL for the specified file.
In addition to the Common Arguments (p. 436) , this command accepts the following argument:
•
--file-path
<file_path>
– The file in the bucket.
set-staging-status
Sets the staging status of the specified file.
In addition to the Common Arguments (p. 436) , this command accepts the following arguments:
•
--file-path
<file_path>
– The file in the bucket.
•
--staging-status
<staging_status>
– Staging status (specify PUBLIC for availability now or
WINDOW for availability within a specified start and end date).
•
--start-date
<start_date>
– Start date value for windowed staging (specifiy NOW or UTC date/time in the format
January 15 2018 14:30
).
•
--end-date
<end_date>
– End date value for windowed staging (specify NEVER or UTC date/time in the format
January 15 2018 14:30
).
show-manifest
List all entries in the content manifest.
Version 1.10
243
Lumberyard Developer Guide
Cloud Gems
In addition to the Common Arguments (p. 436) , this command accepts the following arguments:
•
--file-name
<filename>
– The file entry (local directory + key) to show.
•
--manifest-path
<manifest_path>
– Path to the manifest file to use.
•
--platform-type
<platform_type>
– The platform type of the file entry to list.
•
--section
<section>
– Section to show (
Paks
or
Files
).
show-signature
Show the signature which would be created for a specified file.
In addition to the Common Arguments (p. 436) , this command accepts the following argument:
•
--file-name
<file_name>
– The filename for which to show the signature.
test-signature
Tests whether a base64 signature is valid for the specified string.
In addition to the Common Arguments (p. 436) , this command accepts the following arguments:
•
--signature
<signature>
– Base64 encoded signature.
•
--to-sign
<string_to_sign>
– The string to sign.
update-manifest
Updates the manifest with current file hashes.
In addition to the Common Arguments (p. 436) , this command accepts the following argument:
•
--manifest-path
<path>
– The path of a manifest file other than the default.
update-target-platforms
Update the target platform of a manifest file.
In addition to the Common Arguments (p. 436) , this command accepts the following arguments:
•
--manifest-path
<manifest_path>
– Path to the manifest file to use.
•
--target-platforms
<target_platforms> [<target_platforms> ...]
– Updated target platforms for this new manifest (the default is all supported platforms).
upload-manifest-content
Updates the manifest and uploads changed manifest content to the content bucket.
In addition to the Common Arguments (p. 436) , this command accepts the following arguments:
•
--manifest-path
<path>
– The path of a manifest file other than the default.
•
--staging-status
<PUBLIC|PRIVATE>
– (Optional) Specify PUBLIC to make the new content public immediately. The default is PRIVATE.
•
--all
– (Optional) Updates all content in the manifest regardless of whether it appears to have been updated already.
Version 1.10
244
Lumberyard Developer Guide
Cloud Gems
Testing the Dynamic Content System
Lumberyard contains a basic level called
DynamicContentTest
that you can use to verify that the dynamic content system is functioning properly. The level is located in the dev\CloudGemSamples\Levels
\CloudGemTests\DynamicContentTest
directory.
Prerequisites
To test any cloud gem, you must have a deployment with the necessary resources. These resources are created through the
Cloud Canvas Resource Manager
. For detailed instructions on creating these resources, see
Initializing Cloud Canvas Resource Manager (p. 408)
.
For the test, you are likely to play the role of both content creator and game client. Because the editor prefers loose files to
.pak
files, you might want to run the engine in game client mode instead of editor mode. When you run the engine in editor mode, updated data does not take precedence during run time. If you do want to run the test in editor mode, you can change this setting by typing the console command sys_PakPriority=1
before you start the test. After testing, if you want the editor to return to preferring loose files (the default), type the console command sys_PakPriority=0
.
To run the level as a game client, you must export the mappings from your deployment stack to your
<projectname>
\config
directory. To export the mappings, select your deployment in
Cloud Canvas Resource Manager
and click
Export Mapping
. The mappings file has the format
<deploymentname>
.awslogicalmappings.json
. Because old mapping files can create conflicts, ensure that the config
directory contains only the single mappings file that you want to use.
The test level contains a button that requests an update of a predefined dynamic content manifest that describes a single
.pak
file. The
.pak
file references a gameproperties.csv
file. The static data system uses the properties file to reflect a property value to Lua and to a text control that displays the property value.
When the level starts, the text box displays the current value of the property. Pressing the button starts the update process. During the update, the client checks the dynamic content system for new data.
When it detects new data, it downloads the data and reflects the new value.
Data Preparation
To create data that is considered "new" for the purposes of the test, perform the following steps.
To prepare data for the test
1. Open the gameproperties.csv
file in the dev\CloudGemSamples\StaticData\CSV
directory. The file contents are similar to the following:
GameProperty,Value
DynamicMessage,"LOCAL DATA"
2. Set the
"LOCAL DATA"
message to a string that you want to receive when the data is updated (for example,
"UPDATED"
).
3. Save the file.
4. Do one of the following:
• At a command line prompt, type the following command: lmbr_aws dynamic-content upload-manifest-content --manifest-path
DynamicContentTest.json --staging-status PUBLIC
• Use the packer tool to upload the manifest content. The manifest file that packs up gameproperties.csv
is
DynamicContentTest.json
. Normally you should not have to alter
Version 1.10
245
Lumberyard Developer Guide
Cloud Gems
DynamicContentTest.json
for testing purposes. However, if you want to use it to ensure that your test contains no old test data, configure it like this:
{
"Files": [
{
"bucketPrefix": "",
"cacheRoot": "@assets@",
"hash": "",
"keyName": "gameproperties.csv",
"localFolder": "StaticData/CSV",
"outputRoot": "@user@",
"pakFile": "",
"platformType": ""
}
],
"Paks": [
]
}
At this point, you have created and uploaded a
.pak
file that contains the current version of your gameproperties.csv
file and your manifest.
5. Stage the uploads as
PUBLIC
, which means that they are ready for download. If you used the command line option in the previous step to upload your data, this was done for you with the
--staging-status PUBLIC
option. If you used the packer tool to perform the upload, open the Cloud Gem Portal from your AWS menu, open your Dynamic Content Gem, and move the
DynamicContentTest.manifest.pak
file from the
Private
column to the
Public
column.
6. Change your gameproperties.csv
file message back to
"LOCAL DATA"
or its original message. Do this so that you can be sure that your updated message comes from the downloaded content.
Running the Test
After you have saved the gameproperties.csv
file to reflect local data, you can run the test.
To test the dynamic content system
1. Start the
DynamicContentTest
level. When you start the level, you should see the most recent message that you entered in the game properties file ("LOCAL DATA" in step 6 of
2. Click
Update
. You should see the update in 3 to 10 seconds, depending on Lambda function latency.
Diagnosing Failures
When diagnosing a failure, you must determine how far your updated data went in the processing chain.
Check the .pak File for Upload
First, open the
.pak
file that was to be uploaded with 7-Zip or a similar utility. The file is in the location
CloudGemSamples\DynamicContent\Paks\DynamicContentTest.shared.pak
. The
.pak
file contains the
.csv
file that the end client should have received. If something is wrong with the
.pak
file, the packing process was faulty and should be repeated. If so, delete the
.pak
file. In your gameproperties.csv
file, edit the message you want. Configure the
DynamicContentManifest.json
section earlier in this document. Run the upload command again. Finally, recheck that your
.pak
file has the correct
.csv
file and data.
Version 1.10
246
Lumberyard Developer Guide
Cloud Gems
Check the Downloaded .pak File
If your local
.pak
file for upload is free of errors, check the file that was downloaded. The downloaded file is located in the user directory for your game project (for example,
CloudGemSamples\pc\user
\dynamiccontent\paks\DynamicContentTest.shared.pak
). Perform the same inspection on this file as you did for the file in the upload location. If the data is what you expect, the client did not receive the new data. This can occur because of a download failure, or because the data in the Amazon S3 bucket is incorrect.You can use the AWS console to inspect the corresponding files in your Amazon S3 bucket.
If the downloaded
.pak
file was updated correctly, then the problem might be one of the following:
• The dynamic content system itself did not reload the file.
• The dynamic content system did not accept the new data. Check whether sys_PakPriority
is set to
0
.
In editor mode, you must set this to
1
. For more information, see the
Prerequisites (p. 245) section
earlier in this document.
• The test is not reflecting the file correctly and requires further diagnosis.
Test Implementation Details
Because
DynamicContent
and
StaticData
are system components, they do not have to be added to the entity in the test level. Since in most cases the dynamic content that Lumberyard loads would persist longer than any entity, the example here shows you how to use the
SystemComponent
. The entity in this level contains only Lua script and test logic.
1. In the script, the example connects to the EBus, loads the canvas, and waits for the button event.
Version 1.10
247
Lumberyard Developer Guide
Cloud Gems
When the button is pressed, the code requests the new manifest. The content specified by the manifest is automatically retrieved.
2. After the content is retrieved, a
NewPakContentReady
event fires.
In the test example, you already know that the
.pak
file contains game properties data. In more complex implementations, you might need to query the contents of the file.
3. The
UpdateGameProperties()
function requests that the static data system load the
.csv
file.
4. The file load triggers the
TypeReloaded
event, which calls the
UpdateText()
function.
At this point, the user interface text has been updated with the new game property value.
5. Because the example attached to the
SystemComponent
, and the sample might be running in the editor, the cleanup routine manually removes the dynamic content.
Dynamic Content Engineering Details
This topic provides programmatic details about the dynamic content update process. This includes manifest file information, Dynamic Content Cloud Gem EBus events, and Dynamic Content Cloud Gem
Version 1.10
248
Lumberyard Developer Guide
Cloud Gems service API. For information about the lmbr_aws
CLI extensions enabled by the Dynamic Content Cloud
Gem, see Using lmbr_aws for Dynamic Content (p. 241) .
Manifest File
In your Lumberyard installation, the default location of the manifest file is
<GameFolder>
/AWS/
DynamicContent/DynamicContentManifest.json
.
The following is a simple example manifest for the
SamplesProject DontDie
sample.
"Files": [
{
"hash": "3bebdb5bdb8cff74642e5f7f3dc4e900",
"outputRoot": "@user@",
"bucketPrefix": "static-data",
"keyName": "gameproperties.csv",
"cacheRoot": "@assets@",
"platformType": "",
"localFolder": "staticdata/csv"
}
]
The following table describes the properties in the manifest file.
Property
hash outputRoot bucketPrefix keyName cacheRoot platformType localFolder
Description
MD5 hash of the file.
Base output directory.
Prefix inside the bucket for the file
Name of the file key in the bucket, which will be appended to the beginning of the hash. The final key name has the format bucketPrefix/keyName
.
Root directory to search for copies of the outdated file asset.
Windows ( pc
), macOS ( osx_gl
), or Linux ( linux
). An empty value specifies all platforms.
Directory to write locally within the outputRoot
. The full output has the format outputRoot/localFolder/keyName
.
EBus Events
The Dynamic Content Cloud Gem provides an EBus API and includes calls exposed to Lua. The basic toplevel update request looks like this:
EBUS_EVENT_RESULT(requestSuccess,
CloudCanvas::DynamicContent::DynamicContentRequestBus,
RequestManifest, manifestName) requestSuccess (bool)
– Specifies whether the request was successfully sent.
manifestName(char*)
– Specifies the plaintext name of the manifest (for example,
DynamicContentTest.json
). The system handles
.pak
file and platform naming conventions (for example,
DynamicContentTest.shared.pak
).
Note
A legacy
RequestManifest
flow graph node exists, which calls the same EBus.
Version 1.10
249
Lumberyard Developer Guide
Cloud Gems
Manifest Received
The following EBus events are triggered when a manifest has been received successfully or unsuccessfully.
Success
EBUS_EVENT(CloudCanvas::DynamicContent::DynamicContentRequestBus, ManifestUpdated,
bucketName, bucketPrefix)
When all
.pak
files are complete, a
RequestCompleted
event is broadcast.
Failure
EBUS_EVENT(CloudCanvas::DynamicContent::DynamicContentRequestBus, ManifestFailed,
bucketName, bucketPrefix, errorStr)
Service API
The Dynamic Content Cloud Gem exposes API calls through Amazon API Gateway for both the Cloud
Gem Portal and the game client.
The following tables list the calls for the portal.
Portal API Call
/service/status GET
/portal/info/{file_name} GET
Description
Returns the service's status.
Return detailed information about a specific file. This includes the file's name, staging status, staging start and end dates (optional), and parent (optional).
Request deletion of an existing item from the bucket and table.
/portal/info/{file_name}
DELETE
/portal/content GET
/portal/content DELETE
/portal/content POST
Request the list of files to display in the web portal.
Request to deletion of all content from the bucket and staging table.
Request alteration of the staging settings on a provided list of files.
The following table lists the calls for the client.
Client API Call
/client/content POST
Description
Request presigned URLs for a list of files. Returns the URLs or a failure message.
The Player Account Cloud Gem provides a standalone player authentication and management solution that uses Amazon Cognito. The cloud gem includes a player registration API, built-in two-step verification, and support for both anonymous and authenticated players. You can use your Cloud Gem
Portal to administer players and manually register, delete, ban, and update their accounts.
Version 1.10
250
Lumberyard Developer Guide
Cloud Gems
Prerequisites
This tutorial assumes the following:
• You are using a Lumberyard project that has the Cloud Gem Player Account enabled (in Project
Configurator, select
Cloud Gem Player Account
).
• You have created a project stack in Cloud Canvas Resource Manager (p. 184) .
• You have a deployment stack with Player Account Cloud Gem resources in Cloud Canvas Resource
Manager.
• You have opened the Cloud Gem Portal (in Lumberyard Editor, choose
AWS
,
Cloud Gem Portal
.)
If you don't meet the prerequisites, follow the steps in
Setting Up and Accessing the Cloud Gem
Cloud Gem Player Account
in Project Configurator.
Legal Restrictions
You are responsible for (a) providing legally adequate privacy notices to your end users; (b) obtaining any necessary consent from the end user for the collection, use, transfer, and storage of any name, password, other login information, or personally identifiable information or personal data of any end user that you
(or any third-party plug-in or service provider you use) may access; (c) using and authorizing others to access and use the information only for the purposes permitted by the end user; and (d) ensuring the information is collected, used, transferred, and stored in accordance with all laws, rules, and regulations applicable in jurisdictions in which your applications are used.
Using the Player Account Cloud Gem Portal
To open the Player Account Cloud Gem Portal, click
Player Account
on the
Cloud Gems
page.
Version 1.10
251
Lumberyard Developer Guide
Cloud Gems
Adding Users
The first screen is the
Player Account
page, which lists the player accounts in your game. If your game doesn't have any players yet, the list is empty.
To add a player to your game
1. Click
Add Account
to add a player.
2. In the
Add Account
dialog box, fill in the appropriate information. Only the
Username
and
fields are required.
Version 1.10
252
Lumberyard Developer Guide
Cloud Gems
After you fill in the information, the player appears in the list of player accounts.
Each player entry has the following fields:
•
User Name
– The Amazon Cognito user name.
•
Player Name
– The name of the player in the game.
•
Cognito Identity ID
– The unique ID of the player in the Amazon Cognito database. This ID field is initially empty and is filled after the user signs in for the first time.
•
– The email of the player.
•
Account ID
– An automatically assigned ID.
•
Account Status
– The current status of the account. The following statuses are possible:
•
Archived
– The account has been archived due to inactivity. You can change this from the
Amazon Cognito console.
•
Compromised
– This account requires further investigation from Amazon Cognito console.
•
Disabled
– The user account is currently disabled. You can reenable it on the Amazon Cognito console.
•
Force Change Password
– An AWS administrator has used Amazon Cognito to create the user account, and the user now must change their temporary password before they can successfully sign in.
•
Reset Required
– The user's account was imported, but the user has not logged in.
•
Unconfirmed
– The player account hasn't confirmed the account's email address or phone number. The account is unusable until it has been confirmed. To confirm an account manually,
see Confirming an Account (p. 258)
later in this document.
•
Unknown
– The account is in an unknown state. Use the Amazon Cognito console to investigate further.
3. You can use the box and filter on the upper right of the
Player Account
page to search the list of player accounts.
Version 1.10
253
Lumberyard Developer Guide
Cloud Gems
Viewing and Editing Account Details
To view the details of an account, click the account. The
Player Account Profile
page shows additional account details.
Version 1.10
254
Lumberyard Developer Guide
Cloud Gems
To edit the user information, click the settings icon in the
Player Account Profile
box.
Version 1.10
255
Lumberyard Developer Guide
Cloud Gems
All fields are editable except
Account ID
and
Username
.
Version 1.10
256
Lumberyard Developer Guide
Cloud Gems
Resetting Passwords
To reset a user's password, click the arrow next to the settings icon for the user, and then click
Reset
Password
.
Version 1.10
257
Lumberyard Developer Guide
Cloud Gems
This resets the password and sends a temporary password to the player's email account.
Confirming an Account
You can use the Player Account Cloud Gem Portal to confirm an account whose status is
Unconfirmed
.
To confirm an account
1. Click the player account with
Unconfirmed
status.
2. Click the arrow next to the settings icon.
3. Choose
Confirm Account
.
Banning an Account
Accounts that you ban no longer can log in to the game.
To ban an account
1.
On the
Player Account
page, click the ban icon next to the player.
2. In the
Ban Player Account
confirmation dialog box, click
Save
. The account disappears from the
Accounts
tab.
3. Click the
Banned Players
tab. The banned account has been added to the banned players list.
Version 1.10
258
Lumberyard Developer Guide
Cloud Gems
Removing a Ban
Removing a ban from an account is similar to adding one.
To remove an ban from an account
1. On the
Player Account
page, click the
Banned Players
tab.
2.
Click the ban icon for the account that you want to reinstate.
Version 1.10
259
Lumberyard Developer Guide
Cloud Gems
3. In the confirmation dialog box, click
Save
.
4. Click the
Accounts
tab. The account reappears in the list of players.
Next Steps
After you have added player accounts to your Cloud Gem Portal, you can start using them in your game.
The Lumberyard team is always looking for feedback on cloud gems and suggestions for improvements.
Feel free to reach out to us on our forums or send email to
.
The Player Account Sample Level
The CloudGemSamples project contains a sample level named
PlayerAccountSample
. The player account sample level provides a menu from which users can create an account, verify their email addresses, sign in and out of their accounts, and recover their passwords by email.
The following table describes the files for the player account sample level.
Location
\dev\CloudGemSamples\Levels
\PlayerAccountSample
\dev\CloudGemSamples\Scripts
\PlayerAccount
\dev\CloudGemSamples\UI
\Canvases\PlayerAccount
Description
A level that contains an entity with the Lua script component.
The Lua scripts that manage the UI canvases and interact with the
Player Account Cloud Gem's EBus API.
The UI canvases displayed for the player.
Note that in the sample, UI canvases do not include functionality for displaying error messages graphically; instead, error messages are output to the console. If you integrate this gem into an existing project, you should use the UI canvas to show error messages. For example, you could do this when the confirmation code is incorrect or the password does not meet the minimum password length. For more
information on using the Player Account Cloud Gem in an existing project, see Integrating the Player
Account Cloud Gem into an Existing Project (p. 267)
.
The following diagram shows how the UI canvases are connected. For more information on the Amazon
Cognito user pool signup process, see the Signing Up and Confirming User Accounts page in the Amazon
Cognito Developer Guide .
Version 1.10
260
Lumberyard Developer Guide
Cloud Gems
Testing the Player Account Cloud Gem
To test the Player Account Cloud Gem, you can use the CloudGemSamples project that is included with
Lumberyard.
To test the Player Account Cloud Gem
1. In Project Configurator, select the
CloudGemSamples
project.
2. Start Lumberyard Editor.
3. On the
Welcome to Lumberyard Editor
screen, click
Open level
,
Levels
,
PlayerAccountSample
,
Open
.
4. Click
AWS
,
Cloud Canvas
,
Select a Deployment
.
5. Click the deployment that you want to use, and then click
OK
.
6. Press
Ctrl+G
to start the game.
7. In the main menu of the sample, click
Create Account
.
Note
If the
Create Account
option does not appear, click
Sign Out
and try again.
8. Type a user name, password, and an email account to which you have access.
Version 1.10
261
Lumberyard Developer Guide
Cloud Gems
9. Click
Create
.
10. From the email account, copy the confirmation code that you receive.
11. In Lumberyard, paste the confirmation code into the
Verification Code
box, and then click
Verify
.
12. Sign in using the password that you specified earlier. This tests the custom authentication flow.
13. Click
Manage Account
.
14. Click
Edit Account
.
Version 1.10
262
Lumberyard Developer Guide
Cloud Gems
15. Type in a name for
Player Name
, and then click
Save
. This step tests the player service API.
The main menu displays the player name that you specified.
16. Press
ESC
to stop the game.
17. In Lumberyard Editor, click
AWS
,
Open Cloud Gem Portal
.
18. In the Cloud Gem Portal, choose the deployment that you are using for the test.
19. Click
Cloud Gems
, and then click
Player Account
.
Version 1.10
263
Lumberyard Developer Guide
Cloud Gems
20. The gem displays the account that you created.
Click the account so that you can edit its information. These steps test the administrative service API.
21. In
Player Account Profile
, click the down arrow, and then click
Edit
.
Version 1.10
264
Lumberyard Developer Guide
Cloud Gems
22. Make a change to the player name, and then click
Save
.
Version 1.10
265
Lumberyard Developer Guide
Cloud Gems
23. Verify the change in the profile for the player.
Version 1.10
266
Lumberyard Developer Guide
Cloud Gems
Integrating the Player Account Cloud Gem into an Existing Project
To integrate the Player Account Cloud Gem into an existing project, you must enable the Player Account
Cloud Gem, update your deployment stack, and integrate the gem into your game menu.
To integrate the Player Account Cloud Gem into an existing project
1. Enable the gem. In Project Configurator, click
Cloud Gem Player Account
.
2.
Create or update the project stack (p. 409) .
The Player Account Cloud Gem uses an Amazon Cognito user pool. If you created your project using a version of Lumberyard earlier than 1.9, update it by opening a command prompt window in the
\dev directory and typing the following command.
lmbr_aws project update-code
3.
Create or update the deployment stack (p. 412)
. Be sure the
CloudGemPlayerAccount
resource group is added to your deployment. If your deployment doesn't have the
CloudGemPlayerAccount resource group, make sure that the Cloud Gem Player Account gem is enabled in Project
Configurator.
4. At a command prompt, type the following command to update the deployment access stack.
lmbr_aws deployment update-access
This ensures that the
CloudGemPlayerAccount
resource group is correctly linked to the
PlayerAccess identity pool in the deployment access stack.
5. Integrate the gem into your game menu. We recommend that you include the following features:
•
A global signout
– This security feature allows players to invalidate an account's tokens across all devices if a device has been lost or stolen. The sample level shows how to offer this as a standalone feature. If the previous password was compromised and already used to obtain authentication tokens, you can also have the menu automatically globally sign out after a password change. To implement this functionality, do the following:
1. Monitor the
CloudGemPlayerAccountNotifications::OnChangePasswordComplete
EBus event.
Version 1.10
267
Lumberyard Developer Guide
Cloud Gems
2. When you receive confirmation that the password change has succeeded, send the following event.
EBUS_EVENT(CloudGemPlayerAccountRequestBus, GlobalSignOut, username)
•
Email verification
– An email verification step ensures that email can be used to recover account access if a password has been forgotten. You can customize the content of the verification emails by using Lambda triggers. To add a new Lambda trigger to the AWS CloudFormation template, use the
LambdaConfig
property of
PlayerUserPool
in the dev\Gems\CloudGemPlayerAccount\AWS
\resource-template.json
file. For more information, see Customizing User Pool Workflows by
Using AWS Lambda Triggers .
Building the Menus for the Player Account Cloud Gem
To build the menus, use the code for
CloudGemPlayerAccountRequestBus
and
CloudGemPlayerAccountNotificationBusHandler
in the dev\Gems\CloudGemPlayerAccount\Code
\Include\CloudGemPlayerAccount\CloudGemPlayerAccountBus.h
file. Keep in mind the following points:
• Most of the EBus events are wrappers for Amazon Cognito user pool API operations. For the Amazon
Cognito API reference, see Amazon Cognito Identity Provider .
• To return the user name for the currently logged-in user, call the
GetCurrentUser
function, which has a corresponding
OnGetCurrentUserComplete
event. This function and EBus event are not part of the
Amazon Cognito user pool API but are needed for most calls to the API.
• The
GetCurrentUser
function also loads the returned user's credentials and caches them inside the gem's system component. As a result, subsequent calls to
GetCurrentUser
are faster.
• The act of signing in also caches the user's credentials inside the gem's system component.
For information about Player Account Cloud Gem functions for creating accounts, password recovery, signing in and out, and account management, see
Player Account Cloud Gem Implementation
.
Storing Data Associated with a Player Account
Each player account has a randomly generated account ID. When you store data associated with a player, use this ID instead of the identifiers provided by the Amazon Cognito user and identity pools. You should do this for the following reasons:
• Lumberyard uses the
PlayerAccounts
table defined in the dev\Gems\CloudGemPlayerAccount\AWS
\resource-template.json
file to map account IDs to Amazon Cognito IDs. By associating a player's data with the account ID, you can move all of the player's data from one identity to another by simply updating the mapping.
• The Amazon Cognito ID on the Amazon Cognito identity pool is not guaranteed to stay the same for a particular player. For example, it can change if identities are merged. Amazon Cognito identity pools are public facing and do not prevent the merging of identities.
Version 1.10
268
Lumberyard Developer Guide
Cloud Gems
• If you configure the
PlayerAccess
identity pool to support identity providers other than the Amazon
Cognito user pool, the user pool's user name cannot be used for players that use another provider.
• If a user name is deleted from the Amazon Cognito user pool, the name can be reused. Amazon
Cognito user pools are publicly visible and do not prevent a user from deleting his or her own user name.
A
PlayerName
field is provided in the
PlayerAccounts
table as an example of how to store player data for an account. The Amazon Cognito user pool supports storing a variety of attributes and could also be used for storing player data. However, this is not recommended if you configure the
PlayerAccess identity pool to use more than one identity provider. In such a scenario, some players might not have a user in the Amazon Cognito user pool.
Warning
Do not store the data for unauthenticated (guest or anonymous) players who are using an
Amazon Cognito ID directly or indirectly on the server. The reasons not to store this data are the following:
• A person who knows the Amazon Cognito ID for an unauthenticated account can claim the identity by linking it to a user that the person controls. The identity's original owner cannot recover the account if an original device is lost or the identity is stolen. For more information on identity pools, see Identity Pools .
• The local copy of the unauthenticated Amazon Cognito ID is overwritten with a new one when the player logs in and out.
• The player has no way to recover an unauthenticated Amazon Cognito ID after it has been overwritten locally. The identity still exists in the identity pool, but the identity and data associated with its Amazon Cognito ID effectively become orphaned.
• The buildup of orphaned identities can be misleading when trying to determine the actual number of players.
• If a player uses an unauthenticated identity and then creates a new account, the account ID from the unauthenticated identity does not carry over to the new account.
Obtaining Player Account IDs
You can use the following techniques to obtain player account IDs and account information programmatically.
•
To get a player's account ID in game
– Call
GetPlayerAccount
on the
CloudGemPlayerAccountRequestBus
. This EBus is defined in the dev\Gems
\CloudGemPlayerAccount\Code\Include\CloudGemPlayerAccount\CloudGemPlayerAccountBus.h
file. The player's account ID is in the
AccountResultInfo
parameter of
CloudGemPlayerAccountNotificationBusHandler::OnGetPlayerAccountComplete
.
•
To get the account ID from a Lambda function located behind an API Gateway
– Because Amazon
API Gateway provides the Amazon Cognito ID to the Lambda function, the Lambda function can look up the account ID. To quickly look up the account ID, you can use the global secondary index
Version 1.10
269
Lumberyard Developer Guide
Cloud Gems
CognitoIdentityIdIndex
of the
PlayerAccounts
table. The
PlayerAccounts
table is defined in the dev
\Gems\CloudGemPlayerAccount\AWS\resource-template.json
file.
•
To get the caller's account information without relying on the caller to provide its account
ID
– Use the request's authentication parameters. For an example, see the code in the dev\Gems
\CloudGemPlayerAccount\AWS\lambda-function-code\api\account.py
file.
Player Account Cloud Gem Implementation Details
You can use the API operations described on this page to manage user accounts with the
Functions and Callbacks
Most functions for the Player Account Cloud Gem have a corresponding callback that supplies the results of the call. The results contain the information gathered or error information. To make calls to and receive responses from user registration and login component API operations, you use the
.
The callbacks use this naming convention: For every function
X
, the corresponding callback function is named
On
X
Complete
. For example, when a response to an EBus call of
SignUp()
is ready, the response is sent through the EBus to
OnSignUpComplete()
. For more examples, see dev\Gems
\CloudGemPlayerAccount\Code\Include\CloudGemPlayerAccount\CloudGemPlayerAccountBus.h
.
HasCachedCredentials()
is an exception to this convention because it is a synchronous call and has no corresponding handler.
Functions for Key Player Account Cloud Gem Tasks
You can use the functions described in this section for new account creation, password recovery, user sign-in, and account management. Most of the source code for the classes and functions can be found in the Lumberyard directory
\dev\Gems\CloudGemPlayerAccount\Code\Source
.
Creating an Account (CloudGemPlayerAccountBus)
Use the following functions for creating new accounts.
SignUp(username, password, attributes)
Creates an account. The attributes
parameter contains relevant data (for example, email, address, name, and profile). A confirmation email or text message is sent to the user as part of the signup.
Password recovery requires a valid email address.
OnSignUpComplete(resultInfo, deliveryDetails, wasConfirmed)
A callback function that returns the results (p. 272)
of the signup. The
attribute contains details about where the confirmation code was sent.
ResendConfirmationCode(username)
Resends the confirmation code to the user. The confirmation code received from the user is passed as an argument to
ConfirmSignUp(username, confirmationCode)
.
Password Recovery (CloudGemPlayerAccountSystemComponent)
Use the following functions if a user has forgotten a password and has an account with a valid email or phone number.
Version 1.10
270
Lumberyard Developer Guide
Cloud Gems
ForgotPassword(username)
Causes a confirmation code to be sent to the user.
OnForgotPasswordComplete(resultInfo, deliveryDetails)
Contains information regarding the password reset.
ConfirmForgotPassword(username, password, confirmationCode)
Receives the confirmation code, user name, and new password from the user and sets the new password.
Sign In and Sign Out
Use the following functions to sign users in and out of your game.
InitiateAuth(username, password)
Call this function to sign in users. Sign-in is a two-step process. When
InitiateAuth
finishes, the server issues a challenge to which the client must respond correctly. Currently, authorization by user name and password is supported; MFA and other forms of additional authentication are not.
You have two ways to sign out:
SignOut(username)
and
GlobalSignOut(username)
.
SignOut
Clears all cached authentication information from memory, so that the user's credentials are essentially forgotten. No server-side changes occur, so the authentication information, if it were known, could still be used. The
SignOut
function always succeeds, even if the user is not actually signed in.
GlobalSignOut
Invalidates all access and refresh tokens for the user on all devices that the user might be signed into. Unlike
SignOut
,
GlobalSignOut
can succeed only when the user is signed in.
Account Management (CloudGemPlayerAccountSystemComponent)
All of the following functions require that the user be signed in.
ChangePassword(username, previousPassword, proposedPassword)
Allows a user to update a password without the use of a confirmation code.
DeleteOwnAccount(username)
Deletes the user's account. Use this function with caution.
GetUser(username)
Retrieves attributes (for example, email, address, name, and profile) that have been associated with the user's account.
UpdateUserAttributes(username, attributes)
Updates the specified set of attributes. If any updates require verification, confirmation codes are sent. Details are found in the deliveryDetailsArray
parameter that is passed to
OnUpdateUserAttributesComplete
. Note that it is possible to update attributes that previously did not have any associated information.
Version 1.10
271
Lumberyard Developer Guide
Cloud Gems
VerifyUserAttribute(username, attributeName, confirmationCode)
Following a call to
UpdateUserAttributes
, verifies a single attribute that requires confirmation. Most attribute updates do not require verification.
DeleteUserAttributes(username, attributesToDelete)
Removes the specified set of attributes from the user's account. The attributes can be added again with a call to
UpdateUserAttributes
.
Key Player Account Cloud Gem Classes and Functions
This section describes key classes and functions in the Player Account Cloud Gem.
BasicResultInfo Class
The
BasicResultInfo
class bundles together information returned in almost all responses from the component. The class has no functions to be used at run time and contains the following values, which are public: wasSuccessful
A Boolean that indicates whether the request succeeded.
username
The name of the user for which a request was made.
errorTypeName
The name of the error type.
errorTypeValue
The numeric value of the error type. If errorTypeValue
is greater than or equal to 0, it corresponds to a standard
CognitoIdentityProviderErrors
value. Otherwise, an unexpected error occurred.
Most commonly, the user has not yet signed in for the operation. In this case, see the error information in errorTypeName
for details.
errorMessage
A human readable string that describes the error.
DeliveryDetails Class
The
DeliveryDetails
class provides details related to the sending of confirmation codes to the user. it contains the following string functions:
GetAttributeName()
The name of the attribute for which a confirmation code was sent (for example, email
).
GetDeliveryMedium()
The medium used to send the confirmation code (for example,
).
GetDestination()
The destination to which the confirmation code was sent. The destination is partially obscured for security (for example, d***@a***.com
).
DeliveryDetailsArray Class
The
DeliveryDetailsArray
class is a collection of
DeliveryDetails
objects and contains the following functions:
Version 1.10
272
Lumberyard Developer Guide
Flow Graph Node Reference
GetSize()
The number of
DeliveryDetails
objects in the array.
At(index)
Returns a copy of the object at the specified index.
UserAttributeValues Class
UserAttributeValues
maps attribute names like address
, and family_name
to attribute values.
An attribute value can be a string up to 256 characters. In general, the attributes are those used by the
OpenID Connect specification . See the
UserAttributeValues.h
file for details.
Phone numbers must follow these formatting rules:
• The phone number must start with a plus (+) sign, followed immediately by the country code.
• The phone number can contain only the + sign and digits.
• You must remove characters such as parentheses, spaces, or dashes from the phone number before submitting the value. For example, a United States–based phone number must follow the format
+14325551212
.
Resource Group
The Player Account Cloud Gem uses an Amazon Cognito user pool that contains all registered users. It is set as an authentication provider with
PlayerAccessIdentityPool
. For more information, see Controlling
.
This section provides a reference of the flow graph nodes available for Cloud Canvas.
•
Cloud Canvas Configuration Nodes (p. 273)
•
Cognito (Player Identity) Nodes (p. 276)
•
DynamoDB (Database) Nodes (p. 278)
•
Lambda (Cloud Functions) Node (p. 285)
•
•
SNS (Notification Service) Nodes (p. 287)
•
SQS (Message Queuing Service) Nodes (p. 290)
•
Static Data (PROTOTYPE) Nodes (p. 291)
For general information on how to use flow graph nodes, see Flow Graph System .
You can use these flow graph nodes to configure Cloud Canvas settings.
Topics
•
ApplyConfiguration node (p. 274)
•
SetConfigurationVariable node (p. 274)
•
•
GetConfigurationVariableValue node (p. 275)
•
SetDefaultRegion node (p. 276)
Version 1.10
273
Lumberyard Developer Guide
Flow Graph Node Reference
ApplyConfiguration node
Applies AWS configuration to all managed clients.
Inputs
Port
Apply
Outputs
Port
Success
Error
Type
Any
Type
Any
String
SetConfigurationVariable node
Sets a configuration parameter value.
Description
Applies the current AWS configuration to all managed clients
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
Inputs
Port
Configure
Name
Value
Type
Any
String
String
Description
Sets the parameter value
Name of the parameter to set
Value to which the parameter will be set; may contain
$param-name$
substrings
Outputs
Port
Success
Error
Type
Any
String
ConfigureProxy node
Sets the proxy configuration used by all AWS clients.
Version 1.10
274
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
Lumberyard Developer Guide
Flow Graph Node Reference
Inputs
Port
Expand
Value
Outputs
Port
Success
Error
Inputs
Port
Configure
Host
Port
UserName
Password
Outputs
Port
Success
Error
Type
Any
String
Integer
String
String
Type
Any
String
GetConfigurationVariableValue node
Inserts configuration value parameters into a string.
Description
Sets the proxy configuration
Proxy host
Proxy port
Proxy user name
Proxy password
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
Type
Any
String
Type
Any
String
Version 1.10
275
Description
Expands parameter references
Value containing
$param-name$
substrings
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
Port
Value
Lumberyard Developer Guide
Flow Graph Node Reference
Type
String
SetDefaultRegion node
Sets (overrides) the region for all AWS clients in the current project.
Description
Value with
$param-name$ substring replaced by parameter values
Inputs
Port
Activate
Region
Type
Any
String
Description
Sets the region for all AWS clients in the current project
The region name to set as the default region for all AWS clients
Outputs
Port
Success
Error
Type
Any
String
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
Choose
Apply
if you want to apply the configuration change to all AWS clients immediately. If
Apply
is set to
false
, you must add an
ApplyConfiguration (p. 274) flow node to activate the changes.
Use Amazon Cognito to configure player identity with these flow graph nodes.
Topics
•
ConfigureAnonymousPlayer node (p. 276)
•
ConfigureAuthenticatedPlayer node (p. 277)
ConfigureAnonymousPlayer node
Creates an anonymous identity on the device in your AWS account.
Version 1.10
276
Lumberyard Developer Guide
Flow Graph Node Reference
Inputs
Port
Configure
Type
Any
Description
Configure your game to use Amazon Cognito for anonymous players
AWSAccountNumber
IdentityPoolID
String Your AWS account number. This is needed to access Amazon
Cognito.
String The unique ID of your Amazon Cognito identity pool. To create an identity pool ID, sign in to the AWS Management Console and use the Amazon Cognito console at https://console.aws.amazon.com/ cognito/ .
CachingFileLocationOverride If specified, causes the Amazon Cognito ID to be cached to the path specified instead of to
<HOME_DIR>
/.aws/.identities
.
Outputs
Port
Success
Error
CognitoIdentityID
Type Description
Any Activated upon a successful operation
String Activated upon an error being detected; the value of the port is the error message
String The unique ID of the user
The first time the player runs the game and this node is triggered, an anonymous ID is generated for the player. This ID is persisted locally, and future runs of the game use the same identity.
ConfigureAuthenticatedPlayer node
Creates an authenticated identity on the device in your AWS account.
Inputs
Port
Configure
AWSAccountNumber
IdentityPoolID
Type
Any
String
String
ProviderName String
Version 1.10
277
Description
Configure your game to use Amazon Cognito with the values specified.
Your AWS account number. This is needed for configuring Amazon Cognito.
The unique ID of your Amazon Cognito identity pool. To edit your identity pool ID, open the AWS
Management Console and choose
Cognito
.
Specifies the provider that authenticates the user
Lumberyard Developer Guide
Flow Graph Node Reference
Port
ProviderToken
Type
String
Description
Provider token with which to authenticate the user
Outputs
Port
Success
Error
CognitoIdentityID
Type
Any
String
String
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The unique ID of the user
The first time the player runs the game and this node is triggered, an authenticated ID is generated for the player. The same ID is returned any time the user logs in with the same account, even on a second device.
You can use these flow graph nodes to connect your game to Amazon DynamoDB.
Topics
•
•
•
•
•
•
•
•
AtomicAdd node
Add a number to an attribute in DynamoDB and return the number.
Inputs
Port
Add
Type
Any
Version 1.10
278
Description
Writes the val
specified in the
Value
port to
DynamoDB
Lumberyard Developer Guide
Flow Graph Node Reference
Port
TableName
TableKeyName
Key
Attribute
Value
Outputs
Port
Success
Error
NewValue
Type
String
String
String
String
Integer
Type
Any
String
String
Description
The name of the DynamoDB table to which to write
The key name used in the table
Specifies the key to which to write
Specfies the attribute to which to write
Specifes the value to write
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The value of the attribute after the addition.
This is an atomic operation. You do not need to create the attribute before you use it.
DeleteItem node
Deletes a record in DynamoDB.
Inputs
Port Type Description
DeleteItem Any Deletes the specified item from DynamoDB.
TableName String The name of the DynamoDB table from which to delete
KeyValue String Specifies the key to delete
Outputs
Port
Success
Error
Type
Any
String
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
Activated when matches were found to delete
Version 1.10
279
Lumberyard Developer Guide
Flow Graph Node Reference
Port Type
NoResults Any
Description
No matching results were found
GetItem node
Gets values from DynamoDB.
Inputs
Port
GetItem
TableName
TableKeyName
KeyValue
AttributeToReturn
Outputs
Port
Success
Error
DataOut
NumberOut
BoolOut
NoResults
PutItem node
Writes values to DynamoDB.
Type
Any
String
String
String
String
Any
Type
Any
String
String
String
String
Description
Retrieves the item specified from DynamoDB
The name of the DynamoDB table from which to read
The key name used in the table
Specifies the key to read
Specfies the attribute to read
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
String data that was read from DynamoDB
Number data that was read from DynamoDB
Boolean value that was read from DynamoDB
No matching results were found for the table, key, and attribute specified
Version 1.10
280
Lumberyard Developer Guide
Flow Graph Node Reference
Inputs
Port
PutItem
TableName
TableKeyName
KeyValue
AttributeToWrite
DataIn
DataType
KeyMustNotExist
Type
Any
String
String
String
String
String
String
Boolean
Outputs
Port
Success
Error
KeyAlreadyExists
Query node
Queries values in DynamoDB.
Type
Any
String
Any
Description
Writes the item specified to DynamoDB
The name of the DynamoDB table to which to write
The key name used in the table
Specifies the key to write
Specfies the attribute to write
The data to write
The data type that the data will be written as
When true, specifies that the key must not already exist; the default is true. Setting this to false allows you to overwrite an existing key in the table, including all of its existing attributes, and replace them with the new key and attribute values.
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The key already exists; no change was made
Version 1.10
281
Lumberyard Developer Guide
Flow Graph Node Reference
Inputs
Port
Query
TableName
TableKeyName
KeyValue
Type Description
Any Queries table data in DynamoDB
String The name of the DynamoDB table to query
String The name of the table key to query
String The value of the key to query
AttributeToCheck String The attribute to query
AttributeComparisonType String The comparison type to make against the attribute; the default is
EQUALS
. Other possible values are
GREATER_THAN
,
GREATER_THAN_OR_EQUALS
,
LESS_THAN
,
LESS_THAN_OR_EQUALS
.
AttributeComparisonValueString The value to compare against the attribute
AttributeComparisonValueType
AttributeComparisonValue
( string
, bool
, or number
); the default is string
Outputs
Port
Success
Error
MatchFound
NoMatch
Type
Any
String
Any
Any
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
A match was found
No match was found
ScanTable node
Scans for entries which pass a comparison test in DynamoDB.
Version 1.10
282
Lumberyard Developer Guide
Flow Graph Node Reference
Inputs
Port
Scan
Type Description
Any Scans for matches in DynamoDB table data using the specified attributes
String The name of the DynamoDB table to scan TableName
Attribute String The attribute to query for
AttributeComparisonType String The comparison type to make against the attribute; this defaults to
EQUALS
.
AttributeComparisonValueString The value to compare against the attribute
AttributeComparisonValueType
AttributeComparisonValue
( string
, bool
, or number
); the default is string
Outputs
Port Type Description
Success
Error
Any Activated upon a successful operation
String Activated upon an error being detected; the value of the port is the error message
MatchesFoundAny The number of matches found on a successful scan
UpdateItem node
Updates attribute values of an existing item in DynamoDB.
Inputs
Port
UpdateItem
TableName
TableKeyName
KeyValue
AttributeToWrite
DataIn
Type
Any
String
String
String
String
String
Version 1.10
283
Description
Updates an item in DynamoDB
The name of the DynamoDB table to use
The name of the key in the table
The value of the key to write
The attribute to write to
The data to write
Lumberyard Developer Guide
Flow Graph Node Reference
Port
DataType
KeyMustExist
AttributeMustExist
Type
String
Boolean
Boolean
Description
The data type to write the data as
True if the key specified must already exist in the table; the default is true.
True if the attribute must exist for the key specified; the default is true
Outputs
Port Type Description
Success Any Activated upon a successful operation
Error String Activated upon an error being detected; the value of the port is the error message
ConditionsFailed Key or attribute not found (either the
KeyMustExist
or
AttributeMustExist
condition failed)
GetStringSet node
Retrieves the members of a string set.
Inputs
Port
GetItem
TableName
TableKeyName
KeyValue
AttributeToWrite
Outputs
Port
Success
Error
DataOut
Type
Any
String
String
String
String
Description
Reads data from DynamoDB
The name of the DynamoDB table to use
The name of the key in the table
The value of the key to write
The attribute to write to
Type
Any
String
String
Version 1.10
284
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The data read from DynamoDB. The
DataOut
port fires once for each member of the set.
Lumberyard Developer Guide
Flow Graph Node Reference
The success port indicates that all members of the set have been output.
You can use this flow graph node to invoke AWS Lambda functions.
Invoke node
Inputs
Port
Invoke
Type Description
Any Invokes a Lambda function, optionally providing JSON data as arguments through the
Args
port. For more information, see AWS Lambda Invoke Request Syntax .
Args StringThe input data that will be sent to the Lambda function call as arguments in JSON format. For more information, see AWS Lambda Invoke Request Syntax .
Outputs
Port
Success
Error
Result
Type
Any
String
String
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The data that was output by the Lambda function if no error occured
You can use these flow graph nodes to download and upload files from the Amazon Simple Storage
Service (Amazon S3), and to generate a public URL that points to a specific location in Amazon S3.
Topics
•
•
•
GeneratePublicUrl node (p. 287)
DownloadFile node
Downloads a file from Amazon S3.
Version 1.10
285
Inputs
Port
DownloadFile
BucketName
KeyName
FileName
Outputs
Port
Success
Error
UploadFile node
Uploads a file to Amazon S3.
Type
Any
String
Type
Any
String
String
String
Lumberyard Developer Guide
Flow Graph Node Reference
Description
Reads file data from an Amazon S3 bucket
The name of the Amazon S3 bucket to use
The name of the file to download from Amazon
S3
The filename to use for the downloaded object
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
Inputs
Port
UploadFile
BucketName
KeyName
ContentType
Type
Any
String
String
String
FileName String
Version 1.10
286
Description
Uploads a file to an Amazon S3 bucket
The name of the Amazon S3 bucket to use
What to name the uploaded object on Amazon S3.
If this value is not updated on subsequent uses, the existing Amazon S3 object is overwritten.
The mime-content type to use for the uploaded object (for example, text/html
, video/mpeg
, video/avi
, or application/zip
). The type is stored in the Amazon S3 record. You can use this type to help identify or retrieve a specific type of data later. The default is application/octetstream
.
The name of the file to upload
Lumberyard Developer Guide
Flow Graph Node Reference
Outputs
Port
Success
Error
Type
Any
String
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
GeneratePublicUrl node
Generates a presigned URL that points to an Amazon S3 location that you specify.
Inputs
Port
PresignUrl
BucketName
KeyName
Type
Any
String
String
Http Request Method String
Description
Generates a presigned URL for the Amazon S3 location specified
The name of the Amazon S3 bucket to use
What to name the uploaded object on Amazon S3.
If this value is not updated on subsequent uses, the existing Amazon S3 object is overwritten.
The HTTP method against which to presign
(
DELETE
,
GET
,
POST
, or
PUT
)
Outputs
Port
Success
Error
Url
Type
Any
String
String
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The signed URL
You can use these flow graph nodes to process Amazon Simple Notification Service (Amazon SNS) messages.
Topics
•
•
•
CheckArnSubscribed node (p. 289)
•
SubscribeToTopic node (p. 289)
Version 1.10
287
Inputs
Port
Notify
Message
Subject
TopicARN
Outputs
Port
Success
ParseMessage node
Lumberyard Developer Guide
Flow Graph Node Reference
Inputs
Port
Parse
Message
Outputs
Port
Success
Error
Body
Subject
Type
Any
String
Type
Any
String
String
String
Notify node
Publishes messages to an Amazon SNS topic.
Description
Extract the subject and body text in JSON format from an Amazon SNS message
The JSON message to deserialize.
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The message body
The message subject
Type
Any
String
String
String
Description
Sends a notification to an Amazon SNS topic
The message to send
The subject of the message
The Amazon Resource Name for your Amazon SNS topic
Type
Any
Version 1.10
288
Description
Activated upon a successful operation
Lumberyard Developer Guide
Flow Graph Node Reference
Port
Error
Type
String
CheckArnSubscribed node
Checks if an ARN is subscribed to an Amazon SNS topic.
Description
Activated upon an error being detected; the value of the port is the error message
Inputs
Port
Check
TopicARN
Endpoint
Type
Any
String
String
Description
Checks if an ARN is subscribed to an Amazon SNS topic
The Amazon SNS topic ARN to check
The endpoint to check for subscription to the specified topic. The endpoint can be an email address, an Amazon SQS queue, or any other endpoint type supported by Amazon SNS.
Outputs
Port Type Description
Success Any Activated upon a successful operation
Error String Activated upon an error being detected; the value of the port is the error message
True
False
Any The ARN is subscribed to the Amazon SNS topic
Any The ARN is not subscribed to the Amazon SNS topic
SubscribeToTopic node
Subscribes to an Amazon SNS topic.
Inputs
Port
Subscribe
Type
Any
Version 1.10
289
Description
Subscribes to a topic to receive messages published to that topic. For more information, see
Subscribe to a Topic .
Lumberyard Developer Guide
Flow Graph Node Reference
Port
Protocol
TopicARN
Endpoint
Type
String
String
String
Description
The protocol of the endpoint to which to subscribe
The ARN of the Amazon SNS topic to which to subscribe
The address of the endpoint to subscribe (for example, an email address). For information on sending to HTTP or HTTPS, see Sending Amazon
SNS Messages to HTTP/HTTPS Endpoints .
Outputs
Port
Success
Error
SubscriptionArn
Type
Any
String
String
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The ARN of the created subscription
For more information on Amazon SNS, see the Amazon Simple Notification Service Developer Guide .
You can use these flow graph nodes to start polling AWS queues and to push messages to AWS queues.
Topics
•
•
PollAndNotify node
Inputs
Port
Start
QueueName
Type
Any
String
Description
Start polling an AWS queue
The name of an AWS queue that has already been created
Version 1.10
290
Lumberyard Developer Guide
Flow Graph Node Reference
Outputs
Port
Success
Error
OnMessageReceived
QueueArn
Type
Any
String
String
String
Push node
Pushes a message to an AWS queue
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The most recent message on the stack
The ARN (Amazon Resource Name) of the queue
Inputs
Port
Push
QueueName
Message
Type
Any
String
String
Description
Pushes a message to an AWS queue
The name of an AWS queue that has already been created
The message to send
Outputs
Port
Success
Error
Type
Any
String
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
Static Data is a Lumberyard system for managing game data that changes less frequently through monitored Amazon S3 buckets. You can use these flow graph nodes to update or query your buckets and/or monitor them at regular intervals for changes.
Topics
•
Add Monitored Bucket node (p. 292)
•
•
Load Static Data node (p. 293)
•
Remove Monitored Bucket node (p. 293)
•
Version 1.10
291
Lumberyard Developer Guide
Flow Graph Node Reference
•
Set Update Frequency node (p. 294)
Add Monitored Bucket node
Adds an Amazon S3 bucket to monitor.
Inputs
Port
AddBucket
BucketName
Type
Void
String
Outputs
Port
Success
Error
Finished
Type
Any
String
String
Get Static Data node
Retrieves a field from a static data definition.
Description
Adds a bucket to watch for updates
The name of the Amazon S3 bucket to watch
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The bucket was added
Inputs
Port
Get
StaticDataType
StaticDataId
StaticDataField
ActivateOnUpdate
Type
Void
String
String
String
Void
Version 1.10
292
Description
Retrieves a value from static data
The type of the static data to retrieve
The identifier for the static data definition in the table
The field name of the data to retrieve
Fire the node again the next time an update of the data takes place
Lumberyard Developer Guide
Flow Graph Node Reference
Outputs
Port
Success
Error
StringOut
NumberOut
BoolOut
FloatOut
Type
Any
String
String
Integer
Boolean
Integer
Load Static Data node
Attempts to load static data of the type specified.
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The output of a string field
The output of a numeric field
The output of a Boolean
The output of a floating point numeric field
Inputs
Port
Load
StaticDataType
Type
Any
String
Description
Load a type of static data
The type of static data to load
Outputs
Port
Success
Error
Finished
Type
Any
String
String
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
Finished attempting to load
Remove Monitored Bucket node
Removes a bucket name from the list of monitored buckets.
Version 1.10
293
Lumberyard Developer Guide
Flow Graph Node Reference
Inputs
Port
Remove
BucketName
Outputs
Port
Success
Error
Finished
Type
Any
String
Type
Any
String
String
Description
Removes a bucket from the list of monitored buckets
The name of the bucket to remove
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
Finished removing the bucket
Request Bucket node
Requests an update of a specific bucket, or of all monitored buckets.
Inputs
Port
RequestBucket
BucketName
Type
Any
String
Description
Requests an update of a specific bucket or of all monitored buckets
The name of the bucket for which to request an update. To request updates for all buckets, leave this value blank.
Outputs
Port
Success
Error
Finished
Type
Any
String
String
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
Finished sending the request
Set Update Frequency node
Sets or clears a recurring timer to poll monitored buckets.
Version 1.10
294
Lumberyard Developer Guide
Software Engineering Guide
Inputs
Port
SetTimer
TimerValue
Type
Void
Integer
Description
Sets a recurring timer to the value specified in
TimerValue
The time interval at which to poll. Possible values are from 0 to 100. A value of 0 clears the timer; 0 is the default.
Outputs
Port
Success
Error
Set
Type
Any
String
String
Description
Activated upon a successful operation
Activated upon an error being detected; the value of the port is the error message
The timer has been set
This section provides in-depth information for Cloud Canvas Resource Manager and the cloud gem framework.
Topics
•
Resource Manager in Depth (p. 295)
•
The effective use of Cloud Canvas Resource Manager is key to the success of any cloud-connected game project. This section provides in-depth information for software engineers.
For information on permissions in Resource Manager, see Understanding the Resource Manager Security
.
Topics
•
Understanding Resource Status Descriptions (p. 296)
•
Editing Resource Manager Files (p. 296)
•
Working with JSON Files (p. 297)
•
Viewing the Cloud Canvas Progress Log (p. 298)
•
Working with Resource Groups (p. 299)
•
•
Permissions Metadata for Resource Definitions (p. 310)
Version 1.10
295
Lumberyard Developer Guide
Resource Manager in Depth
•
Importing Resource Definitions into Cloud Canvas (p. 312)
•
•
•
Resource Manager Resource Group Parameters (p. 320)
•
The status of AWS resources is displayed in the
Cloud Canvas Resource Manager
in places such as the progress log. The following list provides descriptions of common resource status codes. To see the reason for the current status, you can pause your mouse on the status text in the resource manager.
Create in progress
– The resource is in the process of being created in AWS.
Create complete
– The resource has been successfully created in AWS.
Create failed
– The resource could not be created in AWS.
Update in progress
– The resource is in the process of being updated in AWS.
Update complete
– The resource was successfully updated in AWS.
Update failed
– The resource could not be updated in AWS.
Delete in progress
– The resource is in the process of being deleted in AWS.
Delete complete
– The resource has been deleted in AWS.
Rollback in progress
– An operation has failed and AWS CloudFormation is attempting to restore the resource to its previous state.
Rollback failed
– A rollback has failed. The AWS resources in a CloudFormation stack that have this status are in an inconsistent state. You may have to delete and recreate the stack.
The navigation pane in the
Cloud Canvas Resource Manager
dialog contains a number of nodes that
The child nodes of template files each represent one section of the parent node template file. These child nodes can help you locate and edit the resource definition sections of the parent node template file.
Using the Internal Editor
When you select a text file node in the navigation pane, the file content and text editing options are shown in the detail pane of
Cloud Canvas Resource Manager
. You can use the detail pane to view and edit the contents of the file. Use the
Edit
,
Search
menu item to search for text, and the
Previous
and
Next
buttons to navigate from one match to the next. After you have modified a file, you can save it by clicking
Save
in the toolbar or by choosing
File
,
Save
.
Note
The changes that you make in the template file child nodes are always saved to the parent node template file.
Using an External Editor
You can use an external script editor instead of the
Cloud Canvas Resource Manager
to edit files. You can specify which editor to use in Lumberyard Editor.
Version 1.10
296
Lumberyard Developer Guide
Resource Manager in Depth
To specify an external script editor
• In Lumberyard Editor, click
File
,
Global Preferences
,
Editor Settings
,
General Settings
,
Files
,
External Editors
,
Scripts Editor
.
To open a file in an external script editor
• Right-click the file in the navigation pane and choose
Open in script editor
:
To copy the path of the template file to the clipboard, right-click the file in the navigation pane and choose
Copy path to clipboard
.
Notes
Note the following:
• Opening a child node of a template file in a script editor opens the full (parent) file for editing.
• If your project files are under source control, Lumberyard prompts you to check out files before they can be edited. The source control icon on the toolbar dynamically displays the status of a selected file in source control.
• If the contents of the file change on disk while there are unsaved changes in the editor, Lumberyard prompts you to load the updated contents from disk and replace the modified contents in the editor.
Some of the nodes in the
Cloud Canvas Resource Manager
navigation pane represent JSON template or settings files for your project. The content of these files is described in detail in Resource Definitions .
When you select one of these nodes in the navigation pane, the detail pane shows the contents of that file. You can edit the file directly in the resource manager or use an external editor. For more information, see
Editing Resource Manager Files (p. 296) .
In the navigation pane, some template file nodes have child nodes. Each of the child nodes represents one section of its parent node template file. These child nodes make it easier to find and edit the corresponding sections of the parent node template file. Any changes that you make in a child node are always saved in the corresponding section of the parent template file.
The following template is found in each resource group under the
Resource Groups
node: resource-template.json
Each resource group has a
resource-template.json
node and a
lambda-function-code
child node.
The resource-template.json
file defines the group’s resources. For more information, see Resource
Definitions . In the navigation pane, each of the nodes under
resource-template.json
represents one of the resources defined in a section of the resource-template.json
file.
Version 1.10
297
Lumberyard Developer Guide
Resource Manager in Depth
The following templates are found under the
Administration (advanced)
node: project-settings.json
The project-settings.json
file contains project configuration data. For more information, see Resource
Definitions .
project-template.json
The project-template.json
file defines the resources used by
Cloud Canvas Resource Manager
. For more information, see Resource Definitions .
deployment-template.json
The deployment-template.json
file defines the AWS CloudFormation stack resources for each of the projects resource groups. For more information, see Resource Definitions .
deployment-access-template.json
The deployment-access-template.json
file defines the AWS CloudFormation stack resources that control access to each deployment’s resources. For more information, see Resource Definitions and
Controlling Access to Resources (p. 420)
.
user-settings.json
The user-settings.json
file contains user specific settings. For more information, see Resource
Definitions .
The
Cloud Canvas Resource Manager Progress log
shows the progress of AWS CloudFormation stack updates. During the update, the progress log expands from the bottom of the detail pane to display the progress of the update. You can adjust the amount of space the log uses by dragging the divider line between the panes.
Version 1.10
298
Lumberyard Developer Guide
Resource Manager in Depth
To hide the progress log, drag the divider downward.
Resource groups define the AWS resources that cloud-connected game features such as high score tables require. You define the resource groups locally and then upload them to AWS, where the features you specify are created in the cloud.
You can use the
Cloud Canvas Resource Manager
to manage resource groups collectively or individually.
You can create a resource group locally, specify the AWS resources that you want the resource group to have, and then upload the resource group definition to have it created in AWS. This document shows you how to use
Cloud Canvas Resource Manager
to perform these and other resource group-related tasks.
Managing Resource Groups
To see the status of the resource groups that belong to your project's current deployment, click
Resource
Groups
in the
Cloud Canvas configuration
navigation pane . Note the following:
• If you select
Resource Groups
and no AWS profile is configured, Lumberyard prompts you to provide one. A profile is required for Lumberyard to display the status of your project’s resources. For more
information, see Managing Cloud Canvas Profiles (p. 200)
.
• If you select
Resource Groups
and deployments exist but no deployment is active, Lumberyard prompts you to select one. For more information, see
Making a Cloud Canvas Deployment
The
Resource Groups
detail pane lists the resource groups in your current deployment:
The
Resource Groups
detail pane has the following options:
Upload all resources
Starts the process of modifying your resources in AWS as needed to match all the definitions in all of your local resource groups. As the update proceeds, resource groups with the
Pending
status of
Create
change to the
Status
of
Create complete
. The update might take a few minutes.
Version 1.10
299
Lumberyard Developer Guide
Resource Manager in Depth
Note the following:
• If you have not yet initialized your Lumberyard project with an AWS account for the resources that you want to upload, Lumberyard prompts you to do so. To prepare your Lumberyard project for use with AWS, you must be an administrator of the AWS account that you use. For more
information, see Initializing Cloud Canvas Resource Manager (p. 408) .
• After you have initialized the project, Lumberyard prompts you to create a deployment for it. A deployment creates all the AWS resources that are specified in your resource group definition.
For more information, see
Version 1.10
300
Lumberyard Developer Guide
Resource Manager in Depth
Add resource group
Adds a new resource group definition to your Lumberyard project. A resource group definition represents a single game feature like a high score system. The definition specifies the AWS resources that the feature will use.
Clicking
Add resource group
opens the
New resource group
dialog:
Provide the following information:
•
Resource group name
– The name of the resource group. The name must be alphanumeric.
Lumberyard uses this name to create an AWS CloudFormation stack resource definition in the deployment-template.json
file.
•
Example resources
– (Optional) Choose to include example resources in the resource group.
You can study the examples to see how resources are defined in a resource group, or modify the examples to turn them into a feature for your project.
Resource group status
Shows the status of the AWS CloudFormation stack of each resource group in the active deployment.
Resource group
shows the resource group name. For descriptions of the remaining fields in this
table, see Stack Resources Table (p. 411) in the
Working with Project Stacks (p. 409)
section.
Progress log
Shows the progress of AWS CloudFormation stack updates. For more information, see
Cloud Canvas Progress Log (p. 298) .
Managing Individual Resource Groups
Each child node of
Resource Groups
represents a resource group in your Lumberyard project. When you select one of these resource groups, the detail pane shows the status of the resource group.
Version 1.10
301
Lumberyard Developer Guide
Resource Manager in Depth
Adding Resources to a New Resource Group
When you create a resource group, the group does not yet have any AWS resource definitions. Use the
Add resource
option to add one:
Importing Resources
You can also click
Import resource
to import an AWS resource that already exists in your AWS account.
For more information, see
Importing Resource Definitions into Cloud Canvas (p. 312) .
Creating Resources in AWS
The resource definitions that you add are created locally and only describe the AWS resources that you want to use. The resources themselves are not created in AWS until you click
Create resources
:
Version 1.10
302
Lumberyard Developer Guide
Resource Manager in Depth
Individual Resource Group Status
You can use a resource group's status pane to manage the resource group.
In addition to
Add resource
and
Import resource
, the status pane for a resource group has the following options:
Upload Lambda code
Use this option to upload Lambda function code without updating the entire project stack.
Upload resources
After you have created one or more resource definitions, you click
Upload resources
to start the process of creating the resources in AWS. Resource creation follows the local resource definitions that you created with the
Add resource
option.
Version 1.10
303
Lumberyard Developer Guide
Resource Manager in Depth
As the update proceeds, the resources with the
Pending
status of
Create
change to the
Status
of
Create complete
.
Remove resource group
Click
Remove resource group
to remove the selected resource group from your local configuration.
To delete the actual resources from AWS, use the
Delete resources
option as described in the section that follows.
Note
The remove resource operation does not remove the resource group's configuration data from the local disk. As long as that data exists on disk, you can restore the resource group by adding a new resource group with the same name.
Delete resources
The
Delete resources
option appears after you have removed a resource group from your local configuration (for example, by clicking
Remove resource group
) when the resources defined by the resource group still exist in AWS.
Version 1.10
304
Lumberyard Developer Guide
Resource Manager in Depth
When you click
Delete resources
, Lumberyard prompts you to confirm the deletion of resources in
AWS for the deployment that is currently active in Lumberyard Editor. You must select the
It is OK that this will permanently DELETE resources
check box before you can click
Yes
.
After you click
Yes
, the deletion operation might take several minutes to complete.
Stack resources
The
Stack resources
table shows the status of each of the AWS resources that you defined for the resource group. For descriptions of the fields in this table, see
Stack Resources Table (p. 411) in the
Working with Project Stacks (p. 409)
section.
resource-template.json
For information about this node, see Working with JSON Files (p. 297)
.
lambda-function-code
The
lambda-function-code
node and its child nodes correspond to the lambda-function-code
directory in your project. The lambda-function-code
directory contains the code that implements the AWS
Lambda function resources that are defined by your resource group. For more information, see lambdafunction-code Directory
Also see related information for the project-code (p. 305)
node.
project-code
This node is located at the bottom of the
Administration (advanced)
section in the resource manager navigation tree. The project-code
directory contains the code that implements the AWS Lambda
Version 1.10
305
Lumberyard Developer Guide
Resource Manager in Depth function resources that
Cloud Canvas Resource Manager
uses. For more information, see Resource
Definitions . The
project-code
node contains file and directory child nodes. Click a file node to see or edit
its contents in the detail pane. For more information, see Editing Resource Manager Files (p. 296) .
Resource definitions for your game project are AWS CloudFormation template files that determine the resources (for example, DynamoDB databases, Lambda functions, and access control information) that will be created in AWS for the game. Game code uses AWS resources and expect those resources to exist and to be configured in a specific way. The resource definitions determine this architecture and configuration.
Game Resource Definitions
A description of the resources required by the game is stored in files under the dev\
{game}
\AWS
directory, where dev
is the Lumberyard installation
\dev
subdirectory and
{game}
is the directory identified by the sys_game_folder
property in the \ dev\bootstrap.cfg
file. For example, if your game is the Samples
Project, your resource definition path might be
C:\lumberyard\dev\SamplesProject\AWS
. These files should be checked into the project's source control system along with your other game code and data.
The default
{game}
\AWS
directory contents are created by the lmbr_aws
command.
In addition, some user-specific configuration data is kept in the dev\Cache\
{game}
\
{platform}
\user\AWS directory. The contents of this directory should not be checked into the project's source control system.
The following shows the contents of these
AWS
directories.
dev\
{game}
\AWS\
resource-group\
{resource-group-name}
\
lambda-function-code\
(Lambda function Code)
resource-template.json
local-project-settings.json
dev\Cache\
{game}
\
{platform}
\user\AWS\
user-settings.json
The
.json
files are described in the following sections.
resource-group\
{resource-group}
Directory
The AWS resources used by the game are organized into separate resource groups. The resourcegroup
directory contains these in individual
{resource-group}
subdirectories. Each
{resource-group}
subdirectory is typically named after your game project and can contain a lambda-function-code directory and a resource-template.json
file.
The lambda-function-code Directory
The lambda-function-code
subdirectory is present when a resource template defines Lambda function resources. This directory can contain source files that implement those functions. Lumberyard uploads the code from this directory when using the template to update the AWS CloudFormation stack.
Note
Use of the lambda-function-code
directory is deprecated. For more information, see Lambda
.
Version 1.10
306
Lumberyard Developer Guide
Resource Manager in Depth resource-template.json
A resource-template.json
file is an AWS CloudFormation template that defines the AWS resources associated with each resource group. You can specify any AWS resource type supported by AWS
CloudFormation in your resource-template.json
file. For a list of the available resource types, see the
AWS CloudFormation AWS Resource Types Reference .
To determine the resource group stacks to include in a deployment, Lumberyard reads the resourcetemplate.json
files in
AWS\resource-group
subdirectories and in the
AWS
subdirectories of enabled cloud gems. Following are two examples.
\dev\CloudGemSamples\AWS\resource-group\CloudGemAWSBehavior\resource-template.json
\dev\Gems\CloudGemMessageOfTheDay\AWS\resource-template.json
local-project-settings.json
The dev\
<project name>
\local-project-settings.json
file contains a
ProjectStackId
identifier that points to AWS and lists the resource groups that have been enabled for the project. The following example shows the format of the local-project-settings.json
file for the Cloud Gem Samples project:
{
"ProjectStackId": "arn:aws:cloudformation:
{aws-region}
:
{aws-access-id}
:stack/
CloudGemSamples/
{project-name}
/
{uuid}
",
"EnabledResourceGroups": [
"ProjectDefinedGroup",
"CloudGemMessageOfTheDay",
"CloudGemPlayerAccount",
"CloudGemDynamicContent",
"CloudGemLeaderboard"
]
}
Note
As of Lumberyard 1.8, the project-settings.json
file is stored in the project's
Bucket (p. 317) . The bucket is defined by the project's AWS CloudFormation stack template.
ProjectStackId Property
The
ProjectStackId
property identifies the AWS CloudFormation stack for the project. This stack contains the resources used by Cloud Canvas to manage your Lumberyard project. Initially, the
ProjectStackId
property is not present in the local-project-settings.json
file. After the project stack is created, the
ProjectStackId
property is written to the file and is the project's AWS CloudFormation stack ID .
The
ProjectStackId
property is set by the
command. If for some reason you want to associate the project with an existing project stack, you can use the AWS Management Console to look up the stack's ARN and paste it into the local-project-settings.json
file (navigate to AWS
CloudFormation, select the stack, select
Overview
, and then copy the value of the
Stack Id
property).
user-settings.json
The user-settings.json
file contains user-specific configuration data.
File Location
The user-settings.json
file is found at dev\Cache\
{game}
\
{platform}
\user\AWS\user-settings.json
.
It is not in the dev\
{game}
\AWS
directory along with the other files described in this section because it should not be checked into the project's source control system.
Version 1.10
307
Lumberyard Developer Guide
Resource Manager in Depth
Project Template Files
Cloud Canvas project template files are AWS CloudFormation templates that define resources, stacks, and deployment permissions for a project. Following are the project template files:
• project-template.json
• deployment-template.json
• deployment-access-template.json
The content of each of these template files can be supplemented with a corresponding
*-extensions.json
file. Starting in Lumberyard 1.10, these files are located in the
\Gems
\CloudGemFramework\v
N
\ResourceManager\resource_manager\templates
directory, where
N
represents a
Cloud Gem framework version number.
project-template.json
The project-template.json
file is an AWS CloudFormation template that defines project-wide resources that support the Cloud Canvas resource management system. For information about Cloud Canvas
Resource Manager, see
Understanding Cloud Canvas Resource Manager (p. 184) . For security-related
information, see
Understanding the Resource Manager Security System (p. 420) .
deployment-template.json
In versions of Lumberyard prior to 1.10, the project's copy of the deployment-template.json
file contained stack definitions for each of the project's resource groups. These resources are now inserted into the base template before it is passed to AWS CloudFormation. To determine the resource group stacks to include, Lumberyard reads the resource-template.json
files in
AWS\resource-group subdirectories and in the
AWS
subdirectories of enabled gems.
deployment-access-template.json
The deployment-access-template.json
file is an AWS CloudFormation Template that defines the resources used to secure a deployment. For information about Cloud Canvas Resource Manager,
see Understanding Cloud Canvas Resource Manager (p. 184)
. For security-related information, see
Understanding the Resource Manager Security System (p. 420)
.
Parameters
The deployment access stack defines parameters that identify the deployment and other resources that are needed to set up security for the deployment. A value for each of these parameters is provided by
Cloud Canvas when a deployment is created.
Resources
This section describes some of the key resources that are defined in the example deployment-accesstemplate.json
file.
Player
The
Player
resource describes the IAM role that determines the access granted to the player.
For example, for the game to invoke a Lambda function, the player must be allowed the lambda:InvokeFunction
action on the Lambda function resource.
The role's policies are determined by the
PlayerAccess
metadata elements found on resources in the project's resource templates (see
resource-template.json (p. 307)
). The role's policies are updated
by the
PlayerAccess
custom resources that appear in the
deployment-access-template.json (p. 308)
and in the
resource-template.json (p. 307)
PlayerAccessIdentityPool
Amazon Cognito identity pool resource allows players to assume this role.
Version 1.10
308
Lumberyard Developer Guide
Resource Manager in Depth
For more information, see
PlayerAccessIdentityPool (p. 309)
and
PlayerLoginRole
The
PlayerLoginRole
resources describes the IAM role that is temporarily assumed by the player as part of the login process.
For more information, see
Controlling Access to Resources (p. 420)
.
PlayerLoginIdentityPool
The
PlayerLoginIdentityPool
resource describes the Amazon Cognito identity pool that provides the player with a temporary identity during the login process.
For more information, see
Controlling Access to Resources (p. 420)
.
PlayerAccessIdentityPool
The
PlayerAccessIdentityPool
resource describes the Amazon Cognito identity pool that provides the player with a temporary identity during the login process.
For more information, see
Controlling Access to Resources (p. 420)
.
Template Extension Files
Starting in Lumberyard 1.10, you can use the following extension files to add resources to the project templates:
• deployment-access-template-extensions.json
• deployment-template-extensions.json
• project-template-extensions.json
You can use the extension files to define new outputs, metadata, and resources. The addition of template parameters is not supported.
To create extension files, you can use the lmbr_aws
project create-extension-template (p. 447)
command. To create a template file of a particular type, use the corresponding argument, as the following examples show.
• To create a project-template-extensions.json
file, type: lmbr-aws project create-extension-template --project
• To create a deployment-template-extensions.json
file, type: lmbr-aws project create-extension-template --deployment
• To create a deployment-access-template-extensions.json
file, type: lmbr-aws project create-extension-template --deployment-access
In the base (nonextension) template files, the
Custom::AccessControl
resource
DependsOn
property includes all the resources defined in the extension files if the
DependsOn
property does not specify
AccessControl
.
Version 1.10
309
Lumberyard Developer Guide
Resource Manager in Depth
Code Directories
The location and naming of code directories has changed in Lumberyard 1.10. For more information, see
Cloud Gem Framework and Resource Manager Versioning (p. 403)
.
Lambda Code Directories
Starting in Lumberyard 1.10, we recommend that you put your Lambda code in
AWS\lambda-code
\
<lambda-name>
directories (for example, dev\Gems\CloudGemPlayerAccount\AWS\lambda-code
) and your shared code in a common-code
directory (for example, dev\Gems\CloudGemPlayerAccount\AWS\commoncode
).
In versions of Lumberyard prior to 1.10, the code for a resource group's Lambda functions was kept in an
AWS\lambda-function-code
directory. As of Lumberyard 1.10, the use of
AWS\lambda-function-code and
AWS
\<lambda-name>
-lambda-code
directories is no longer recommended. Support for them will be removed in a future release. Instead, we recommend that you put your Lambda code in
AWS\lambda-code
\
<lambda-name>
directories.
In addition, the use of the shared-lambda-code
directory is no longer recommended. Support for it will also be removed in a future release. Instead, use the more flexible common-code
directory. For more information, see
. For information about upgrading your projects and cloud gems to version 1.0.0 of the Cloud Gem framework, see
Updating Projects and Cloud Gems to Version
1.0.0 of the Cloud Gem Framework (p. 405)
.
The project-code Directory
The dev\Gems\CloudGemFramework\v
N
\AWS\project-code
subdirectory contains the source code for the AWS CloudFormation Custom Resource handler that is used in the project's AWS CloudFormation
templates. For information about custom resources, see Custom Resources (p. 320)
.
It also contains the code that implements the token exchange step of the player login process. For more information, see
Controlling Access to Resources (p. 420) .
To determine what permissions should go into a policy, the
Custom::CloudGemFramework::AccessControl
resource looks for Cloud Canvas permissions metadata on resource definitions in resource group stacks. In the following example, the metadata on the
Messages resource gives the
SayHello
AWS Lambda function permission to put items into a Amazon DynamoDB table. The metadata on the
SayHello
resource gives players permission to invoke the
SayHello
Lambda function.
...
"
Messages
": {
"Type": "AWS::DynamoDB::Table",
"Properties": {
"AttributeDefinitions": [
{
"AttributeName": "PlayerId",
"AttributeType": "S"
}
],
"KeySchema": [
{
"AttributeName": "PlayerId",
"KeyType": "HASH"
}
],
"ProvisionedThroughput": {
"ReadCapacityUnits": { "Ref": "ReadCapacityUnits" },
"WriteCapacityUnits": { "Ref": "WriteCapacityUnits" }
Version 1.10
310
Lumberyard Developer Guide
Resource Manager in Depth
}
},
"Metadata": {
"CloudCanvas": {
"Permissions": [
{
"AbstractRole": "
SayHello
",
"Action": "
dynamodb:PutItem
"
}
]
}
}
},
"
SayHello
": {
"Type": "
AWS::Lambda::Function
",
"Properties": {
"Description": "Example of a function called by the game to write data into a
DynamoDB table.",
"Handler": "main.say_hello",
"Role": { "Fn::GetAtt": [ "SayHelloConfiguration", "Role" ] },
"Runtime": { "Fn::GetAtt": [ "SayHelloConfiguration", "Runtime" ] },
"Code": {
"S3Bucket": { "Fn::GetAtt": [ "SayHelloConfiguration",
"ConfigurationBucket" ] },
"S3Key": { "Fn::GetAtt": [ "SayHelloConfiguration", "ConfigurationKey" ] }
}
},
"Metadata": {
"CloudCanvas": {
"Permissions": [
{
"AbstractRole": "
Player
",
"Action": "lambda:InvokeFunction"
}
]
}
}
},
...
You can use the lmbr_aws
command line tool to manage permissions metadata on the resource definitions in a resource group's resource-template.json
file. For more information, see
.
Properties
•
Each Cloud Canvas
Permission
metadata object can have the following properties.
Property Description
AbstractRole
Required string or list of strings. Identifies the role whose policy will reflect the
permission. For more information, see Role Mapping Metadata (p. 425)
.
Action
Required string or list of strings. Identifies the actions to be placed in the policy. This is used as the Action property of a Statement in the policy. See AWS Service Actions and
Condition Context Keys for Use in IAM Policies for a list of actions supported by IAM.
Optional string or list of strings. Provides values that are appended to the ARN in the Resource property of a statement in the policy. There is one
Resource
property
Version 1.10
311
Lumberyard Developer Guide
Resource Manager in Depth
Property Description
value for each suffix listed. If no suffixes are listed, the
Resource
property value is the resource ARN with no suffix.
See Also
For an overview of security in Cloud Canvas Resource Manager, see Understanding the Resource Manager
You can use the Cloud Canvas resource importer to add definitions of existing AWS resources to a
Cloud Canvas resource group. You can add resources by using the Cloud Canvas Resource Manager in
Lumberyard Editor or at a command line prompt.
Importing Resources using Lumberyard Editor
In Lumberyard Editor, you can import a resource by specifying an Amazon Resource Name (ARN) or by choosing from a list.
To import a resource by using an ARN
1. From the Lumberyard Editor top menu, choose
AWS
,
Cloud Canvas
,
Resource Manager
.
2. In the navigation pane, select a resource group.
3. In the detail window, click
Import resource
,
Import using ARN
. You can also open the context
(right-click) menu for the resource in the navigation pane and choose
Import resource
,
Import using ARN
.
4. In the
Import using ARN
dialog box, provide the ARN and name of the resource that you are going to import. Both are required.
After you have provided both items of information, the
Import
button is enabled.
5.
Import
.
To import a resource by choosing from a list
1. From the Lumberyard Editor top menu, choose
AWS
,
Cloud Canvas
,
Resource Manager
.
2. In the navigation pane, select a resource group.
3. In the detail window, choose
Import resource
,
Import using ARN
. You can also open the context
(right-click) menu for the resource in the navigation pane and choose
Import resource
,
Import using ARN
.
Version 1.10
312
Lumberyard Developer Guide
Resource Manager in Depth
4. In the
Import from list
dialog box, choose the AWS Region of the resource for
Region
. The default value is the region of the project stack if it exists. Resources start loading in the list as soon as you choose a region that has importable resources.
5. You can use the AWS service selector to filter the resources by service, and then use the
Search
box to filter resources by name.
6. Select the check box to the left of each resource that you want to import.
7.
Configure
.
8. In the
Configuration
dialog box, provide a reference name for each resource, or accept the default.
The default name is the original name of the resource on AWS.
9. To delete a selected resource from the list, open the context (right-click) menu for the resource and choose
Delete
.
Version 1.10
313
Lumberyard Developer Guide
Resource Manager in Depth
10. When you are ready, click
Import
. A progress bar displays. An
Import Error
message informs you of any errors that occur.
11. Click
X
to close the
Import from list dialog
box. The resources that you imported are listed in the details pane of Cloud Canvas Resource Manager.
Importing Resource Definitions Using the Command Line
To list and import resources using the Cloud Canvas command line, see
resource-importer listimportable-resources (p. 452)
and
resource-importer import-resource (p. 451)
.
Understanding Resource Definitions
When you use the Cloud Canvas resource importer to import the definition of a resource, it is important to understand that you are importing the resource's definition, not the resource itself. For example, suppose you use the AWS console to create a high score table in DynamoDB called Table A. You create a game client that uploads scores, and send out the client to your players. Table A begins to populate with data from the users who play your game.
You then decide to use Cloud Canvas to manage your resources and deployments. Using the Cloud
Canvas Resource Manager, you import Table A because it has the exact configuration values that you want, and it has worked well for your use cases.
When you create a deployment with the imported resource, the deployment contains Table B, which is a new table with Table A's structure but not its data. Table B is managed by Cloud Canvas and has the same behavior as Table A. However, Table B is not a reference to Table A, and it does not have Table A's data or history. Keep this distinction in mind when you import resource definitions.
Automatically Imported Resource Definitions
Some of the existing resources that you select might be related to other resources. For example, Lambda functions can respond to events from the selected triggers. You can use event notifications from an
Amazon S3 bucket to send alerts or trigger workflows. Cloud Canvas imports the related resources for you automatically.
Cloud Canvas uses the following naming conventions for automatically imported resource definitions.
Version 1.10
314
Lumberyard Developer Guide
Resource Manager in Depth
Source Naming Convention Example Name of Imported
Resource
LambdaFunctionAutoAddedtable0
DynamoDB table, Lambda function, Amazon SNS topic,
Amazon SQS queue
<resource_name>
+
+ "AutoAdded"
<resource_type>
+
<counter>
Lambda function configuration resource??
<lambda_function_name>
"Configuration"
+
Lambda function policy resource
<lambda_function_name>
+
"Permission"
DynamoDB table Lambda function event source
<DynamoDB_table_name>
+
"EventSource"
LambdaFunctionConfiguration
LambdaFunctionPermission
DynamoTableEventSource
Resources Supported for Import
The following sections list the resource attributes and related resources that Cloud Canvas imports for each supported AWS service.
Dynamo DB Tables
For DynamoDB tables, Cloud Canvas imports the following resource attributes:
•
AttributeDefinitions
•
GlobalSecondaryIndexes
•
KeySchema
•
LocalSecondaryIndexes
•
ProvisionedThroughput
•
StreamSpecification
Amazon S3 Buckets
For Amazon S3 buckets, Cloud Canvas imports the following resource attributes:
•
CorsConfiguration
•
LifecycleConfiguration
•
NotificationConfiguration
•
Tags
•
VersioningConfiguration
•
WebsiteConfiguration
For Amazon S3 buckets, Cloud Canvas also imports the following related resources:
• Lambda functions
• Amazon SQS queues
• Amazon SNS topics
Lambda Functions
For Lambda functions, Cloud Canvas imports the following resource attributes:
Version 1.10
315
Lumberyard Developer Guide
Resource Manager in Depth
•
Code
•
Description
•
Handler
•
MemorySize
•
Role
•
Runtime
•
Timeout
•
VpcConfig
For Lambda functions, Cloud Canvas also imports the following related resources:
• Lambda function configurations
• Lambda function permissions
• DynamoDB tables
• Event source mappings
Amazon SNS Topics
For Amazon SNS topics, Cloud Canvas imports the following resource attributes:
•
DisplayName
•
Subscription
For Amazon SNS topics, Cloud Canvas also imports any Lambda functions that are related resources.
SQS Queues
For SQS queues, Cloud Canvas imports the following resource attributes:
•
DelaySeconds
•
MaximumMessageSize
•
MessageRetentionPeriod
•
ReceiveMessageWaitTimeSeconds
•
RedrivePolicy
•
VisibilityTimeout
You implement deployments using AWS CloudFormation stacks . You create and manage the stacks using tools provided by Lumberyard.
A project may define any number of deployments, up to the limits imposed by AWS CloudFormation
(for more information, see AWS CloudFormation Limits ). Each deployment contains a completely independent set of the resources that the game requires. For example, you can have separate development, test, and release deployments so that your development and test teams can work independently of the deployment used for the released version of the game.
An AWS account that hosts a Lumberyard project contains the following resources:
•
{project}
– An AWS CloudFormation stack that acts as a container for all the project's deployments.
•
{project}
-
Configuration
– An S3 bucket used to store configuration data.
Version 1.10
316
Lumberyard Developer Guide
Resource Manager in Depth
•
{project}
-
ProjectResourceHandler
– A Lambda function that implements the handler for the custom
resources used in the templates. See Custom Resources (p. 320) .
•
{project}
-
ProjectResourceHandlerExecution
– An IAM role that grants the permissions used by the
ProjectResourceHandler
Lambda function when it is executing.
•
{project}
-
PlayerAccessTokenExchange
– A Lambda function that implements the token exchange
•
{project}
-
PlayerAccessTokenExchangeExecution
– An IAM role that grants the permissions used by the
PlayerAccessTokenExchange
Lambda function when it runs.
•
{project}
-
{deployment}
– AWS CloudFormation stacks for each of the project's deployments.
•
{project}
-
{deployment}
Access
– AWS CloudFormation stacks that control access to each of the project's deployments.
•
{project}
-
{deployment}
Access-PlayerAccessIdentityPool
– An Amazon Cognito identity pool used
for player identity. For more information, see Controlling Access to Resources (p. 420) .
•
{project}
-
{deployment}
Access-PlayerLoginIdentityPool
– An Amazon Cognito identity pool that provides the temporary player identity used during the player login process. For more information, see
Controlling Access to Resources (p. 420)
.
•
{project}
-
{deployment}
-
{resource-group}
– An AWS CloudFormation stack for each resource group of the project.
•
{project}
-
{deployment}
-
{resource-group}
-
{resource}
– The resources defined by a resource group.
Because of how AWS CloudFormation works, parts of these names have unique identifiers appended to them. For example, for a project named MyGame with a deployment named Development and a feature named HighScore, the actual name of a Scores resource would be something like:
MyGame-
Development-1FLFSUKM3MC4B-HighScore-1T7DK9P46SQF8-Scores-1A1WIH6MZKPRI
. The tools provided by Lumberyard hide these actual resource names under most circumstances.
•
{project}
-
{iam-policy-or-role}
– An IAM policy or role that manages resource and deployment permissions. For more information, see
Cloud Canvas Built-In Roles and Policies (p. 423) .
Configuration Bucket
The configuration Amazon S3 bucket is used to store configuration data for the project. The bucket is located at
/s3/buckets/
<projectname>
-configuration-
<ID>
/
. The tools provided with Cloud Canvas manage uploads to this bucket.
The cgp-resource-code
directory contains resource and deployment information for cloud gems in the Cloud Gem Portal. The upload
directory contains objects that are uploaded from the
{game}
/AWS directory by the Cloud Canvas tools when stack management operations are performed. The uploads for each operation get assigned a unique
{upload-id}
value to prevent concurrent operations from impacting each other.
project-settings.json
The project-settings.json
file contains project configuration data.
The structure of the project-settings.json
file is as follows:
{
"
{key}
": "
{value}
",
"deployment": {
"
{deployment}
": {
"
{key}
": "
{value}
",
"resource-group": {
"
{resource-group}
": {
"
{key}
": "
{value}
"
}
}
Version 1.10
317
Lumberyard Developer Guide
Resource Manager in Depth
}
}
}
The
{key}
and
{value}
pairs represent individual settings. The pairs at the root apply to the project. The pairs under
{deployment}
apply to that deployment. The pairs under
{resource-group}
apply to that resource group. Either or both of
{deployment}
and
{resource-group}
can be
*
, to indicate the settings they contain apply to all deployments or resource groups, respectively. Settings under a named entry take precedence over settings under a
*
entry.
Note
As of Lumberyard 1.8, the
ProjectStackId
property is stored in the dev\
<project name>
\AWS\local-project-settings.json
file. For more information, see ProjectStackId
DefaultDeployment Property
The
DefaultDeployment
property identifies the deployment that is to be used by default when working in Lumberyard Editor. The
DefaultDeployment
property in the
file overrides this setting. The project and user defaults can be set using the lmbr_aws
deployment default (p. 436) command. The
DefaultDeployment
setting is also used by the lmbr_aws
mappings update (p. 443) command.
ReleaseDeployment Property
The
ReleaseDeployment
property identifies the deployment that is to be used in release builds of the game. The
ReleaseDeployment
setting is used by the lmbr_aws
mappings update (p. 443) command.
DeploymentStackId Property, PendingDeploymentStackId
The
DeploymentStackId
property identifies the AWS CloudFormation stack for a deployment. The
PendingDeploymentStackId
property identifies a stack whose deployment is pending. The project's
The
DeploymentStackId
property is set by the deployment create (p. 436) command. If for some reason
you want to associate the deployment with an existing deployment, you can use the AWS Management
Console to look up the stack's ARN and paste it into the project-settings.json
file (navigate to AWS
CloudFormation, select the stack, select
Overview
, and then copy the value of the
Stack Id
property).
DeploymentAccessStackId Property
The
DeploymentAccessStackId
property identifies the AWS CloudFormation stack for the resources that control access to a deployment.
The
DeploymentAccessStackId
is set by the deployment create (p. 436)
command. If for some reason you want to associate the deployment with an existing deployment stack, you can use the AWS
Management Console to look up the stack's ARN and paste it into the project-settings.json
file
(navigate to AWS CloudFormation, select the stack, select
Overview
, and then copy the value of the
Stack Id
property).
parameter Property
The parameter
property provides the values for resource template parameters. The property must be in the following format.
{
...
"parameter": {
"{template-parameter-name-1}": {template-parameter-value-1},
...
Version 1.10
318
Lumberyard Developer Guide
Resource Manager in Depth
"{template-parameter-name-n}": {template-parameter-value-n}
}
...
}
Resource mappings map the friendly names used in a game's
to the actual
names of the resources created for one or more specific Resource Deployments (p. 316)
. For example, a DynamoDB table name like DailyGiftTable would get mapped to a name like
SamplesProject-
DontDieDeployment-78AIXR0N0O4N-DontDieAWS-1I1ZC6YO7KU7F-DailyGiftTable-1G4G33K16D8ZS
where
SamplesProject
is the name of the project,
DontDieDeployment
is the name of a deployment, and
DontDieAWS
is the name of a resource group. The
78AIXR0N0O4N
,
1I1ZC6YO7KU7F
and
1G4G33K16D8ZS parts of the resource name are inserted by AWS CloudFormation to guarantee that the resource name is unique over time. Thus, even if a resource is deleted and a new one with the same logical name is created, the physical resource ID will be different.
Usually different deployments, and consequently different mappings, are used for game development and for the released version of a game. Furthermore, different development, test, and other teams often work with their own deployments so that each team has distinct mappings.
The deployment used by default during development is specified in the
file. The file is located in the Amazon S3 configuration bucket at
/s3/ buckets/
<projectname>
-configuration-
<ID>
/project-settings.json
. The file can be overridden for each user by the dev\Cache\
{game}
\pc\user\AWS\ user-settings.json (p. 307)
file. You can change the default deployment by using the lmbr_aws
command or by using the
Cloud Canvas Resource Manager (p. 416)
.
The mappings used during development when the game is launched from the Lumberyard IDE by pressing
Ctrl+G
are stored in the user-settings.json (p. 307)
file just mentioned. This file is updated automatically when the default deployment changes, when the default deployment is updated, and when Lumberyard Editor is started. It can be refreshed manually by using the lmbr_aws
mappings update (p. 443) command.
When a game launcher application created in Lumberyard launches a release build of a game, the mappings for the game are stored in the
{root}
\
{game}
\Config\awsLogicalMappings.json
file.
These mappings can be updated manually using the lmbr_aws
command, which produces the awsLogicalMappings.json
file. You can specify the deployment for the release mappings in the
ReleaseDeployment
property of the
file.
For more information, see
Running AWS API Jobs Using the Cloud Gem Framework (p. 364) .
Using Mappings in AWS Flow Nodes
AWS flow nodes that define
TableName
(DynamoDB),
FunctionName
(Lambda),
QueueName
(Amazon SQS),
TopicARN
(Amazon SNS), or
BucketName
(Amazon S3) ports work with mappings. Set the port to a value like
{resource-group}
.
{resource}
where
{resource-group}
is the name of the resource group that defines the resource, and where
{resource}
is the name of the resource that appears in the
Resources
section of the resource group's resource-template.json
file. For detailed information on the Cloud
Canvas flow graph nodes, see the
Cloud Canvas Flow Graph Node Reference (p. 273) .
Using Mappings in Lambda Functions
Lambda function resources defined as part of a resource group often need to access other resources defined by that resource group. To do this, the function code needs a way to map a friendly resource name to the actual resource name used in AWS API calls. The
LambdaConfiguration
resource provides a way to such mappings, as well as other settings, to the lambda code. For more information, see
.
Version 1.10
319
Lumberyard Developer Guide
Resource Manager in Depth
Cloud Canvas Resource Manager uses AWS CloudFormation templates to describe the AWS resources needed for a project. AWS CloudFormation templates can have parameters. You provide the values for these parameters when a template creates or updates a stack.
AWS CloudFormation template parameters are useful when you want separate deployments of a resource group to be configured differently. For example, you could configure an internal test instance of
Amazon DynamoDB to use lower throughput than a public instance.
Follow the steps below to use AWS CloudFormation template parameters for your resource groups.
To use template parameters
1.
Define a parameter in the AWS CloudFormation template . You must provide a default value for the parameter. Be sure not to remove or modify the parameter definitions used by Cloud Canvas (for example,
ConfigurationBucket
or
ConfigurationKey
).
2.
Reference the parameter when you define a resource. You can use parameters to provide values for resource properties, including passing settings to Lambda functions through the Cloud Canvas
Custom::CloudGemFramework::LambdaConfiguration (p. 324)
resource.
3. Use the lmbr_aws parameter list
, parameter set
, and parameter clear
commands to view and set parameter values. These commands are described later in this document.
4. Update (or create) the resource group stack using the lmbr_aws resource-group upload
command, or click
Upload Resources
in the Cloud Canvas Resource Manager window in Lumberyard Editor.
Parameter Configuration
A project's parameter configuration is stored in a
project's configuration bucket. The bucket is defined by the project's AWS CloudFormation stack template.
You can specify parameter values for a specific deployment or for all deployments by using the
* character as a wildcard in place of a deployment name. You can also specify parameter values for a specific resource group or for all resource groups by using the
*
in place of a resource group name. If you provide a parameter value for both a wildcard (
*
) entry and a named entry, the value from the named entry overrides the value from the wildcard entry.
The following table shows the lmbr_aws
commands for listing, setting, and clearing parameter values.
Your project must be initialized (that is, a project stack must have been created) before you can list, set, or clear parameter values. For usage details, visit the corresponding links in the table.
lmbr_aws
command
parameter list (p. 444) parameter set (p. 444)
Description
Lists the parameters currently configured for your project.
Sets parameter configuration for your project.
Clears the specified parameter configuration for your project.
Cloud Canvas provides a number of AWS CloudFormation custom resources that can be used in the AWS
CloudFormation template files for the project, deployment, and resource group. These custom resources are implemented by the Lambda function code found in the dev\
{game}
\AWS\project-code
directory and the
ProjectResourceHandler
resource defined in the dev\
{game}
\AWS\project-template.json
file.
Version 1.10
320
Lumberyard Developer Guide
Resource Manager in Depth
Rather than static entities, these resources act more like library functions. Each custom resource has input and output properties.
A summary list of custom resources follows.
•
CognitoIdentityPool (p. 321) – Manages Amazon Cognito identity pool resources.
•
– Manages Amazon Cognito user pool resources.
•
– Used in the deployment-template.json
when there are no resource groups defined.
•
ResourceGroupConfiguration (p. 323)
– Provides configuration data for a resource-group's AWS
CloudFormation stack resource.
•
– Provides configuration data for Lambda function resources and maintains the Lambda function's execution role.
•
– Provides convenience functions for use in templates.
•
Cloud Gem Framework Service API (p. 373)
– Provides programmatic access to cloud gem functionality that you can use to implement cloud-connected features in your game.
For information on controlling access to resources, see Controlling Access to Resources (p. 420) .
CognitoIdentityPool
The
Custom::CloudGemFramework::CognitoIdentityPool
resource is used in the deployment-accesstemplate.json
file to create and configure Amazon Cognito identity pool resources.
Input Properties
•
ConfigurationBucket
Required. The name of the Amazon S3 bucket that contains the configuration data.
•
ConfigurationKey
Required. The Amazon S3 object key prefix where project configuration data is located in the configuration bucket. This property causes the custom resource handler to be executed by AWS
CloudFormation for every operation.
•
IdentityPoolName
Required. The name of the identity pool.
•
UseAuthSettingsObject
Required. Must be either true
or false
. Determines whether the Amazon Cognito identity pool is configured to use the authentication providers that were created from the add-login-provider command.
•
AllowUnauthenticatedIdentities
Required. Must be either true
or false
. Determines whether the Amazon Cognito identity pool is configured to allow unauthenticated identities. See Identity Pools for more information on Amazon
Cognito's support for authenticated and unauthenticated identities.
•
Roles
Optional. Determines the IAM role assumed by authenticated and unauthenticated users. See
SetIdentityPoolRoles for a description of this property.
Output Properties
•
IdentityPoolName
Version 1.10
321
Lumberyard Developer Guide
Resource Manager in Depth
The name of the identity pool (same as the
IdentityPoolName
input property).
•
IdentityPoolId
The physical resource name of the identity pool.
CognitoUserPool
The
Custom::CloudGemFramework::CognitoUserPool
resource is used in the Player Account Cloud
resource-template.json
file to create and configure Amazon Cognito user pool resources. You can use this resource to add Amazon Cognito user pools and link them to an Amazon
Cognito identity pool.
Input Properties
•
PoolName
Required. The name of the user pool.
•
ConfigurationKey
Required. The Amazon S3 object key prefix where project configuration data is located in the configuration bucket. This property causes the custom resource handler to be executed by AWS
CloudFormation for every operation.
•
ServiceToken
Required. The handler for this custom resource type.
•
ClientApps
Required. A list of client apps to be created for the user pool. At least one must be provided.
•
LambdaConfig
Optional. A map of a Lambda trigger name to a Lambda function ARN. This map is passed to the
Amazon Cognito
CreateUserPool
API when a user pool is created and to the Amazon Cognito
UpdateUserPool
API when a user pool is updated.
Metadata: Linking a User Pool to an Identity Pool
To link a
Custom::CloudGemFramework::CognitoUserPool
to a
Custom::CloudGemFramework::CognitoIdentityPool
, you add an
Identities
section to the
Metadata
CloudCanvas
section, as in the following example.
"Metadata": {
"CloudCanvas": {
"Identities": [
{
"IdentityPoolName": "PlayerAccess",
"ClientApp": "DefaultClientApp"
}
]
}
}
The handler for
Custom::CloudGemFramework::CognitoIdentityPool
looks for this metadata on
Custom::CloudGemFramework::CognitoUserPool
resources when it configures the identity pool. The
IdentityPoolName
in the user pool's metadata must match the
IdentityPoolName
in the identity pool's properties.
ClientApp
must be one of the apps listed in the user pool's
ClientApps
property.
Version 1.10
322
Lumberyard Developer Guide
Resource Manager in Depth
Output Properties
•
UserPoolName
The name of the user pool.
•
UserPoolId
The ID of the user pool.
•
ClientApps
A list that contains the
ClientId and
ClientName
of each of the user pool's client apps.
•
PhysicalResourceId
The physical resource ID of the user pool.
EmptyDeployment
The
Custom::CloudGemFramework::EmptyDeployment
resource is used in the deployment-template.json
file when there are no resource groups defined. This is necessary to satisfy the AWS CloudFormation requirement that a template define at least one resource.
This resource supports no input or output properties.
ResourceGroupConfiguration
The
Custom::CloudGemFramework::ResourceGroupConfiguration
resource is used in the deploymenttemplate.json
to identify the location of the copy of the resource-template.json
file in the configuration bucket that should be used for a specific resource group.
Input Properties
•
ConfigurationBucket
Required. The name of the Amazon S3 bucket that contains the configuration data.
•
ConfigurationKey
Required. The Amazon S3 object key prefix where the deployment configuration data is located in the configuration bucket.
•
ResourceGroup
Required. The name of the resource group that is to be configured.
Output Properties
•
ConfigurationBucket
The name of the Amazon S3 bucket that contains the configuration data. This is always the same as the
ConfigurationBucket
input property.
•
ConfigurationKey
The Amazon S3 object key prefix where the specified resource group's configuration data is located in the configuration bucket. This is the input
ConfigurationKey
with the string
ResourceGroup
and the value of
ResourceGroup
appended.
•
TemplateURL
The Amazon S3 URL of the resource group's copy of the resource-template.json
in the configuration bucket. This value should be used as the resource group's
TemplateURL
property value.
Version 1.10
323
Lumberyard Developer Guide
Resource Manager in Depth
LambdaConfiguration
The
Custom::CloudGemFramework::LambdaConfiguration
resource is used in resource-template.json
files to provide configuration data for Lambda function resources.
Input Properties
•
ConfigurationBucket
Required. The name of the Amazon S3 bucket that contains the configuration data.
•
ConfigurationKey
Required. The Amazon S3 object key prefix where configuration data for the resource group is located in the configuration bucket.
•
FunctionName
Required. The friendly name of the Lambda function resource being configured.
•
Settings
Optional. Values that are made available to the Lambda function code.
•
Runtime
Required. Identifies the runtime used for the Lambda function. Cloud Canvas currently supports the following Lambda runtimes: nodejs
, python2.7
.
Output Properties
•
ConfigurationBucket
The name of the Amazon S3 bucket that contains the configuration data. This is always the same as the
ConfigurationBucket
input property.
•
ConfigurationKey
The Amazon S3 object key prefix where the specified function's zipped code is located in the configuration bucket.
•
Runtime
The Lambda runtime used by the function. This is always the same as the input
Runtime
property value.
•
Role
The ID of the Lambda function execution created for this function.
For information on how the
LambdaConfiguration
custom resource is used to allow Lambda functions to
Helper
The
Custom::CloudGemFramework::Helper
resource is used in templates to perform simple tasks similar to those performed by AWS CloudFormation's Intrinsic Functions .
Input Properties
•
Input
Provides a JSON object that is processed by the custom resource handler.
Version 1.10
324
Lumberyard Developer Guide
Cloud Gem Framework
Output
The output is the processed version of the JSON object that is provided by the
Input
property.
Helper Function
The
Helper
resource supports the following function. The function is applied to the
Input
property value by resource handler to produce its output.
HelperFn::LowerCase
Converts a string to lowercase.
Syntax
{ "HelperFn::LowerCase" : "converted-string-value" }
Example
The following example from the project-template.json
file uses
HelperFn::LowerCase
to lower the case of a stack name.
{
...
"Resources": {
...
"Helper": {
"Type": "Custom::CloudGemFramework::Helper",
"Properties": {
"Input": {
"LowerCaseStackName": { "HelperFn::LowerCase": { "Ref":
"AWS::StackName" } }
},
"ServiceToken": ...
}
},
...
{ "Fn::Join": [ "", [ "arn:aws:s3:::", { "Fn::GetAtt": [ "Helper",
"LowerCaseStackName" ] }, "-*" ] ] }
...
}
The Cloud Gem Framework and this documentation are in preview release and are subject to change.
More topics are planned.
The Lumberyard Cloud Gem Framework makes it easy to build popular cloud-connected features, such as dynamic content, leaderboards, and daily messages. The Cloud Gem Framework has two components:
•
Cloud Gem Portal
– A web application for visually managing and administering your cloud features
(like scheduling messages, releasing dynamic content, or deleting a fraudulent leaderboard score)
•
Cloud gems
– Modular packages of discrete functionality and assets that include everything necessary for a developer to include that functionality into their project, including backend and client functionality.
Version 1.10
325
Lumberyard Developer Guide
Cloud Gem Framework
Cloud gems can be used out of the box in production, and they come with full source code in case you want to customize their behavior.
Topics
•
Getting Started with the Cloud Gem Framework (p. 326)
•
Getting Started With Development on the Cloud Gem Portal (p. 328)
•
Making HTTP Requests Using the Cloud Gem Framework (p. 343)
•
Cloud Gem Framework Resource Manager Hooks (p. 344)
•
Running AWS API Jobs Using the Cloud Gem Framework (p. 364)
•
AWS Behavior Context Reflections (p. 366)
•
Cloud Gem Framework Service API (p. 373)
•
Using the Cloud Gem Framework Command Line (p. 400)
•
•
Cloud Gem Framework and Resource Manager Versioning (p. 403)
•
Updating Projects and Cloud Gems to Version 1.0.0 of the Cloud Gem Framework (p. 405)
Lumberyard cloud gems make it easy to create cloud-connected functionality for your games. You can use the cloud gems included with Lumberyard, or use Lumberyard's Cloud Gem Framework to create your own cloud gems.
Cloud Gems
Cloud gems are Lumberyard gems that use
Cloud Canvas Resource Manager (p. 184)
(CCRM) to define AWS resources that support their operation. CCRM provides the infrastructure needed to create, configure, and access AWS resources. A cloud gem defines resources and implements the required operations to create a complete game subsystem.
Cloud gems use general purpose AWS features that operate in your AWS account. They are not gamespecific services operated by Amazon. Cloud gems follow a serverless microservice architecture that makes use of AWS Lambda functions for computation, and Amazon DynamoDB, Amazon RDS, and
Amazon S3 for data storage. However, a cloud gem can use any AWS service.
For example, a cloud gem could provide a leaderboard system that uses a DynamoDB table to store high scores. The gem could use an AWS Lambda function to validate submitted scores and allow fraudulent high scores to be deleted.
In this scenario, CCRM performs the following tasks:
• Creates the DynamoDB table and Lambda function defined by the gem.
• Enables the game client to invoke the API to submit a score.
• Protects the integrity of the leaderboard by removing fraudulent scores automatically.
• Permits the creation of a user interface that enables an authorized employee to remove fraudulent scores manually.
Cloud Gem Framework
The Cloud Gem Framework is a collection of tools and API operations that support the creation and operation of cloud gems.
Version 1.10
326
Lumberyard Developer Guide
Cloud Gem Framework
The following diagram shows a high-level view of the Cloud Gem Framework architecture.
The Cloud Gem Framework contains the following major components:
•
– A web application for operating and managing cloud gems.
•
Cloud Gem Framework Service API (p. 373)
– An API that provides a secure interface to a cloud gem's functionality.
•
AWS API Jobs (p. 364) – Integrates the AWS API with the Lumberyard job execution systems (not
illustrated).
•
HTTP Request Job (p. 343) – A Lumberyard job for executing HTTP requests (not illustrated).
Creating a Cloud Gem
Lumberyard includes some cloud gems, such as leaderboards and dynamic content distribution, that provide full-featured services. You can use these gems in your games with a minimum of effort. Because the full source code for these cloud gems is included with Lumberyard, you can customize them or use them as examples for developing your own cloud gems.
To create a new cloud gem
1. Use the Lumberyard Project Configurator to create a new gem.
2. In Project Configurator, enable the gem for your project.
3. In Project Configurator, enable the
Cloud Gem Framework
gem for your project.
4. In the
\dev\Gems\
<gem-name>
directory for your new gem, add the following dependency to the gem.json
file.
"Dependencies": [
{
"Uuid" : "6fc787a982184217a5a553ca24676cfa",
"VersionConstraints": [ "~>0.1" ],
"_comment": "CloudGemFramework"
},
{
"Uuid" : "102e23cf4c4c4b748585edbce2bbdc65",
"VersionConstraints": [
"~>0.1"
Version 1.10
327
Lumberyard Developer Guide
Cloud Gem Framework
],
"_comment": "CloudCanvasCommon"
}
],
5. Type the following command line to add a CCRM resource group to your gem. The command creates a
\dev\Gems\
<gem-name>
\AWS
directory with a resource-template.json
file and a lambda-functioncode
directory.
lmbr_aws resource-group add --gem --resource-group
<gem-name>
6. Type the following command line to add service API resources to the resource group.
lmbr_aws cloud-gem-framework add-service-api-resources --resource-group
<gem-name>
The add-service-api-resources
command adds
ServiceApi
,
ServiceLambda
, and
ServiceLambdaConfiguration
resources to the resource group. It also adds an
Output
for the service API URL. The
AccessControl
resource is configured as described in
. The add-service-api-resources
command also creates a swagger.json
file
that describes the API for the cloud gem. For more information, see Cloud Gem Framework Service
.
7. Add any additional resource definitions to the resource-template.json
file that the cloud gem requires.
8. Implement the cloud gem's functionality by adding code to the lambda-function-code
directory.
You upload this code to the
ServiceLambda
Lambda function resource that you created earlier.
9. Add paths and operations to the swagger.json
file to create an API operation that exposes the cloud
gem's functionality. For more information, see Cloud Gem Framework Service API (p. 373) .
tutorial. This process uses the resource descriptions in your resourcetemplate.json
file to create resources in AWS for your cloud gem.
11. Type the following command to generate a service API client for the cloud gem.
lmbr_aws cloud-gem-framework generate-service-api-code --resource-group
<gem-name>
The generate-service-api-code
command reads the cloud gem's API definitions from the swagger.json
file and generates C++ code in the
/dev/Gems/
<gem-name>
/Code/AWS
directory. This code implements a Lumberyard component that you can use to invoke the cloud gem's service API operations from C++ or Lua.
12. Use Lumberyard components, EBuses, and other features to implement game client functionality for the gem. Place the code in the cloud gem's
/dev/Gems/
<gem-name>
/Code
directory. You can use the service API client that you generated to access the functionality in the cloud gem's
ServiceLambda
Lambda function.
To help you get started with development on the Cloud Gem Portal (CGP), this tutorial shows you how to do the following:
• Set up your environment for CGP development.
• Create a cloud gem and a dynamic Cloud Gem Portal.
• Test your Cloud Gem Portal locally.
• Deploy your Cloud Gem Portal to AWS and view it in production.
Version 1.10
328
Lumberyard Developer Guide
Cloud Gem Framework
Setting Up Your Environment
Setting up your environment includes installing Node.js packages, Git, creating a test URL, and configuring Microsoft Visual Studio if you are using it.
Installing Node.js and Git
The Cloud Gem Portal uses the Angular 2 version of AngularJS for development and the Node.js package manager (npm) for managing dependencies.
To install Node.js and git
1. Download and install Node.js from the Node.js website .
2. Download and install Git from the Git download page .
3. Obtain a GitHub account if you do not have one. You must have a GitHub account to download the
GitHub packages for the Cloud Gem Portal and for the optional jspm package management tool.
jspm is a package manager for the SystemJS universal module loader and is built on the dynamic
ES6 Module Loader .
Updating Packages and Running a Local Server
From a command prompt, run the following commands to change to the
CloudGemPortal
directory, install packages, and run a gulp server. gulp is a toolkit for automating tedious or time-consuming development tasks.
To update packages and run a local server
1. Type the following command to change to the
CloudGemPortal
directory.
cd
<Lumberyard directory path>
\dev\Gems\CloudGemFramework\v
<N>
\Website\CloudGemPortal
2. If you want to use JSPM, type the following command.
npm install -g jspm
3. Run the following commands.
npm install -g gulp npm install gulp serve
The npm install
command installs the packages that you need to run the Cloud Gem Portal website. If you are using perforce, you must checkout the package.json
and config.js
files so that they are writable.The gulp serve
command runs the default gulp task to set up a browsersync server. You do not have to run npm install
again unless you add or update packages.
4. The output of the gulp serve
command looks like the following.
[ ] Access URLs:
-----------------------------------
Local: http://localhost:3000
External: http://00.00.00.0:3000
-----------------------------------
UI: http://localhost:3001
UI External: http://00.00.00.0:3001
-----------------------------------
5. Open a browser and navigate to http://localhost:3000
. A login page should appear.
Version 1.10
329
Lumberyard Developer Guide
Cloud Gem Framework
Creating an Administrator Account
Now you are ready to create an administrator account so that you can sign in on the page that you just opened.
To create an administrator account
1. Type the following from a command prompt window: cd
Lumberyard_directory
\dev lmbr_aws cloud-gem-framework cloud-gem-portal --show-configuration --show-url
These commands create an administrator account so that you can sign in. It also generates a project settings JSON string and an HTTPS URL. The project settings string is the text between the
{} braces, as you can see in the following example.
Before you can sign in with your administrator credentials, you must copy this project settings string to a file in your Cloud Gem Portal code.
2. Open the
\dev\Gems\CloudGemFramework\v
<N>
\Website\CloudGemPortal\cgp_bootstrap.js
file for editing in a text editor.
3. Set the variable cgpBootstrap
to the project settings JSON string that you generated, as in the following example.
Note
The HTTPS URL that was generated is not required. Be sure not to paste it into the cgp_bootstrap.js
file.
4. Save your changes.
5. With your browser open to http://localhost:3000
, sign in with the temporary administrator credentials that were generated.
Version 1.10
330
Lumberyard Developer Guide
Cloud Gem Framework
6. Your password is temporary, so create a new one.
Version 1.10
331
Lumberyard Developer Guide
Cloud Gem Framework
After you change the administrator password, you are automatically logged in and redirected to the cloud gems page, which lists your active gems.
Now you can start editing your code. Your changes should appear when you reload the site.
Version 1.10
332
Lumberyard Developer Guide
Cloud Gem Framework
To learn how to set up Microsoft Visual Studio for creating cloud gems, see the following section. To
start creating your own cloud gems right away, see Developing Cloud Gems (p. 335) .
Microsoft Visual Studio Setup
You can edit your code with any text editor, but for creating cloud gems, you might prefer Microsoft
Visual Studio for its Typescript support. To use Visual Studio 2015 to create cloud gems, you configure it to work with Node.js, add some TypeScript extensions, and optionally install Task Runner Explorer to run gulp tasks.
Configuring Visual Studio to Work with Node.js
Perform the following steps to configure Visual Studio to work with Node.js.
To configure Visual Studio to work with Node.js
1. Open the
<lumberyard>
\dev\Gems\CloudGemFramework\v
<N>
\Website\CloudGemPortal
\Portal.csproj
solution file from Visual Studio.
2. In the navigation bar, click
Tools
,
Options
,
Projects and Solutions
,
External Web Tools
.
3. Add your nodejs
and node_modules\.bin
directories to the external tools configuration so that
Visual Studio can find them. The ordering of the paths is important. Move your nodejs
and
.node_modules/.bin
paths above the defaut Visual Studio paths, as shown in the following image.
Tools and Extensions Setup
Next, you must install TypeScript-related extensions for Visual Studio.
To install TypeScript-related extensions
1. Click
Tools
,
NuGet Package Manager
,
Manage NuGet Packages for Solution
.
2. Install the following packages:
•
angularjs.TypeScript.DefinitelyTyped
Version 1.10
333
Lumberyard Developer Guide
Cloud Gem Framework
•
es6-shim.TypeScript.DefinitelyTyped
•
jquery.TypeScript.DefinitelyTyped
After you install these packages, you can develop cloud gems in Visual Studio.
Note
If you are using Visual Studio 2015, it is possible to update npm packages or run a local server by right-clicking
package.json
and then choosing
Restore Packages
. However, you might find that using the npm install
command from the
<Lumberyard directory path>
\dev\Gems
\CloudGemFramework\v
<N>
\Website\CloudGemPortal\
directory works more consistently.
Using the Task Runner Explorer (Optional)
To run the gulp task, you can use Task Runner Explorer , a Visual Studio UI extension that executes any grunt or gulp task or target.
To use Task Runner Explorer
1. In Visual Studio, right-click
gulpfile.js
.
2. Choose
Task Runner Explorer
. The tool displays all the current gulp tasks.
3. To start a task, double-click the task.
4. To start a server, run
default
or
gulp serve
in the list of gulp
Tasks
.
Version 1.10
334
Lumberyard Developer Guide
Cloud Gem Framework
Troubleshooting
If opening a
.ts
file causes Visual Studio to crash, make sure that no other Visual Studio plugins are installed that open
.ts
files (QT Visual Studio and QT Linguist are two examples).
Developing Cloud Gems
Now you are ready to create cloud gems, which you can easily modify and redistribute to other developers. To develop a cloud gem, you add base files and set up your TypeScript,
.html
, and
.css
files.
Adding Base Files
From a command prompt window, create a symbolic link to your cloud gem source directory. The link should point to the cgp-resource-code
directory within your cloud gem.
On Windows, use the following syntax.
mklink /J
<Workspace Path>
\dev\Gems\CloudGemFramework\v
<N>
\Website\CloudGemPortal\external
\
<gem-name> <Workspace Path>
\dev\Gems\
<gem-name>
\AWS\cgp-resource-code
The following example syntax creates a symbolic link to the cgp-resource-code
directory for the
Message of the Day Cloud Gem.
mklink /J
<Workspace Path>
\dev\Gems\CloudGemFramework\v
<N>
\Website\CloudGemPortal\external
\CloudGemMessageOfTheDay
<Workspace Path>
\dev\Gems\CloudGemMessageOfTheDay\AWS\cgpresource-code
At this point, your file system is ready. Now you can add skeleton code to the TypeScript,
.html
, and
.css
files.
Creating TypeScript Files
The Cloud Gem Portal is built on the Angular 2 version of AngularJS . The default language for Angular
2 is TypeScript . TypeScript is a typed superset of the JavaScript language. TypeScript files have a
.ts
extension. To build your cloud gem, you must create a number of .ts files.
Basic Cloud Gem
The following diagram shows the recommended directory structure for a basic cloud gem and the
.ts
and other files that it contains.
Version 1.10
335
Lumberyard Developer Guide
Cloud Gem Framework
<gem name>
<gem name>
.ts
<gem name>
.module.ts
api-handler.class.ts
index.component.html
index.component.scss
index.component.ts
index.ts
model.class.ts
thumbnail.component.html
thumbnail.component.ts
Basic Cloud Gem File Descriptions
File
<gem name>
.module.ts
<gem name>
.ts
api-handler.class.ts
index.component.html
index.component.scss
index.component.ts
index.ts
model.class.ts
thumbnail.component.html
thumbnail.component.ts
Description
The main cloud gem module.
Required. The factory entry point for the gem.
A custom service API handler class.
HTML for the index component.
Style sheet definition for the index component.
The index component (the main component for the gem).
The export barrel.
Contains component model classes.
HTML markup for the thumbnail component that appears on the
Cloud Gems
page.
The thumbnail component that appears on the
Cloud Gems
page.
Advanced Cloud Gem
If you plan on creating a more complex cloud gem (for example, one with many components, services, and pipes), we recommend the following file structure.
<gem name>
<gem name>
.ts
<gem name>
.module.ts
component
*.component.ts
*.component.html
*.component.scss
module
*.module.ts
directive
*.directive.ts
service
*.service.ts
pipes
*.pipe.ts
Example Starter Cloud Gem .ts Files
The following example
.ts
files are for the Message of the Day Cloud Gem.
Version 1.10
336
Lumberyard Developer Guide
Cloud Gem Framework
//
cloudgemmessageoftheday.module.ts
import { GemModule } from 'app/view/game/module/cloudgems/gem.module'; import { MessageOfTheDayIndexComponent, MessageOfTheDayThumbnailComponent } from './index' import { GameSharedModule } from 'app/view/game/module/shared/shared.module' import { NgModule } from '@angular/core';
/*
* The Cloud Gem Angular 2 NgModule defines context for the cloud gem
*/
@NgModule({
imports: [
GameSharedModule,
GemModule
],
declarations: [
MessageOfTheDayIndexComponent,
MessageOfTheDayThumbnailComponent
],
providers: [
],
bootstrap: [MessageOfTheDayThumbnailComponent, MessageOfTheDayIndexComponent]
}) export class CloudGemMessageOfTheDayModule { }
//
cloudgemmessageoftheday.ts
import { CloudGemMessageOfTheDayModule } from './index' import { NgModule } from '@angular/core';
/*
* Entry point for the cloud gem factory
*/ export function definition(context: any): NgModule {
return CloudGemMessageOfTheDayModule;
}
//
index.component.ts
import { Input, Component } from '@angular/core'; import { AbstractCloudGemIndexComponent } from 'app/view/game/module/cloudgems/class/ index';
@Component({
selector: 'message-of-the-day-index',
template: `Welcome to the message of the day index page`
// OR you can use a templateUrl: 'external/cloudgemmessageoftheday/ index.component.html'
}) export class MessageOfTheDayIndexComponent extends AbstractCloudGemIndexComponent {
@Input() context: any; //REQUIRED
constructor() {
super()
}
//Your component controller code
}
//
thumbnail.component.ts
(without a REST API handler) import { AbstractCloudGemThumbnailComponent, TackableStatus, TackableMeasure, Measurable }
from 'app/view/game/module/cloudgems/class/index'; import { Component, Input, OnInit } from '@angular/core' import { Observable } from 'rxjs/rx'
Version 1.10
337
Lumberyard Developer Guide
Cloud Gem Framework
@Component({
selector: 'cloudgemmessageoftheday-thumbnail',
template: `
<thumbnail-gem
[title]="displayName"
[cost]="'High'"
[srcIcon]="srcIcon"
[metric]="metric"
[state]="state"
>
</thumbnail-gem>`
}) export class MessageOfTheDayThumbnailComponent implements
AbstractCloudGemThumbnailComponent{
@Input() context: any
@Input() displayName: string = "Your first Cloud Gem";
@Input() srcIcon: string = "https://m.media-amazon.com/images/G/01/cloudcanvas/images/ message_of_the_day._V536715120_.png"
public state: TackableStatus = new TackableStatus();
public metric: TackableMeasure = new TackableMeasure();
constructor() {
super()
}
ngOnInit() {
this.report(this.metric)
this.assign(this.state)
}
public report(metric: Measurable) {
metric.name = "My Metric";
metric.value = "1million!";
new Observable<any>(observer => {
setTimeout(() => {
observer.next({
value: '100,000,000'
});
}, 3000);
setTimeout(() => {
observer.complete();
}, 1000);
}).subscribe(response => {
metric.value = response.value;
})
}
public assign(status: TackableStatus) {
status.label = "My Status";
status.styleType = "Enabled";
new Observable<any>(observer => {
setTimeout(() => {
observer.next({
status: 'Online'
});
}, 3000);
setTimeout(() => {
observer.complete();
}, 1000);
}).subscribe(response => {
Version 1.10
338
Lumberyard Developer Guide
Cloud Gem Framework
}
status.label = response.status;
status.styleType = response.status;
})
}
//
index.ts
(export barrel) export * from './thumbnail.component' export * from './index.component' export * from './cloudgemmessageoftheday.module
Testing the Results
After your setup of the
.ts
files is complete, you can test the results. If you are running your local server with gulp serve
or gulp serve-watch
, navigate to localhost:3000
. Your new gem should appear in the
Cloud Gems
section.
If you click the gem thumbnail, the page that appears is blank, but that's expected at this point.
Creating an HTML File
You can verify that your gem is working by adding a header like the following to your
.html
file.
<h1> Hello welcome to my new gem! </h1>
If you reload the Cloud Gem Portal page and navigate to your gem, your new text appears.
Version 1.10
339
Lumberyard Developer Guide
Cloud Gem Framework
Creating Dynamic Content
To make your content more dynamic, you can use Angular 2 directives in your
.html
and
.ts
files. To see this in action, modify the
.html
and
.ts
files to create a test button on the Message of the Day Cloud
Gem, as in the following example.
In the
.html
file, add the following markup.
<h1> Hello welcome to my new gem! </h1>
<h2 *ngIf="testButton"> Why oh why would you touch that? </h2>
<form>
<button class="btn l-primary" (click)="testButton = !testButton">
Check out this fancy button
</button>
</form>
Modify your
.ts
file as in the following example.
export class Motd extends DynamicGem {
...
private testButton: boolean;
ngOnInit() {
this.testButton = false;
}
}
The following image shows what happens when the button is clicked.
Version 1.10
340
Lumberyard Developer Guide
Cloud Gem Framework
Creating a CSS File
You can use standard CSS to style your cloud gems. For convenience, Lumberyard's cloud gems use the
Bootstrap 4 CSS framework. When you use standard HTML tags, the your tags automatically pick up CSS changes that provide a professional looking, consistent user interface.
Deploying Your Changes
After you are satisfied with your gem, you can upload it to AWS to verify that it is working. Deploying your changes includes three steps: packaging your changes, copying your files to a local AWS directory, and uploading your cloud gem and Cloud Gem Portal files to AWS.
1. Packaging Your Changes
To package your changes, perform one of the following tasks:
• In Visual Studio, run the gulp task build_deploy
.
• From a command line prompt, run gulp build_deploy
.
Doing so packages the three Cloud Gem Portal files index.html
, bundles\app.bundle.js
, and bundles
\dependencies.bundles.js
and copies them to the lumberyard\Gems\CloudGemFramework\AWS\www publishing directory.
Version 1.10
341
Lumberyard Developer Guide
Cloud Gem Framework
3. Uploading the Cloud Gem With Your Cloud Gem Portal Content
Before you upload your cloud gem to AWS, make sure you have you added your new cloud gem to your project with the Project Configurator. To perform the upload, you can use either Lumberyard Editor or a command-line prompt.
To use Lumberyard Editor to upload your cloud gem and Cloud Gem Portal content to AWS
1. In Lumberyard Editor, click
AWS
,
Cloud Canvas
,
Resource Manager
.
2. Under
Administration
,
Deployments
, click your active deployment. If you don't have a deployment, create one first.
3. Click
Upload All Resources
.
4. After the upload has completed, click
AWS
,
Open Cloud Gem Portal
in Lumberyard Editor to access the Cloud Gem Portal that you uploaded. Your changes should be visible on the live website.
To use a command line prompt to upload your cloud gem and Cloud Gem Portal content to
AWS
1. To update all of the files in the
Gems\cgp-resource-code
directory in the cloud, type the following command: lmbr_aws cloud-gem-framework upload-portal
2. To update your Amazon S3 Cloud Gem Portal bucket with the latest files from your lumberyard
\Gems\CloudGemFramework\AWS\www
directory, type the following command.
lmbr_aws cloud-gem-framework upload-portal --project
Summary
In this tutorial, you accomplished the following tasks:
1. Added a gem to the
CloudGemPortal
framework.
Version 1.10
342
Lumberyard Developer Guide
Cloud Gem Framework
2. Used TypeScript and Angular 2 to create three required
.js
,
.html
, and
.css
files.
3. Used Lumberyard Editor to upload your changes to Amazon S3.
4. Viewed your changes in production.
The Cloud Gem Framework and this documentation are in preview release and are subject to change.
The Cloud Gem Framework Gem provides C++ classes and EBus interfaces to execute HTTP requests using the
AZ::Job
system. Your game client can use this feature to make HTTP requests for data from a public API such as Twitter or from a custom API. For example, your game could make HTTP requests to
Twitter to see who is tweeting about your game.
To enable your game code to make HTTP requests
1. In Lumberyard Project Configurator , enable the
Cloud Canvas Common
and
Cloud Gem Framework
gems for your project.
2. In Lumberyard Editor, in
Entity Inspector
, click
Add Component
.
3. From the
Cloud Gem Framework
section, add the
HttpClientComponent
to an entity in your scene.
4. To make HTTP requests from your game code, perform one of the following steps:
• From a Lua script component attached to your entity, add code based on the following example.
local url = "https://my.url.com" local http_method = "GET" local json_body = "{}"
HttpClientComponentRequestBus.Event.MakeHttpRequest(self.entityId, url, http_method,
json_body)
• From C++, use Lumberyard's
, as in the following example.
AZStd::string url = "https://my.url.com"
AZStd::string httpMethod = "GET"
AZStd::string jsonBody= "{}"
EBUS_EVENT
(HttpClientComponentRequestBus, MakeHttpRequest, url, httpMethod,
jsonBody);
• From C++, use
HttpRequestJob
, as in the following example.
AZStd::string url = "https://my.url.com"
AZStd::string httpMethod = "GET"
AZStd::string jsonBody= "{}" auto job = aznew
HttpRequestJob
(true, ServiceJob::GetDefaultConfig(),
[this](int responseCode, AZStd::string content)
{
// handle success
},
[this](int responseCode)
{
// handle failure
}
); job->SetUrl(url.c_str()); job->SetHttpMethod(httpMethod ); job->SetJsonBody(jsonBody.c_str());
Version 1.10
343
Lumberyard Developer Guide
Cloud Gem Framework job->Start();
Getting HTTP Responses Using Script
To get responses from a HTTP request, your script class needs an
HttpClientComponentNotificationBus as in the following example.
function httpClientUsageExample:OnActivate()
self.notificationHandler =
HttpClientComponentNotificationBus.Connect
(self,
self.entityId); end
Next, your script class must implement the
HttpClientComponentNotificationBus
functions
OnHttpRequestSuccess and OnHttpRequestFailure
as in the following example.
function myscript:
OnHttpRequestSuccess
(responseCode, responseBody)
Debug.Log("HTTP RESPONSE -- " .. responseCode);
Debug.Log("HTTP BODY -- " .. responseBody); end function myscript:
OnHttpRequestFailure
(errorCode)
Debug.Log("HTTP Error-- " .. errorCode); end
Getting HTTP Responses Using C++
To get the notifications in C++, you must create a component that inherits from
HttpClientComponentNotificationBus::Handler
. This class must implement
OnHttpRequestSuccess
and
OnHttpRequestFailure
and should be placed on the same entity as the
HttpClientComponent
in your level.
The Cloud Canvas Resource Manager ensures that the AWS resources that the game uses match the definitions of those resources in the game's source code. However, you might need to add functionality to these processes. For example, for the Dynamic Content Cloud Gem, you must upload any default packages for the project immediately after you create a new deployment.
The resource manager provides some Python hook modules for cloud gems. The code for these modules is located in the resource-manager-code
directory found in the cloud gem's AWS directory (for example,
\dev\Gems\CloudGemDynamicContent\AWS\resource-manager-code
).
The following modules are supported:
• update.py
– Contains functions that are called before and after stack update operations. For more
information, see Update Hook Functions (p. 361)
.
• command.py
– Contains functions that add new CLI and GUI support to the resource manager. For more
information, see Command Hook Functions (p. 362) .
Hook Function Parameters
All hook functions are called with the following:
• A parameter that represents the hook function
• Some keyword arguments that are specific to each hook function
Version 1.10
344
Lumberyard Developer Guide
Cloud Gem Framework
The parameter that represents the hook function is a
object (p. 353) . The most important
property provided by the
HookModule
object is context
, which is a
Context object gives your hook function access to the Cloud Canvas Resource Manager configuration data for the project.
Futureproofing Your Functions
When you write a hook function, always add Python's
**kwargs
construct as the last argument. That way your function can gracefully accept (and ignore) arguments that future versions of resource manager might add after your function is written.
For example, suppose resource manager passes arg_a
and arg_b
arguments to your hook function. You declare the hook function as follows: def a_hook(hook, arg_a, arg_b, **kwargs)
Later, when resource manager adds an arg_c
argument, your hook function does not break. Your function still accepts arg_a
and arg_b
but can ignore arg_c
because arg_c
was passed through the kwargs
parameter.
Cloud Canvas Resource Manager Objects
Cloud Canvas Resource Manager includes Python objects that you can use to access project configuration data and perform various project operations.
Note
The source code for these objects is located in the Lumberyard dev\Tools\lmbr_aws
\AWSResourceManager
directory.
Context Object
The
Context
object has properties that provide access to project configuration and that perform operations such as adding resource definitions to a resource group template.
You can get a
Context
object instance from the context
property of the
HookModule
object instance passed to hook functions.
Name
aws config gem hooks resource_groups stack view
Description
An
AWSContext
object.
A
ConfigContext
object.
A
GemContext
object.
A
HookContext
object.
A
ResourceGroupContext
object.
A
StackContext
object.
A
ViewContext
object.
Other properties or functions of this object are internal to resource manager and should not be used.
AWSContext Object
The
AWSContext
object has helper functions and properties related to AWS clients and credentials.
Version 1.10
345
Lumberyard Developer Guide
Cloud Gem Framework
You can get an
AWSContext
object instance from the aws
property of a
Context
object.
Name
assume_role(logical_role_id, deployment_name) client(service_name, region=None, use_role=True) get_credentials_file_path() get_default_profile() get_temporary_credentials(logical_role_id, deployment_name, duration_seconds)
Description
Assumes a role that uses the user's current AWS credentials. New clients that were created from the client
function use the temporary credentials that were created by assuming the role. These credentials have a 3600 second (5 minute) lifetime.
The logical_role_id
parameter can be the logical name of a
AWS::IAM::Role
resource defined in the project-template.json
or deployment-access-template.json
files. In the case of a role that is defined in the deploymentaccess-template.json
file, the deployment_name identifies the actual role that will be assumed.
Creates a Python AWS API (boto3) client for the specified AWS service. If use_role
is
True
, the client uses the credentials that are created when assume_role
was called.
The returned object is a wrapper around the actual boto3 client object. The wrapper logs all
API call attempts and responses when the
-verbose
option is passed to lmbr_aws
. This aids in debugging.
The client wrapper also performs retries with exponential back off.
Returns the full path to the user's
.aws/ credentials
file.
Gets the AWS credentials profile name that is used by default when clients are created.
Creates temporary credentials by using the user's current credentials to assume a role.
The logical_role_id
parameter can be the logical name of a
AWS::IAM::Role
resource defined in the project-template.json
or deployment-access-template.json
files. In the case of a role defined in the deploymentaccess-template.json
file, the deployment_name identifies the actual role that will be assumed.
The return value is a Python dict
with the following properties:
AccessKeyId
SecretAccessKey
SessionToken
Version 1.10
346
Lumberyard Developer Guide
Cloud Gem Framework
Name
load_credentials() profile_exists(profile_name) save_credentials(credentials) session set_default_profile
Description
Returns an
AWSCredentials
object that contains the data read from the user's
.aws/credentials file.
Determines whether the specified profile exists in the user's
.aws/credentials
file.
Saves a modified
AWSCredentials
object into the user's
.aws/credentials
file.
The boto3 session object that is used by client()
.
Sets the AWS credentials profile that is used when clients are created. This resets the session property.
Other properties or functions of this object are internal to resource manager and should not be used.
AWSCredentials Object
The
AWSCredentials
object contains AWS credential information that is read from the user's
.aws/credentials
file. This is essentially a wrapper around a Python
ConfigParser
object. The
AWSCredentials
object handles the AWS credential file's use of the default
section, which conflicts with how
ConfigParser
handles defaults.
To get an
AWSCredentials
object instance, use the load_credentials
function on an
AWSContext
object.
Name
add_section(section_name) get(section_name, option_name) has_option(section_name, option_name) has_section(section_name) items(section_name) options(section_name) read(path) remove_option(section_name, option_name) remove_section(section_name) sections() set(section_name, option_name, value) write(path)
Description
Adds a section.
Gets the value of an option in a section.
Determines whether an option exists in a section.
Determines whether a section exists.
Returns a list of name value pairs of the options in a section.
Returns a list of options in a section.
Reads credentials from a file with the specified path.
Removes an option from a section.
Removes a section.
Returns a list of section names. Each profile is represented by a section.
Sets an option value.
Writes credentials to a file with the specified path.
Other properties or functions of this object are internal to resource manager and should not be used.
Version 1.10
347
Lumberyard Developer Guide
Cloud Gem Framework
ConfigContext Object
The
ConfigContext
object has properties and functions that provide access to project and deployment configuration data.
You can get a
ConfigContext
object instance from the config
property of a
Context
object.
Name Description
aws_directory_path base_resource_group_directory_path clear_user_default_deployment() clear_user_default_profile() configuration_bucket_name
The full path to the currently enabled game project (as determined by the bootstrap.cfg
file or options passed to lmbr_aws
).
The directory where resource groups that are defined by the project (as opposed to those defined by gems) are located. This is typically the resource-group
subdirectory that is found in the directory identified by aws_directory_path
.
Clears the user's default deployment setting.
Clears the user's default AWS credentials profile name. This does not update the user's
.aws/ credentials
file. The name of the default profile is saved in the Cloud Canvas Resource Manager's user settings file.
The name of the project's
Configuration
Amazon
S3 bucket.
copy_default_lambda_function_content
Copies the default Lambda function content to the specified location.
(destination_path) copy_default_project_content(destination_path)
Copies the content from the default project AWS directory to the specified location.
Copies the content from the default resource group to the specified location.
Copies the content from the example resource group to the specified location.
default_deployment deployment_access_template deployment_access_template_path deployment_names deployment_stack_exists(deployment_name)
The name of the deployment that is the default for the current user if a default name has been specified. If a default has been specified, the value is that of user_default_deployment
; otherwise, it is that of project_default_deployment
.
A Python object that contains the content of the deployment access template file.
The full path to the project's deployment-accesstemplate.json
file.
A list that contains the names of the project's deployments.
Determines whether a deployment stack exists.
Version 1.10
348
Lumberyard Developer Guide
Cloud Gem Framework
Name Description
finalize_deployment_stack_ids(deployment_name)
Commits the pending deployment and deployment access stack IDs as the deployment's actual stack IDs. See set_pending_deployment_stack_id
and set_pending_deployment_access_stack_id
.
game_directory_path
The full path to the currently enabled game project (as determined by the bootstrap.cfg
file or the options that are passed to lmbr_aws
).
gem_directory_path
The full path to the directory where gems are defined. This is the
Gems
subdirectory of the directory identified by root_directory_path
.
Gets the default stack name for a deployment with the specified name.
optional=False)
Gets the ARN of a deployment access stack. If the specified deployment stack doesn't exist, raises a
HandledError
or returns
None
if optional
is
True
.
get_deployment_stack_id(deployment_name, optional=False) get_game_directory_name() get_project_stack_name() get_protected_depolyment_names() get_resource_group_stack_id(deployment_name, resource_group_name, optional=False) local_project_settings_path no_prompt project_code_path
Gets the ARN of a deployment stack. If the specified deployment stack doesn't exist, raises a
HandledError
or returns
None
if optional
is
True
.
Gets the name of the game directory from the bootstrap.cfg
file.
Gets the name of the project stack.
Returns a list of the protected deployment names.
For more information, see protect_deployment and unprotected_deployment
.
Gets the ARN of a resource group stack. If the specified resource group stack doesn't exist, raises a
HandledError
or returns
None
if optional
is
True
.
Full path to the file that stores project's settings that are kept in a source-controlled file (as opposed to project settings stored in
AWS). Typically, this is the local-projectsettings.json
file in the directory that is identified by aws_directory_path
.
When
True
, specifies that the
--no-prompt
option was passed to lmbr_aws
. This option is typically used when calling lmbr_aws
from scripts when there is no user to respond to prompts. When this option is set, the hook function should raise an error instead of prompting the user.
The path to the project's project-code
directory.
Version 1.10
349
Name
project_default_deployment project_initialized project_resource_handler_id project_settings project_stack_id project_template project_template_path protect_deployment(deployment_name) refresh_user_settings() release_deployment save_deployment_template() save_project_template()
Lumberyard Developer Guide
Cloud Gem Framework remove_deployment(deployment_name) root_directory_path save_deployment_access_template()
Description
The name of the deployment that has been designated as the default for the project, if any. See also user_default_deployment
and default_deployment
.
True
if the project has been initialized and project_stack_id
has a value;
False
otherwise.
The ARN of the
ProjectResourceHandler
Lambda function. Cloud Canvas–defined resource templates require that this value be provided as the
ProjectResourceHandler
parameter value.
A
ProjectSettings
object that contains project settings that are loaded from AWS (as opposed to the content of local_project_settings
).
The project stack ID, if the project stack has been created.
A Python object that contains the content of the project template file.
The full path to the project's projecttemplate.json
file.
Marks a deployment as protected. It requires special confirmation before you can connect debug builds of the game to protected deployments. See also unprotect_deployment
and get_protected_deployment_names
.
A function that reloads the user_settings
object from the user settings file.
The name of the deployment that has been designed as the release deployment of the project.
Removes a deployment from the project's configuration.
The full path to the Lumberyard root directory
(the
\dev
directory), which contains projectspecific directories.
Saves the current deployment_access_template object to the project's deployment-accesstemplate.json
file.
Saves the current deployment_template
object to the project's deployment-template.json
file.
A function that saves the current project_template
object to the project's projecttemplate.json
file.
Version 1.10
350
Lumberyard Developer Guide
Cloud Gem Framework
Name
user_directory_path user_settings user_settings_path
Description
deployment_access_stack_id)
Sets the ID for a deployment access stack that is being created. For more information, see finalize_deployment_stack_ids
and set_pending_deployment_stack_id
.
deployment_stack_id)
Sets the ID for a deployment stack that is being created. For more information, see finalize_deployment_stack_ids
and set_pending_deployment_access_stack_id
.
Sets the default deployment for the project.
Overridden by the value for user's default deployment if one is specified.
set_release_deployment(deployment_name)
Sets the release deployment for the project.
set_user_default_deployment(deployment_name) set_user_default_profile(profile_name)
Sets the default deployment for the user. After it is set, overrides the project default deployment.
Sets the user's default AWS credentials profile.
This does not update the user's
.aws/credentials file; the name of the default profile is saved in the
Cloud Canvas Resource Manager's user settings file.
unprotect_deployment(deployment_name) user_default_deployment user_default_profile
Reverses the action of protect_deployment
.
The name of the deployment that has been designated as the default by the current user. For more information, see project_default_deployment
and default_deployment
.
The user's default AWS profile name as read from user settings.
The full path to the user directory in the
Lumberyard cache directory. This is where userspecific configuration is stored.
A Python object that contains the contents of the user settings file.
The full path to the JSON format text file that resource manager uses to store user-specific configuration. This configuration includes default deployment and AWS credentials profile names. This path is typically the usersettings.json
file in the directory specified by user_directory_path
.
Other properties or functions of this object are internal to resource manager and should not be used.
Gem Object
The
Gem
object provides access to gem-specific configuration data. To get
Gem
object instances, use the enabled_gems
property of a
GemContext
object.
Version 1.10
351
Lumberyard Developer Guide
Cloud Gem Framework
Name
aws_directory aws_directory_exists display_name file_object name project_resources resource_group_name
Description
The full path to the gem's AWS directory.
True if the gem's AWS directory exists.
The gem display name.
A Python object that contains the contents of the gem's gem.json
file.
The name of the gem.
Project resource definitions that are inserted into the project's stack template before the template is uploaded. These definitions are read from a project-template.json
file in the gem's AWS directory.
The gem's resource group name, if any. A gem has a resource group name only if it has a resourcetemplate.json
file.
The full path to the gem's directory.
The unique ID of the gem.
root_directory uuid
Other properties or functions of this object are internal to the resource manager and should not be used.
GemContext Object
The properties and methods of the
GemContext
object provide access to the project's gem configuration.
You can get a
GemContext
object instance using the gems
property of a
Context
object.
Name Description
enabled_gems
A list containing a gem object for each gem that is enabled for the project.
Returns the gem object associated with the specified resource group, or
None
if the resource group doesn't exist or isn't associated with a gem.
By default the resource group name is the same as the gem name, but a
ResoruceGroupAlias
property can be put in the gem's
gem.json
file to override this default.
Other properties or functions of this object are internal to resource manager and should not be used.
HandledError Object
A
HandledError
object is Python
Exception
object. You can use it in a hook function to cause an expected error to be displayed to the user without producing a stack trace. In general, the resource manager considers other kinds of exceptions to be unexpected errors and might show additional debug information that users should not see for expected errors.
Version 1.10
352
Name
context hook_name hook_path
Lumberyard Developer Guide
Cloud Gem Framework
The
HandledError
class is defined in the
AWSResourceManager.errors
module (
\dev\Tools\lmbr_aws
\AWSResourceManager\errors.py
). To create an instance, see the following example.
from AWSResourceManager.errors import HandledError def my_function():
if something_is_wrong:
raise HandledError('Something is wrong.')
HookModule Object
The first argument (and the only positional argument) passed to a hook function is a
HookModule
object that represents the hook module itself. This object's properties give you access to project configuration data.
Description
Provides access to a
Context
object.
The name of the cloud gem that defines the hook module.
The full path to the cloud gem's AWS directory where the hook module is defined.
Other properties or functions of this object are internal to resource manager and should not be used.
HookContext Object
The
HookContext
object provides functionality for working with Cloud Canvas Resource Manager hooks.
You can get a
HookContext
object instance from the hooks
property of the
Context
object.
Name
call_module_handlers(module_name, handler_name, args=(), kwargs={}, deprecated=False) call_single_module_handler(module_name, handler_name, defining_module_name, args=(), kwargs={}, deprecated=False)
Description
Calls the hook function identified by handler_name
in the module identified by module_name
. Use the kwargs
parameter to pass keyword arguments to the handler function. The args
parameter can only be used if deprecated
is
True
. If deprecated
is
True
, a warning regarding the deprecated function is displayed to the user.
Calls a hook function defined by the gem or resource group that is specified by the defining_module_name
parameter. For a description of the other parameters, see call_module_handlers
.
Other properties or functions of this object are internal to resource manager and should not be used.
ProjectSettings Object
The
ProjectSettings
object manages the project configuration data that is stored in the projectsettings.json
file in the project's Amazon S3
Configuration
bucket.
Version 1.10
353
Lumberyard Developer Guide
Cloud Gem Framework
Name
get_deployment(deployment_name)
Description
Returns the configuration dictionary for the specified deployment. The dictionary contains the following keys:
DeploymentStackId
– The ARN of the deployment stack.
DeploymentAccessStackId
– The ARN of the deployment access stack.
get_deployments() get_project_default_deployment() get_release_deployment() get_resource_group_settings(deployment_name) resource-group
– The resource group configuration dictionary for the deployment.
For a description of this value, see get_resource_group_settings
.
Returns the entire configuration dictionary for deployments. The deployment name is the key.
The special deployment name
*
, which contains settings for all deployments, can be present.
For a description of the value dictionary, see get_deployment
.
Returns the default deployment for the project.
Returns the release deployment for the project.
Returns a dictionary containing the resource group configuration for the specified deployment.
The resource group name is the key. The special resource group name
*
, which contains settings for all resource groups, can be present.
Each value is a dictionary with the following key: remove_deployment(deployment_name) remove_project_default_deployment() remove_release_deployment() save() parameter
– A dictionary containing parameter values for the resource group template.
Removes the configuration for the specified deployment name. To commit this change, call save
.
Clears the default deployment for the project. To commit this change, call save
.
Clears the release deployment for the project. To commit this change, call save
.
Saves the current configuration to the Amazon S3 bucket.
Sets the default deployment for the project. To commit this change, call save
.
set_release_deployment(deployment_name)
Sets the release deployment for the project. To commit this change, call save
.
Version 1.10
354
Lumberyard Developer Guide
Cloud Gem Framework
Other properties or functions of this object are internal to resource manager and should not be used.
ResourceGroup Object
The
ResourceGroup
object encapsulates a resource group's configuration. If multiple resource group stacks for a given resource group exist, each resource group stack is associated with a single deployment.
To get
ResourceGroup
object instances, use a
ResourceGroupContext
object.
Name
add_output(logical_id, description, value, force=False) add_parameters(parameter_definitions, force=False) add_resources(resource_definitions, force=False, dependencies=None) copy_directory(source_path, relative_destination_path='.', force=False) copy_file(source_path, relative_destination_path, force=False)
Description
Adds an output value to the resource group's resource template. If force
is
False
, an existing output that has the same name is not replaced but is replaced if force
is
True
. To save the changes, call save_template
. Returns
True
if outputs are added.
Adds parameter definitions to the resource group's resource template. The parameter_definitions
parameter is a dictionary that is merged into the parameter definitions in the template. If force
is
False
, existing definitions are not replaced but are replaced if
force
is True.
To save the changes, call save_template
. Returns
True
if parameter definitions are added.
Adds resource definitions to the resource group's resource template. The resource_definitions parameter is a dictonary that is merged into the template's current
Resources
object value. If force
is
False
, existing definitions are not be replaced but are replaced if force
is
True
.
The dependencies
parameter can be a dictionary that specifies a list of values that are added to the existing resources
DependsOn
list. New resources are always added to the
AccessControl resource's
DependsOn
list even if the dependencies parameter is not specified. To save the changes, call save_template
. Returns
True
if resource definitions are added.
Copies the contents of a specified directory into the resource group's directory. If a value for relative_destination_path
is specified, the content is written into the specified subdirectory in the resource group directory. If force
is
False
, existing files are not replaced, but are replaced if force
is
True
. Returns
True
if any files are copied.
Copies a file to the resource group directory.
The relative_destination_path
parameter can contain the destination file name or a destination path and file name. If force
is
False
, existing files are not replaced but are replaced if force
is
True
.
Returns
True
if the file is copied.
Version 1.10
355
Lumberyard Developer Guide
Cloud Gem Framework
Name
create_file(relative_destination_path, initial_content, force=False) directory_path game_cpp_code_path get_pending_resource_status(deployment_name) get_stack_id(deployment_name, optional=False) get_stack_parameters(deployment_name, uploader) get_template_with_parameters(deployment) is_gem name remove_output(logical_id) remove_parameters(parameter_names)
Description
Creates a file in the resource group directory.
The relative_destination_path
parameter can contain the destination file name or a destination path and file name. The initial_content parameter should contain the initial text content for the file. If force
is False, existing files are not replaced but are replaced if force
is
True
. Returns
True
if the file is created.
The full path to the resource group directory.
The full path to the directory where the C++ code associated with the resource group should be written. This parameter is used when service API client code is generated.
Gets a dictionary that describes the resource group's pending resource status. The status is determined by comparing the configured resource definitions, Lambda code, and parameter values to the current definitions, code, and values.
Gets the resource group's stack ID for the specified deployment. If no stack exists for the resource group, raises a
HandledError
or returns
None
if optional is
True
.
Get stack parameter for the specified deployment.
The uploader
parameter must be an
Uploader object, which is used to determine the values for the
ConfigurationBucket
and
ConfigurationKey parameters.
Returns a Python object that contains the contents of the resource group's resourcetemplate.json
file. The template's default parameter values are set according to the parameter configuration for the specified deployment.
True
if the resource group is defined by a gem;
False
if the resource group is defined in the project's resource-group
directory.
The name of the resource group.
Removes an output value from the resource group's resource template. Returns
True
if the output value existed and was removed. To save the changes, call save_template
.
Removes parameter definitions from the resource group's resource template. The parameter_names parameter must be a list of the names of the parameters to remove. Returns
True
if the parameter definitions are removed.
Version 1.10
356
Lumberyard Developer Guide
Cloud Gem Framework
Name
remove_resources(resource_names) save_template() template template_path
Name
get(name, optional=False) keys() values()
Description
Removes resource definitions from the resource group's resource template. The resource_names parameter must be a list of the logical names of the resources to remove. Returns
True
if the resource definitions are removed. To save the changes, call save_template
.
Saves the current value of the template property to the resource group's resource-template.json
file.
A Python object that contains the content of the resource group's resource-template.json
file.
The full path to the resource group's resourcetemplate.json
file.
Other properties or functions of this object are internal to resource manager and should not be used.
ResourceGroupContext Object
The
ResourceGroupContext
object provides access to resource group configuration data. To get a
ResourceGroupContext
object, use the resource_groups
property of the
Context
object.
Description
Returns a
ResourceGroup
object for the specified resource group. If the resource group doesn't exist, raises a
HandledError
or none if optional
is
True
.
Returns the names of the resource groups in a list.
Returns a list of
ResourceGroup
objects.
Other properties or functions of this object are internal to resource manager and should not be used.
StackContext Object
The
StackContext
object provides a number of helper functions that are useful when working with AWS
CloudFormation stacks. To get a
StackContext
object instance, use the stack
property of the
Context object.
Name
confirm_stack_operation(stack_id, stack_description, args, pending_resource_status, ignore_resource_types = [])
Version 1.10
357
Description
Displays pending changes and prompts the user to confirm that they want to perform a stack operation.
The args
parameter should be the parsed command line arguments for the command. It is used to avoid prompting the user if the necessary
--confirm-...
options are provided.
Name
Lumberyard Developer Guide
Cloud Gem Framework create_using_template(stack_name, template_body, region, created_callback=None, capabilities=[]) create_using_url(stack_name, template_url, region, parameters=None, created_callback=None, capabilities=[]) delete(stack_id, pending_resource_status=None) describe_resources(stack_id, recursive=True, optional=False)
Description
The ignore_resource_types
parameter is a list of resource types that are not included in the list of changes shown to the user. This parameter filters changes to the
Custom::CloudGemFramework::EmptyDeployment resource.
Uses the provided template to start a stack creation operation. Displays stack events until the create operation is complete. If the value for created_callback
is not
None
, the value must be a called function that has the created stack ID as its only parameter.
Uses a template identified by a URL to start a stack creation operation. Displays stack events until the create operation is complete. If the value for created_callback
is not
None
, the value must be a called function that has the created stack ID as its only parameter.
Starts a stack delete operation and displays stack events until the delete operation is complete.
If provided, the pending_resource_status parameter specifies the resources to be deleted from an Amazon S3 bucket in preparation for deletion of the bucket itself.
To retrieve a value for this parameter, use the get_pending_resource_status
function on a
ResourceGroup
object, or use the get_pending_resource_status
function on the
StackContext
object. Preparing an S3 bucket for deletion deletes all the objects from the bucket unless the bucket specifies a
DeletionPolicy property value of
Retain
.
Uses the AWS CloudFormation describe_stack_resources
API to return a description of a stack's resources. The content of the
StackResources
structure is converted to a dictionary keyed on the resource's logical ID.
If recursive
is
True
, the descriptions of the resources in the nested stacks are also returned.
In this case the resource's logical ID has the form
<nested-stack-logical-id>
.
<nested-resourcelogical-id>
.
If the stack does not exist, a
HandledError
is raised if optional
is
False
. Otherwise, an empty dictionary is returned.
Version 1.10
358
Lumberyard Developer Guide
Cloud Gem Framework
Name
describe_stack(stack_id, optional=False) get_current_parameters(stack_id) get_current_template(stack_id) get_pending_resource_status(stack_id, new_template={}, new_parameter_values={}, new_content_paths={}) get_physical_resource_id(stack_id, logical_resource_id, expected_type=None, optional=False) get_resource_arn(stack_id, logical_resource_id) get_stack_status(stack_id) id_exists(stack_id) name_exists(stack_name, region)
Description
Returns a dictionary that contains the data returned by a call to the AWS CloudFormation describe_stacks
API. If the stack does not exist, raises a
HandledError
or returns
None
if optional is
True
.
Gets a stack's current AWS CloudFormation template parameter values.
Gets a Python object that contains the stack's current AWS CloudFormation template.
Gets a dictionary that describes a stack's pending resource status. The status is determined by comparing the configured resource definitions,
Lambda code, and parameter values to the current definitions, code, and values.
The new_template
parameter is the resource definition template to which the stack's current template will be compared.
The new_parameter_values
parameter is a dictionary of parameter values that will be compared to the stack's current parameter values.
The new_content_paths
parameter is a dictionary that maps logical resource names to a list of full directory or file paths. The paths specify where content related to each resource is stored. A resource has pending update status if any of these files have changed since the last resource status update.
Gets the physical ID of a resource in the specified stack. If expected_type
is specified, the resource type is verified to be that type. If the type returned is not the type specified, raises a
HandledError
. If the specified resource does not exist, raises a
HandledError
or returns
None
if optional
is
True
.
Gets the ARN for a resource in the specified stack.
Gets status information for the stack. This function calls the AWS CloudFormation describe_stacks
API and returns the
StackStatus property of the first entry in the
Stacks
array of the response.
Determines whether a stack with the specified ID
(ARN) exists.
Determines whether a stack with the specified name exists in the specified region.
Version 1.10
359
Lumberyard Developer Guide
Cloud Gem Framework
Name
update(stack_id, template_url, parameters={}, pending_resource_status={}, capabilities={})
Description
Starts a stack update operation and displays stack events until the update operation is complete.
If provided, the pending_resource_status parameter specifies the resources to be deleted from an S3 bucket in preparation for deletion of the bucket itself. To retrieve a value for this parameter, use the get_pending_resource_status function on a
ResourceGroup
object. Or use the get_pending_resource_status
function on the
StackContext
object. Preparing an S3 bucket for deletion deletes all the objects from the bucket unless the bucket specifies a
DeletionPolicy property value of
Retain
.
Other properties or functions of this object are internal to resource manager and should not be used.
ViewContext Object
The
ViewContext
object contains methods that produce Cloud Canvas Resource Manager output messages. Hook functions typically do not require these functions. For more information, see the source code for this object.
Uploader Object
You can use an
Uploader
object function to upload content to the project global area of the project's
Configuration
bucket. You pass
Uploader
object instances to the hook functions before_project_update
, after_project_update
, before_resource_group_update
, and after_resoruce_group_update
.
Name
context bucket key upload_content(name, content, description) upload_file(name,path) upload_dir(name, path, alternate_root = None) file_name=None, aggregated_directories=None, aggregated_content=None)
Description
The current
Context
object.
The name of the project's
Configuration
bucket.
The object name prefix that is used when naming uploaded objects.
Uploads the specified content using
key
+ '/' +
name
as the object name. A description of the upload is shown to the user.
Uploads a file using
key
+ '/' +
name
as the object name.
Uses
key
+ '/' +
name
as the base object name to recursively upload the contents of a directory. If alternate_root
is not
None
, the value specified is used as the object name prefix instead of key
.
Recursively compresses the contents of a directory into a
.zip
file. It uses
key
+ '/' +
directory-name
.zip as the object name to upload the file. The
directory-name
is the name of the directory at the end of directory_path
.
You can use the file_name
argument to override the
directory-name
.zip part of the object name.
Version 1.10
360
Lumberyard Developer Guide
Cloud Gem Framework
Name Description
The aggregated_directories
argument can be an optional dictionary that specifies the paths of additional directories whose contents are included in the
.zip
file. The keys are the path location in the
.zip
file where the content is put.
The aggregated_content
argument can be a dictionary that contains additional content to include in the
.zip
file. The keys are the path location in the
.zip
file where the content is put.
Update Hook Functions
Update hooks are implemented in a cloud gem's
Gem\
<gem-name>
\AWS\resource-manager-code
\update.py
file. If update hooks are defined in the module, the resource manager uses the parameters that are described in the
Hook Function Parameters (p. 344) section to call the following functions.
after_project_updated
The after_project_updated
hook function is called after a project stack update operation finishes successfully.
Parameter
project_uploader
Description
An
Uploader
object that you can use to upload additional data.
after_resource_group_updated
The after_resource_group_updated
hook function is called after a resource group stack update operation finishes successfully.
Parameter
deployment_name resource_group_name resource_group_uploader
Description
The name of the deployment that was updated.
The name of the resource group that was updated.
An
Uploader
object that you can use to upload additional data.
before_project_updated
The before_project_updated
hook function is called before a project stack update operation begins.
Parameter
project_uploader
Description
An
Uploader
object that you can use to upload data for the operation.
Version 1.10
361
Lumberyard Developer Guide
Cloud Gem Framework before_resource_group_updated
The before_resource_group_updated
hook function is called before a resource group stack update operation begins.
Parameter
deployment_name resource_group_name resource_group_uploader
Description
The name of the deployment being updated.
The name of the resource group being updated.
An
Uploader
object that can be used to upload additional data.
gather_writable_check_list
The gather_writable_check_list
hook function is called before an update operation to gather a list of writable files. If any of the local files to be updated are read-only, the resource manager gives the user an opportunity to make the files writable (for example, with a source control system).
Parameter
check_list
Description
A list of the full paths of writeable files.
Command Hook Functions
If the following command line hook functions exist in a module, they are defined in a cloud gem's
Gem
\
<gem-name>
\AWS\resource-manager-code\command.py
file. The resource manager uses the parameters in the
Hook Function Parameters (p. 344)
section to call the following functions.
add_cli_commands
Adds additional commands to the command line parser. Called before command line argument parsing.
Cloud Canvas Resource Manager uses the Python argparse
module for command line parsing. All commands are grouped into a number of different subparsers. For example, the commands lmbr_aws project list-resources
and lmbr_aws deployment list
contain the subparsers project
and deployment
, which define a list-resources
and list
command, respectively.
Parameter
subparsers add_common_args
Description
The subparser
collection object returned by the argparse add_subparsers
function. Use the hook function to add a subparser to the collection.
Then, add the commands to the subparser.
Adds a set of common arguments to a command.
This function adds the following arguments. For a description of these arguments, see
Cloud Canvas Command Line (p. 435)
.
--aws-access-key
--aws-secret-key
--profile
--assume-role
Version 1.10
362
Lumberyard Developer Guide
Cloud Gem Framework
Parameter Description
--root-directory
--game-directory
--aws-directory
--user-directory
--verbose
--no-prompt
The common arguments are processed by lmbr_aws
. The hook does not typically process these options.
This function can take the following parameters: parser
– The argparse
defined parser object to which the arguments are added.
no_assume_role
–
True
specifies that the
-assume-role
common argument is not added;
False
specifies that it is.
add_cli_view_commands
Adds additional methods to the
ViewContext
object. Called before other command line commands.
Parameter
view_context
Description
A
ViewContext
object.
add_gui_commands
Adds commands to the Cloud Canvas Resource Manager in Lumberyard Editor. When the resource manager window is first opened, Lumberyard Editor initializes the resource manager Python subsystem, which calls add_gui_commands
.
Parameter
handlers
Description
A dictionary that maps user interface command names to the handler functions that process them. The command names are passed to Python from the user interface.
add_gui_view_commands
Adds additional methods to the
ViewContext
object. Called before a GUI command is executed.
Parameter
view_context
Description
A
ViewContext
object.
Version 1.10
363
Lumberyard Developer Guide
Cloud Gem Framework
The Cloud Gem Framework and this documentation are in preview release and are subject to change.
The Cloud Gem Framework Gem provides C++ classes that can execute any C++ AWS API call by using the Lumberyard job execution system. This allows the operation to be performed on background threads that are managed by the job system.
To use AWS API Jobs in your project
1. In Lumberyard Project Configurator , enable the
Cloud Canvas Common
and
Cloud Gem Framework
gems for your project.
2. We recommend that you put the code that uses AWS in a gem, but this is not required. If you do use a gem, make the
Cloud Gem Framework
and
Cloud Canvas Common
gems dependencies of your gem by adding the following to your gem's gem.json
file.
"Dependencies": [
{
"Uuid" : "6fc787a982184217a5a553ca24676cfa",
"VersionConstraints": [ "~>0.1" ],
"_comment": "
CloudGemFramework
"
},
{
"Uuid" : "102e23cf4c4c4b748585edbce2bbdc65",
"VersionConstraints": [
"~>0.1"
],
"_comment": "
CloudCanvasCommon
"
}
],
3. Activate your gem for your project.
4. In your gem or game project's
.wscript
file, make the following changes: a. To the list of includes, add: bld.Path('Code/SDKs/AWSNativeSDK/include') b. To the list of used static libraries, add
CloudGemFrameworkStaticLibrary
.
c.
Add
AWS_CPP_SDK_CORE
and other AWS API dynamic libraries as required. For a list of available aliases like
AWS_CPP_SDK_LAMBDA
and other library names, see the dev\_WAF_\3rd_party
\aws_native_sdk_shared.json
file.
d. Add the security libraries for platforms other than Windows, as in the following
.wscript
file for a gem.
SUBFOLDERS = [] def build(bld):
import lumberyard_sdks
bld.DefineGem(
includes = [bld.Path('Code/SDKs/AWSNativeSDK/include')],
file_list = ['cloudcanvassample.waf_files'],
use = ['CloudGemFrameworkStaticLibrary'],
uselib = ['AWS_CPP_SDK_CORE', 'AWS_CPP_SDK_LAMBDA'],
Version 1.10
364
Lumberyard Developer Guide
Cloud Gem Framework
darwin_lib = ['curl'],
linux_lib = ['curl'],
ios_lib = ['curl'],
appletv_lib = ['curl'],
durango_lib = ['msxml6'],
ios_framework = [ 'security' ],
appletv_framework = [ 'security' ]
)
bld.recurse(SUBFOLDERS)
5. Include the
CloudGemFramework\AwsApiJob.h
header and the AWS SDK header files that are required for calling an API, as in the following example:
#include <CloudGemFramework/AwsApiRequestJob.h>
#pragma warning(disable: 4355) // <future> includes ppltasks.h which throws a C4355
warning: 'this' used in base member initializer list
#include <aws/lambda/LambdaClient.h>
#include <aws/lambda/model/InvokeRequest.h>
#include <aws/lambda/model/InvokeResult.h>
#include <aws/core/utils/Outcome.h>
#include <aws/core/utils/memory/stl/AWSStringStream.h>
#pragma warning(default: 4355)
6. Using code similar to the following, run an AWS API job. An alternative approach is to extend the job class (like
LambdaInvokeRequestJob
in the example) and provide overrides for the
OnSuccess
and
OnFailure
methods.
using LambdaInvokeRequestJob = AWS_API_REQUEST_JOB(Lambda, Invoke); auto job = LambdaInvokeRequestJob::Create(
[](LambdaInvokeRequestJob* job) // OnSuccess handler - runs on job thread
{
Aws::IOStream& stream = job->result.GetPayload();
std::istreambuf_iterator<AZStd::string::value_type> eos;
AZStd::string content =
AZStd::string{std::istreambuf_iterator<AZStd::string::value_type>(stream),eos};
AZ_Printf("Example", "Got response %s", content.c_str());
},
[](LambdaInvokeRequestJob* job) // OnError handler (optional) - runs on job thread
{
AZ_Printf("Example", "Was error %s", job->error.GetMessageA().c_str());
}
);
AZStd::string content = "..."; std::shared_ptr<Aws::StringStream> stream = std::make_shared<Aws::StringStream>();
*stream << content.c_str(); job->request.SetFunctionName("..."); job->request.SetBody(stream); job->Start();
7. If your project uses the
Cloud Canvas Resource Manager
, get the physical resource ID and the logical resource ID of the AWS resource for each resource group. These IDs cause your AWS API call to use the correct resource for the active deployment. This ensures that your development, test, and released versions of a game don't interfere with each other.
#include <CloudCanvasCommon/CloudCanvasCommonBus.h>
AZStd::string functionName;
Version 1.10
365
Lumberyard Developer Guide
Cloud Gem Framework
EBUS_EVENT_RESULT(functionName, CloudCanvasCommon::CloudCanvasCommonRequestBus,
GetLogicalToPhysicalResourceMapping, "RESOURCE-GROUP.RESOURCE"); job->request.SetFunctionName(functionName.c_str());
8. If your project uses the
Cloud Canvas Resource Manager
, the AWS API is called using the player's
AWS credentials. These credentials are provided by the anonymous Amazon Cognito Identitypool that Cloud Canvas creates for your project. If you do not use
Cloud Canvas Resource Manager
or want to use other credentials, you can use code like the following to override the default configuration.
#include <aws/core/auth/AWSCredentialsProvider.h>
LambdaInvokeRequestJob::Config config(LambdaInvokeRequestJob::GetDefaultConfig()); const char* accessKey = "..."; const char* secretKey = "..."; config.credentialsProvider =
std::make_shared<Aws::Auth::SimpleAWSCredentialsProvider>(accessKey, secretKey); config.requestTimeoutMs = 20000; auto job = LambdaInvokeRequestJob::Create(
..., // OnSuccess handler
..., // OnError handler
&config
);
The CloudGemAWSScriptBehaviors Gem uses the behavior context to expose some useful AWS services to script, including Amazon API Gateway , AWS Lambda , and Amazon S3 . It also provides some supporting utilities. The
\dev\CloudGemSamples\Scripts
directory has sample Lua code for each reflection. To try the samples, run the AWSBehaviorExamples level in the CloudGemSamples project.
API Service
API service behavior context reflections include a class and EBus that interact with Amazon API Gateway.
AWSBehaviorAPI Class
Calls methods that are exposed through the Amazon API Gateway service. The class properly signs requests with appropriate credentials in an HTTP request. The class translates the logical resource names in Cloud Canvas to physical names. This makes the class easy to use with other cloud gems.
Properties
Property
string HTTPMethod string Query string ResourceName
Description
Specifies the HTTP method that calls the API. This string
is API specific.
Valid strings are:
GET
,
POST
,
DELETE
,
PUT
, and
PATCH
.
A standard URL query string
that passes parameters to the API. This string
is only the query and function portion of the URL and has the format player/messages?time=now&lang=eng
.
Specifies the logical resource name of the API to call. Accepts only API
Gateway resource names. Returns an error if other resource types are specified.
Version 1.10
366
Lumberyard Developer Guide
Cloud Gem Framework
Methods
Method
void Execute()
Description
Performs the HTTP request with the specified properties.
AWSBehaviorAPINotificationsBus
The
AWSBehaviorAPINotificationsBus
has the following methods.
Methods
Method Description
Called when the request returns a response.
The responseCode
parameter contains the HTTP response code; the responseData
parameter contains the response data, which is often a
JSON string.
void OnError(string requestBody) void OnSuccess(string resultBody)
Called when the API call fails. The requestBody parameter contains the request body.
Called when the API call succeeds. The resultBody
parameter contains the request response body.
Lambda Service
Lambda service behavior context reflections include a class and EBus that interact with AWS Lambda.
AWSLambda Class
Invokes an AWS Lambda function.
Properties
Property
string functionName string requestBody
Description
The logical function name in Cloud Canvas that you want to invoke.
Optional. Specifies request parameters to pass to the Lambda invocation.
Methods
Method
void InvokeAWSLambda()
Description
Invokes the specified Lambda function.
AWSLambdaHandler
The
AWSLambdaHandler
EBus has the following methods.
Version 1.10
367
Lumberyard Developer Guide
Cloud Gem Framework
Methods
Method
void OnError(string errorBody) void OnSuccess(string resultBody)
Description
Called when the Lambda invocation fails. The errorBody
parameter contains the information that was returned in the Lambda error response.
Called when the
Lambda
invocation succeeds. The resultBody
parameter contains the information that was returned by the Lambda function, if any.
S3 Service
S3 behavior context reflections include classes and EBuses that interact with Amazon S3.
AWSBehaviorS3Upload Class
Uploads a local file to an Amazon S3 bucket.
Properties
Property
string bucketName string contentType string keyName string localFileName
Description
Specifies the logical name in Cloud Canvas for the destination Amazon S3 bucket.
Specifies the MIME file type of the file to be uploaded.
Specifies the destination key for the file. The destination key is the file name that appears in Amazon S3 and must be unique to the bucket.
Specifies the fully qualified path name of the local file to be uploaded.
Methods
Method
void Upload()
Description
Uploads the file with the specified properties.
AWSBehaviorS3UploadNotificationsBus
The
AWSBehaviorS3UploadNotificationsBus
has the following methods.
Methods
Method
void OnError(string errorBody) void OnSuccess(string resultBody)
Description
Called when the file upload fails. The errorBody parameter contains the error information returned by
Amazon S3, if any.
Called when the file upload succeeds. The resultBody parameter contains the information that is returned by
Amazon S3, if any.
Version 1.10
368
Lumberyard Developer Guide
Cloud Gem Framework
AWSBehaviorS3Download Class
Downloads a file from an Amazon S3 bucket to the local file system.
Properties
Property
string bucketName string keyName string localFileName
Description
Specifies the logical name in Cloud Canvas for the
Amazon S3 source bucket.
Specifies the key name (the file name) of the
Amazon S3 source file.
Specifies the fully qualified path of the location to which the downloaded file is written.
Methods
Method
void Download()
Description
Downloads the file with the specified properties.
AWSBehaviorS3DownloadNotificationsBus
The
AWSBehaviorS3DownloadNotificationsBus
has the following methods.
Methods
Method
void OnError(string errorBody) void OnSuccess(string resultBody)
Called when the file download fails. The errorBody
parameter contains error information returned by Amazon S3.
Called when the file download succeeds. The resultBody parameter contains information returned by Amazon S3.
AWSBehaviorS3Presign Class
Provides a presigned URL for a specified Amazon S3 file. This is a URL that can be shared that allows authenticated access to the specified file.
Properties
Property
string bucketName string keyName string requestMethod
Description
Specifies the logical name in Cloud Canvas for the target S3 bucket.
Specifies the key name (the file name) of the target Amazon S3 file.
The HTTP method to generate for the URL. Valid strings are
PUT
,
POST
,
DELETE
, and
GET
.
Version 1.10
369
Lumberyard Developer Guide
Cloud Gem Framework
Methods
Method
void Presign()
Description
Gets a presigned URL for the specified Amazon S3 file.
AWSBehaviorS3PresignNotificationsBus
The
AWSBehaviorS3PresignNotificationsBus
has the following methods.
Methods
Method
void OnError(string errorBody) void OnSuccess(string resultBody)
Description
Called when the operation fails. The errorBody parameter contains error information returned by
Amazon S3.
Called when the operation succeeds. The resultBody
parameter contains the presigned URL returned by Amazon S3.
Utilities
Utility classes and EBuses provide functionality for HTTP, JSON, URL, and string operations.
AWSBehaviorHTTP Class
The
AWSBehaviorHTTP
class implements a simple general-purpose HTTP
GET
request. You can use the class to get any webpage or presigned URL.
Properties
Property
string URL
Description
The URL to get.
Methods
Method
void Get()
Description
Gets the URL specified by the
URL
property.
AWSBehaviorHTTPNotificationsBus
The
AWSBehaviorHTTPNotificationsBus
has the following methods.
Methods
Method
void OnSuccess(string resultBody)
Description
Called when the
GET
operation succeeds. The resultBody
parameter contains the request response body.
Version 1.10
370
Lumberyard Developer Guide
Cloud Gem Framework
Method
void OnError(string errorBody) void GetResponse(int responseCode,
StringMap headerMap, string contentType, string responseBody)
Description
Called when the
GET
operation fails. The errorBody
parameter contains the error body.
Called when the request returns a response. The parameters contain the following information: responseCode
– The HTTP response code.
headerMap
– Contains all the header information.
It can be passed to a StringMap (p. 373)
map property.
contentType
– Contains the MIME content type for the response data.
responseBody
– Contains the response data in string format.
JSON Class
Traverses and parses JSON data. This class reads but does not write JSON data. To write JSON data, use the string utilities provided in the language that you are using.
Some languages do not provide iterator support for JSON. To accommodate these languages, the
JSON class maintains a current value state that gets updated as it traverses the tree of JSON data. Because
JSON data consists of objects and arrays, the current value is either the value of the current object key or the value at the current position in the array. For examples, see the sample code in the
\dev
\CloudGemSamples\Scripts\AWSBehaviorJSONTest.lua
file.
The
JSON
class has no properties. The following table lists its methods.
Methods
Method
int EnterArray()
Description
If the current value is an array, sets the current value to the first element of the array and returns the number of array elements.
void EnterObject(string key) void ExitArray() void ExitCurrentObject()
If the current value is an object, sets the current value to the value of the specified key.
If the current value was set by using
EnterArray
, sets the current value to the array that was entered before the call to
EnterArray
.
If the current value was set by using
EnterObject
, sets the current value to the object that was entered before the call to
EnterObject
.
Loads the JSON object from a JSON string. Parsing errors are logged to the console.
boolean GetBoolean() double GetDouble()
If the current value is a Boolean, returns the value of the Boolean. If the current value is not a Boolean, returns false.
If the current value is a double, returns the value of the double. If the current value is not a double, returns 0.
Version 1.10
371
Lumberyard Developer Guide
Cloud Gem Framework
Method
integer GetInteger() string GetString() boolean IsArray() boolean IsBoolean() boolean IsDouble() boolean IsInteger() boolean IsObject() boolean IsString() void LogToDebugger() boolean NextArrayItem() string ToString()
Description
If the current value is an integer, returns the value of the integer. If the current value is not an integer, returns 0.
If the current value is a string, returns the value of the string. If the current value is not a string, returns an empty string.
Returns true only if the current value is an array.
Returns true only if the current value is a Boolean.
Returns true only if the current value is a double.
Returns true only if the current value is an integer.
Returns true only if the current value is an object.
Returns true only if the current value is a string.
Displays the entire JSON object in the console in human readable format.
Sets the current value to the next element of the array. If the current element is the last element in the array, returns false.
Returns the entire JSON object as a string.
The JSON class has no corresponding EBus.
AWSBehaviorURL Class
The
AWSBehaviorURL
class provides "URL decode" functionality. It removes any escape characters from the specified URL and returns the resulting string.
Properties
Property
string URL
Description
The URL to decode.
Methods
Method
void Decode()
Description
Decodes the specified URL.
AWSBehaviorURLNotificationsBus
The
AWSBehaviorURLNotificationsBus
has the following methods.
Methods
Method
void OnError(string error)
Description
Called if the URL was not successfully decoded. The error parameter contains the reasons for the failure.
Version 1.10
372
Lumberyard Developer Guide
Cloud Gem Framework
Method Description
void OnSuccess(string result)
Called if the URL was successfully decoded. The result
parameter contains the decoded string.
StringMap Class
A simple mapping of string key–value pairs. The
StringMap
class is most often used with the HTTP
Get class but is useful for general string map operations.
Properties
Property
map
Description
Contains a string map that was received from another method for parsing.
Methods
Method
void Clear() int GetSize()
Description
Removes all key–value pairs from the map.
Returns the number of key–value pairs currently stored in the map.
string GetValue(string key) boolean HasKey(string key)
Returns the value at the specified key. If the key that was specified doesn't exist, returns an empty string without adding the key to the map.
Returns true if the map contains the specified key.
Displays all key–value pairs in the console.
void LogToDebugger() void RemoveKey(string key)
Removes the key–value pair from the map that corresponds to the specified key. If the specified key does not exist, fails without returning an error.
Sets the value of the specified key to the specified value.
If the key doesn't exist, the key–value pair is added to the map. If the key does exist, its existing value is overwritten with the specified value.
The
StringMap
class has no corresponding EBus handlers.
This documentation is preliminary and is subject to change.
Lumberyard cloud gems provide services like the
(CGP) that configure and manage a game's operation. The services are implemented by AWS Lambda function resources. The game and tools access these services through the Amazon API Gateway . The code that you provide runs in a Lambda function. API Gateway manages access to the service, provides caching for frequently used results, and supports request throttling.
Version 1.10
373
Lumberyard Developer Guide
Cloud Gem Framework
The following diagram shows how the Cloud Gem Framework service API interacts with the game client, the Cloud Gem Portal, AWS Lambda, and API Gateway.
Cloud Gem Swagger API Descriptions
The Lumberyard game engine and tools use API operations to communicate with your cloud gem service. These APIs are described in the cloud gem's
/dev/Gems/
<gem-name>
/AWS/swagger.json
file.
The swagger.json
file uses the swagger API definition format , which is an open source framework for
RESTful API operations.
Cloud Canvas uses these API descriptions to generate Lumberyard engine components that execute
when it makes service requests. In addition, the API descriptions are used to configure API Gateway to work with your service.
Topics
•
•
•
•
Cloud Gem Framework Extension Object (p. 381)
•
•
Generated Game Client Code Example (p. 384)
•
•
Version 1.10
374
Lumberyard Developer Guide
Cloud Gem Framework
Resources
A cloud gem's service API is implemented based on the resources that are defined in the cloud gem's resource-template.json
file. The following are the key resources for a cloud gem:
•
ServiceAPI
– An AWS CloudFormation custom resource provided by the Cloud Gem Framework. The handler for this resource configures API Gateway to use the cloud gem's swagger.json
file.
•
ServiceLambda
– An AWS Lambda function that implements the cloud gem's functionality.
•
ServiceLambdaConfiguration
– An AWS CloudFormation custom resource provided by Cloud Canvas
Resource Manager that configures (p. 324)
the
ServiceLambda
resource.
To add definitions for these resources to a resource-template.json
file, type the following command.
lmbr_aws cloud-gem-framework add-service-api-resources --resource-group
<gem-name>
In addition to adding the resources mentioned, the add-service-api-resources
command does the following:
• Adds a swagger.json
file to the cloud gem's AWS directory, if one doesn't already exist.
• Adds the
ServiceAPI
and
ServiceLambda
resources to the
AccessControl
resource definition's
DependsOn
property. This insures that the
AccessControl
resource is processed by AWS
CloudFormation after the
ServiceAPI
and
ServiceLambda
resources have been processed.
To use the service API resources that you add to a resource-template.json
file, you must upload those resources to AWS. To upload them, you can use the lmbr_aws resource#group upload
command, the lmbr_aws deployment upload
command, or click
Upload Resources
in the
Resource Manager
feature in
Lumberyard Editor.
Custom::CloudGemFramework::ServiceApi Resource
The handler for the
Custom::CloudGemFramework::ServiceApi
AWS CloudFormation resource is provided by the Cloud Gem Framework. This handler creates, updates, and deletes API Gateway REST API, operation, deployment, and stage resources as needed.
ServiceApi
resource definitions accept the following parameters:
{
"Resources": {
...
"ServiceApi": {
"Type": "Custom::CloudGemFramework::ServiceApi",
"Properties": {
"ServiceToken": { "Ref": "ProjectResourceHandler" },
"ConfigurationBucket": { "Ref": "ConfigurationBucket" },
"ConfigurationKey": { "Ref": "ConfigurationKey" },
"CacheClusterSize": { "Ref": "ServiceApiCacheClusterSize" },
"CacheClusterEnabled": { "Ref": "ServiceApiCacheClusterEnabled" },
"MethodSettings": { ... },
"SwaggerSettings": {
"ServiceLambdaArn": { "Fn::GetAtt": [ "ServiceLambda", "Arn" ] }
}
},
...
ServiceToken
Identifies the Lambda function that implements the custom resource handler.
Version 1.10
375
Lumberyard Developer Guide
Cloud Gem Framework
ConfigurationBucket
Identifies the bucket that contains the uploaded swagger.json
file.
ConfigurationKey
Identifies the location in the bucket where the swagger.json
file is uploaded.
CacheClusterSize
Provides the API Gateway cacheClusterSize value when you create or update the API Gateway stage.
CacheClusterEnabled
Provides the API Gateway cacheClusterEnabled value when your create or update the API Gateway stage.
MethodSettings
Not implemented.
SwaggerSettings
Provides values that you insert into the uploaded swagger.json
file before it is passed to API
Gateway. For example, you can use
$ServiceLambdaArn$
in the swagger.json
file to insert the value of the
SwaggerSettings ServiceLambdaArn
property.
The following settings are automatically defined for you:
ResourceGroupName
The name of the resource group that is defined the
ServiceApi
resource.
DeploymentName
The name of the deployment that the
ServiceApi
resource is in.
RoleArn
The ARN of the role that grants API Gateway the permission to invoke the
ServiceLambda
(or other
permissions configured by the Cloud Canvas Resource Manager Security System (p. 420)
).
Region
The AWS region where the RESTful API resides.
RestApiResourceName
The name to use for the API Gateway REST API resource. API Gateway takes this value from the swagger infoObject title
property (set to
$RestApiResourceName$
in the default swagger.json
file). This is the stack name of the resource group with the
ServiceApi
logical resource ID appended
(usually
-ServiceApi
).
Operations
A cloud gem's service API can implement multiple distinct operations. You define operations in the swagger.json
file by adding operationObject
instances to a pathItemObject
. For each operation, you can define the input data that the operation requires and the output data that it produces. The input data can include path, query, and body parameters. For more information on using swagger to define
APIs, see http://swagger.io/ .
API Gateway routes API requests to the cloud gem's Lambda function. When you upload the cloud gem's resources to AWS, the cloud gem's swagger.json
file is processed. This processing creates the
Version 1.10
376
Lumberyard Developer Guide
Cloud Gem Framework request and response mappings that API Gateway uses to call the cloud gem's Lambda function. This
configuration is controlled by the x-amazon-cloud-canvas-lambda-dispatch
in the swagger.json
file.
Service API operations are implemented in the
ServiceLambda
AWS Lambda function resource. The code for the Lambda function comes from the cloud gem's lambda-function-code
directory. The
Cloud Gem Framework provides a service request dispatch module. For more information, see
.
The following diagram illustrates both request and upload processing.
Topics
•
Default Request Mapping (p. 377)
•
Default Response Mapping (p. 378)
•
Default Request Mapping
A JSON object that implements the request operation is sent to the Lambda function. The JSON object contains the module and function name and the operation's parameters, as the following skeletal syntax shows.
{
"module": "
<module-name>
",
"function": "
<function-name>
",
"parameters": {
"
<parameter-name>
":
<parameter-value>
,
...
}
}
The default module name is derived from the operation path. A path like
/player/
{id}
/highscores results in a module name like player_highscores
. Parameters in the path are skipped. The paths
/ player
and
/player/
{id}
both map to the module name player
. In this case the handler function in that
Version 1.10
377
Lumberyard Developer Guide
Cloud Gem Framework module can use the existence of an id
parameter value to determine the corresponding behavior. The path
/
(and
/{param}
) are mapped to the module name root
.
The default function name is the operation name like
GET
,
POST
, or
PUT
.
These defaults can be overridden by specifying the module and/or function properties of an x-amazoncloud-canvas-lambda-dispatch
extension object. For more information, see Cloud Gem Framework
Parameter names are taken from the parameter definitions in the swagger.json
file. Path, query, and body parameter types are supported.
Default Response Mapping
The Lambda function returns the value to the client as a JSON object such as the following.
{
"result":
<lambda-return-value>
}
If the Lambda function exits with an error (for example, by raising an unhandled exception), it returns the
JSON object in the following format.
{
"errorMessage":"
<error-message>
",
"errorType":"
<error-type>
"
}
If the error message received from the Lambda function starts with the text
Client Error:
, then an
HTTP
400
response is sent to the client. The errorMessage
and errorType
properties received from the Lambda function are forwarded to the client.
If the error message received from the Lambda function does not start with
Client Error:
, or no error message is received at all, an
HTTP 500
response is sent to the client. As a security measure, the errorMessage
returned to the client is always
An internal server error has occurred
, and errorType
is
ServiceError
. This is to avoid sending the exception message to the client. Doing so could provide information that could allow an attacker to discover exploits in your service implementation.
In both the
HTTP 400
and
HTTP 500
cases, no other information (such as a stack trace) is sent to the client; this also is a security measure.
Request Execution
The Cloud Gem Framework has built-in support for service API Lambda functions that are implemented in Python. No built-in support is provided for Node.js or Java Lambda functions. To support these languages, implement the Lambda function handler to look for the module
and function
properties on the event object that the Lambda function provides. You also might need to override the default values generated for the
x-amazon-cloud-canvas-lambda-dispatch
module
and function
properties during the swagger.json
file processing.
A service.py
module file is provided for you in the service's AWS Lambda function. This module's dispatch
function uses the module
and function
properties of the event
object to dispatch the request to the service code that you provide. These properties are set by the request mapping that configures API
Gateway.
Place your service code in your resource group's lambda-function-code\api
directory. The dispatcher uses importlib.import_module
to load the modules from that directory. If the specified function has the
@service.api
decorator, the dispatcher invokes the function on that module, as in the following example.
Version 1.10
378
Lumberyard Developer Guide
Cloud Gem Framework import service
@service.api
def post(
request
, submission, user_id):
...
The first argument passed to the function is a dispatch.Request
object. The request
object has the following properties.
•
event
– The event object that AWS Lambda passes to the dispatch handler. The contents of the object are determined by the request template. Additional properties added to the template through the xamazon-cloud-canvas-lambda-dispatch
object's additional-request-template-content
property are also located here.
•
context
– The Python context object that AWS Lambda passes to the dispatch handler.
The request object's parameters are passed to the handler function as keyword arguments (that is, by using Python
**parameters
).
Error Handling
A
ClientError
class is provided in the errors.py
file. This class extends
RuntimeException
and ensures that the error message is prefixed with
Client Error:
. This triggers an
HTTP 400
response from API
Gateway as described in Default Response Mapping (p. 378) .
If other exceptions are raised during processing, a generic
Internal Service Error
message is sent to the client.
Security
When you make APIs available on the Internet, you must be concerned with security. A best practice is to limit API access to only the people who require it. However, some APIs must be called by the game client.
These APIs can be called by any game player or potentially anyone on the Internet.
For all APIs, consider the following:
• Use the access control mechanism described in the next section to limit API access to only those who require it.
• Don't trust parameter values provided by the client. Verify that the parameter values match expectations before you use them. Be careful when inserting parameter values into query strings that are sent to DynamoDB or other services. For more information, see code injection .
• API Gateway automatically protects your backend systems from distributed denial-of-service (DDoS) attacks, whether attacked with counterfeit requests (Layer 7) or SYN floods (Layer 3). However, this does not protect from less frequent requests that do not trigger API Gateway's protections. These other requests might still have a significant impact on your operating costs due to excessive I/O or on game performance.
Access Control
Configuring access control for a service API involves setting three distinct sets of permissions:
1. The execute-api
operation, enforced by API Gateway.
Version 1.10
379
Lumberyard Developer Guide
Cloud Gem Framework
2. The Lambda
Invoke
function, enforced by AWS Lambda
3. Access to the cloud gem resource, enforced by the resource's AWS service (for example, Amazon
DynamoDB or Amazon S3.)
In all three cases, you use the Cloud Canvas Resource Manager Security (p. 420)
system to configure access. This involves putting
Permissions
metadata on the
ServiceApi
and
ServiceLambda
resource definitions, as well as on the definitions of resources accessed by the
ServiceLambda
code. This is illustrated in the following diagram:
The permissions granted by
ServiceApi
are described in detail in the next section.
ServiceLambda gives
ServiceApi
permission to invoke the Lambda function. Other resources give
ServiceLambda
the permissions that the Lambda function requires.
Service API Permissions
You can secure service API operations on an individual basis. For example, you could give permission to submit high scores to the game, and permission to delete fraudulent high scores to someone who manages operations.
By default, only valid AWS IAM credentials can execute operations. This is done using swagger security requirement and security definitions
configure API Gateway to use other forms of security, or none at all, by putting security objects in swagger object definitions in your swagger.json
file.
To grant permission to execute an operation, modify your resource-template.json
file to include metadata on the
ServiceApi
resource definition, as in the following example.
{
"Resources": {
...
"ServiceApi": {
"Type": "Custom::CloudGemFramework::ServiceApi",
"Properties": { ... },
"Metadata": {
"CloudCanvas": {
"Permissions": [
Version 1.10
380
Lumberyard Developer Guide
Cloud Gem Framework
{
"AbstractRole": [ "ProjectOwner", "DeploymentOwner" ],
"Action": "execute-api:*",
"ResourceSuffix": "/*"
},
{
"AbstractRole": "Player",
"Action": "execute-api:Invoke",
"ResourceSuffix": "/*/POST/score/*"
},
{
"AbstractRole": "DevOps",
"Action": "execute-api:Invoke",
"ResourceSuffix": "/*/DELETE/score/*"
}
]
}
}
}
...
}
The
AbstractRole
property determines who has permission to call the API. Cloud Canvas has built in
Player
,
ProjectOwner
, and
DeploymentOwner
roles. You can create others as required. The abstract
role specified here is mapped to an actual AWS IAM role using metadata on the role definitions. For details,
see Understanding the Resource Manager Security System (p. 420)
.
The
Action
and
ResourceSuffix
are used by the Cloud Canvas Resource Manager access control to generate an AWS IAM policy document statement. This process is described in Statement Reference of
IAM Policies for Executing API in API Gateway .
The
Action
property determines what the permission allows someone to do. When you grant permissions to the
Player
abstract role, specify the permission execute-api:Invoke
. This gives the player permission to invoke the API. When you grant permissions to the
ProjectOwner
and
DeploymentOwner
abstract roles, specify the permission execute-api:*
. This grants permission to invoke the API and manage the API's cache. For other roles, use your own requirements to determine whether to grant a role permission to manage the cache, invoke the API, or both.
The access control system calculates the ARN of the API Gateway REST API resource to which the action can be applied. The
ResourceSuffix
property from the
Permission
metadata provides only the / stagename
/
HTTP-VERB
/ resources-path-specifier
part of the ARN described in the Statement Reference of
IAM Policies for Executing API in API Gateway .
For
ServiceAPI
, the stage-name
is always api
. You can specify either
/api/...
or
/*/...
in the
ResourceSuffix
property value. A
ResourceSuffix
value of
/api/*
or
/*
grants permissions for all operations on all paths of the service API.
Cloud Gem Framework Extension Object
The swagger specification allows tools like the Cloud Gem Framework and API Gateway to define extension objects . These objects allow the swagger.json
file to provide custom configuration data for the tool. The extension object that the Cloud Gem Framework uses is x-amazon-cloud-canvas-lambdadispatch
. This extension object simplifies the configuration of API Gateway for use with an AWS Lambda function.
You can place the x-amazon-cloud-canvas-lambda-dispatch
object in any of the following swagger objects.
• swagger object – Sets the defaults for all paths and operations.
• path item object – Sets the defaults for all the path's operations and overrides the defaults set on the parent swagger object.
Version 1.10
381
Lumberyard Developer Guide
Cloud Gem Framework
• operation object – Sets values for the operation and overrides the defaults set on the parent path and swagger objects.
The x-amazon-cloud-canvas-lambda-dispatch
object supports the following properties:
•
lambda
– The ARN of the Lambda function that the operation invokes.
•
module
– The name of the module that defines the service function that processes the request.
•
function
– The name of the function that processes the request. The dispatch module in the Lambda function uses the function
property and the module
property to call your code when it receives a request. The dispatch module is described in the
Upload Processing (p. 382) section that follows.
•
additional-properties
– An object that provides properties that are added to the generated xamazon-apigateway-integration
object described in the next section.
•
additional-request-template-content
– A string that is inserted into the generated application/ json request template , which is described in the next section.
•
additional-response-template-content
– An object that specifies additional content that is inserted into the generated application/json response template . This template is described in the next section. Properties named
200
,
400
, and
500
are supported. These correspond to the successful (200) and error (400 and 550) responses.
See the API Gateway documentation for more information about mapping templates .
Upload Processing
Before the swagger.json
file is uploaded to API Gateway, the x-amazon-cloud-canvas-lambda-dispatch extension objects in the file are processed. This produces the x-amazon-apigateway-integration extension objects that configure API Gateway to call your cloud gem's AWS Lambda function.
The x-amazon-cloud-canvas-lambda-dispatch
object and processing hide a lot of the complexity, and flexibility, of the x-amazon-apigateway-integration
extension object. The Cloud Gems Framework provides a straightforward and recommended mapping to the API operations that are implemented in Lambda functions. API Gateway offers many other features that can be extremely useful when you must match an API that was implemented elsewhere or use API Gateway as a proxy for existing backend implementations.
You can still use all the power of the x-amazon-apigateway-integration
object in your cloud gem API operations. If you include the object in the operation objects of your swagger.json
file, the processing described here is skipped for the operation.
Note
You can also use the lmbr_aws cloud-gem-framework service-api-process-swagger
command to process the swagger.json
file.
At minimum, the swagger object can include an x-amazon-cloud-canvas-lambda-dispatch
object with a Lambda property. You can allow the module and function for each operation be determined automatically, or you can use x-amazon-cloud-canvas-lambda-dispatch
objects to specify them.
The default swagger.json
file provided by the Cloud Gem Framework contains the following xamazon-cloud-canvas-lambda-dispatch
object. The string
$ServiceLambdaArn$
is replaced with the
ServiceLambdaArn SwaggerSettings
property value provided in the
ServiceApi
resource definition.
"x-amazon-cloud-canvas-lambda-dispatch": {
"lambda": "$ServiceLambdaArn$"
}
When the swagger.json
file is processed, an x-amazon-apigateway-integration
object is added to every swagger operation object that does not have one. These objects have the following properties:
Version 1.10
382
Lumberyard Developer Guide
Cloud Gem Framework
•
type
– Specify
AWS
to enable AWS Lambda function integration.
•
uri
– Construct the URI of the Lambda function with the value of the x-amazon-cloud-canvaslambda-dispatch
object's lambda
property.
•
credentials
– The
Custom::CloudGemFramework::ServiceApi
resource creates the ARN of a role. The role has a policy that is described in
.
•
requestTemplates
– A application/json
template that causes a request as described in
. You can include additional content by using the x-amazon-cloud-canvaslambda-dispatch
object's additional-request-template-content
property. This property can be used to pass other values, such as those defined by the
$context
object, to the Lambda function. The additional request template content should start with a
','
(and for consistent formatting, should start with
',\n '
and use
',\n '
between properties).
•
responses
Specifies – application/json
templates for 200 (success), 400 (client error) and 500
(service error) responses as described in Default Response Mapping (p. 378) . The 400 and 500
responses are inserted into the swagger responses object. However, you should define a 200 response that specifies a scheme that describes the data that the operation returns.
• Additional properties as specified by the x-amazon-apigateway-integration-properties
property.
Game Clients
The Cloud Gem Framework can generate game clients for your service API.
The game client can call some API operations on behalf of the player. Other operations are callable only
AWS credentials by assuming the
Player
role through an Amazon Cognito identity pool. This process,
described in detail in Player Identity (p. 427) , is illustrated in the following diagram.
Generating a Game Client
Generating a game client is straightforward.
To generate a game client
Type the following command: lmbr_aws cloud-gem-framework generate-service-api-code --resource-group
<group>
Version 1.10
383
Lumberyard Developer Guide
Cloud Gem Framework
The generate-service-api-code
command reads the swagger.json
file that contains definitions for the resource group's service API. The command creates a C++ header file that implements a Lumberyard component. The header file is named
<group>
ClientComponent.h
.
The directory location of the header file depends on whether
<group>
refers to a cloud gem or a projectdefined resource group.
Generated Component Header File Locations
Parameter Type
cloud gem
Header File Location
Gems
\<gem>
\Code\AWS\ServiceApi resource group
Code\
<game>
\AWS\
<group>
\ServiceAPI
Component Header File Accessibility
For a gem, the default location of the generated header file does not make it accessible outside of that gem. Typically, a cloud gem's service API is private to the gem, and the gem exposes its functionality through its own custom component. If you want to provide direct access to the cloud gem's API from other gems or game code, you can move the generated header file into the gem's
Code\Include directory.
Notes
• To use the generated client, add the generated file to your gem or project's WAF file list, and then rebuild the gem or project.
• You can use the generated client component to invoke the API from C++ or Lua. For more information, see
• For sample code, see
Generated Game Client Code Example (p. 384) .
Generated Game Client Code Example
The following client code was generated by the swagger.json
file for the Message of the Day Gem that is included with Lumberyard. The swagger file for the gem defines many operations. For brevity, the example shows client code for only the following
GET
and
PUT
operations:
•
GET /admin/messages?index={index}&count={count}&filter={filter}
•
PUT /admin/messages/{msg_id}
For comments, see the
Examining the Generated Game Client Code (p. 395) section that follows the
example.
// Example Generated Game Client
1 #pragma once
2 #include <AzCore/Component/Component.h>
3 #include <AzCore/Component/Entity.h>
4 #include <AzCore/Component/ComponentBus.h>
5 #include <AzCore/EBus/EBus.h>
6 #include <AzCore/Memory/SystemAllocator.h>
7 #include <AzCore/Rtti/BehaviorContext.h>
8 #include <AzCore/Serialization/EditContext.h>
9 #include <AzCore/Serialization/SerializeContext.h>
10 #include <AzCore/std/smart_ptr/scoped_ptr.h>
11 #include <AzCore/std/string/conversions.h>
12
13 #if defined (PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
14 #include <aws/core/http/HttpRequest.h>
Version 1.10
384
Lumberyard Developer Guide
Cloud Gem Framework
15 #include <aws/core/http/HttpResponse.h>
16 #endif // (PLATFORM_SUPPORTS_AWS_NATIVE_SDK)
17
18 #include <LmbrAWS/ILmbrAWS.h>
19
20 #include <CloudGemFramework/ServiceRequestJob.h>
21
22 #include "StdAfx.h"
23
24 namespace CloudGemMessageOfTheDay {
25 namespace ServiceAPI {
26
27 const char* LmbrAWS_CodeGen_PutAdminMessagesReturnType_UUID= "{ec889bb0-c329-11e6b753-80a589a02a3d}";
28 const char* LmbrAWS_CodeGen_Component_UUID= "{ec8874a1-c329-11e6accd-80a589a02a3d}";
29 const char* LmbrAWS_CodeGen_ResponseHandler_UUID= "{ec8874a4-c329-11e6a067-80a589a02a3d}";
30 const char* LmbrAWS_CodeGen_NotificationBus1_UUID= "{ec8874a2-c329-11e6a661-80a589a02a3d}";
31 const char* LmbrAWS_CodeGen_RequestBus1_UUID= "{ec8874a3-c329-11e6a1e9-80a589a02a3d}";
32 const char* LmbrAWS_CodeGen_DeleteAdminMessagesReturnType_UUID= "{ec889bb1c329-11e6-aa94-80a589a02a3d}";
33 const char* LmbrAWS_CodeGen_DetailedMessageList_UUID= "{ec889bb4c329-11e6-8650-80a589a02a3d}";
34 const char* LmbrAWS_CodeGen_ServiceStatus_UUID= "{45baaccf-c88b-11e6b813-80a589a02a3d}";
35 const char* LmbrAWS_CodeGen_DetailedMessageData_UUID= "{ec889bb3-c329-11e6bf48-80a589a02a3d}";
36
37
38 // redefs
39
40
41 bool WriteJson(CloudGemFramework::JsonWriter& writer, const int& item)
42 {
43 return writer.Int(item);
44 }
45
46 bool WriteJson(CloudGemFramework::JsonWriter& writer, const AZStd::string& item)
47 {
48 return writer.String(item);
49 }
50
51 bool WriteJson(CloudGemFramework::JsonWriter& writer, const float& item)
52 {
53 return writer.Double(static_cast<double>(item));
54 }
55
56 struct PutAdminMessagesReturnType
57 {
58
59 AZ_TYPE_INFO(PutAdminMessagesReturnType,
LmbrAWS_CodeGen_PutAdminMessagesReturnType_UUID)
60 AZ_CLASS_ALLOCATOR(PutAdminMessagesReturnType, AZ::SystemAllocator, 0)
61
62 bool OnJsonKey(const char* key, CloudGemFramework::JsonReader& reader);
63 static void Reflect(AZ::ReflectContext* reflection);
64
65 };
66
67 bool WriteJson(CloudGemFramework::JsonWriter& writer, const
PutAdminMessagesReturnType& item)
68 {
69 bool ok = true;
Version 1.10
385
Lumberyard Developer Guide
Cloud Gem Framework
70 ok = ok && writer.StartObject();
71 ok = ok && writer.EndObject();
72 return ok;
73 }
74
75 struct DetailedMessageData
76 {
77
78 AZ_TYPE_INFO(DetailedMessageData, LmbrAWS_CodeGen_DetailedMessageData_UUID)
79 AZ_CLASS_ALLOCATOR(DetailedMessageData, AZ::SystemAllocator, 0)
80
81 int priority;
82 AZStd::string message;
83 AZStd::string endTime;
84 AZStd::string UniqueMsgID;
85 AZStd::string startTime;
86
87 bool OnJsonKey(const char* key, CloudGemFramework::JsonReader& reader);
88 static void Reflect(AZ::ReflectContext* reflection);
89
90 };
91
92 bool WriteJson(CloudGemFramework::JsonWriter& writer, const DetailedMessageData&
item)
93 {
94 bool ok = true;
95 ok = ok && writer.StartObject();
96 ok = ok && writer.Key("priority");
97 ok = ok && WriteJson(writer, item.priority);
98 ok = ok && writer.Key("message");
99 ok = ok && WriteJson(writer, item.message);
100 ok = ok && writer.Key("endTime");
101 ok = ok && WriteJson(writer, item.endTime);
102 ok = ok && writer.Key("UniqueMsgID");
103 ok = ok && WriteJson(writer, item.UniqueMsgID);
104 ok = ok && writer.Key("startTime");
105 ok = ok && WriteJson(writer, item.startTime);
106 ok = ok && writer.EndObject();
107 return ok;
108 }
109
110 using DetailedMessageListPropertyList = AZStd::vector<DetailedMessageData>;
111
112 bool WriteJson(CloudGemFramework::JsonWriter& writer, const
DetailedMessageListPropertyList& list)
113 {
114 bool ok = true;
115 ok = ok && writer.StartArray();
116 for (auto item : list)
117 {
118 ok = ok && WriteJson(writer, item);
119 }
120 ok = ok && writer.EndArray();
121 return ok;
122 }
123
124 struct DetailedMessageList
125 {
126
127 AZ_TYPE_INFO(DetailedMessageList, LmbrAWS_CodeGen_DetailedMessageList_UUID)
128 AZ_CLASS_ALLOCATOR(DetailedMessageList, AZ::SystemAllocator, 0)
129
130 DetailedMessageListPropertyList list;
131
132 bool OnJsonKey(const char* key, CloudGemFramework::JsonReader& reader);
133 static void Reflect(AZ::ReflectContext* reflection);
Version 1.10
386
Lumberyard Developer Guide
Cloud Gem Framework
134
135 };
136
137 bool WriteJson(CloudGemFramework::JsonWriter& writer, const DetailedMessageList&
item)
138 {
139 bool ok = true;
140 ok = ok && writer.StartObject();
141
142 ok = ok && writer.Key("list");
143 ok = ok && WriteJson(writer, item.list);
144
145 ok = ok && writer.EndObject();
146 return ok;
147 }
148
149 // Service RequestJobs
150 CLOUD_GEM_SERVICE(CloudGemMessageOfTheDay);
151
152 void Configure()
153 {
154 // Insert any necessary CloudGemFramework configuration here
155 }
156
157 class PutAdminMessagesRequest
158 : public CloudGemFramework::ServiceRequest
159 {
160 public:
161 SERVICE_REQUEST(CloudGemMessageOfTheDay, HttpMethod::HTTP_PUT, "/admin/ messages/{msg_id}");
162
163 struct Parameters
164 {
165
166 AZStd::string msg_id;
167
168 MessageData msg;
169
170
171 bool BuildRequest(CloudGemFramework::RequestBuilder& request)
172 {
173 bool ok = true;
174
175 ok = ok && request.SetPathParameter("{""msg_id""}", msg_id);
176
177
178 ok = ok && request.WriteJsonBodyParameter(*this);
179 return ok;
180 }
181
182 bool WriteJson(CloudGemFramework::JsonWriter& writer) const
183 {
184 bool ok = true;
185
186 ok = ok && CloudGemMessageOfTheDay::ServiceAPI::WriteJson(writer,
msg);
187
188 return ok;
189 }
190 };
191
192
193 PutAdminMessagesReturnType result;
194
195
196 Parameters parameters;
Version 1.10
387
Lumberyard Developer Guide
Cloud Gem Framework
197 };
198
199
200 using PutAdminMessagesRequestJob =
CloudGemFramework::ServiceRequestJob<PutAdminMessagesRequest>;
201
202 class GetAdminMessagesRequest
203 : public CloudGemFramework::ServiceRequest
204 {
205
206 public:
207
208 SERVICE_REQUEST(CloudGemMessageOfTheDay, HttpMethod::HTTP_GET, "/admin/ messages");
209
210 struct Parameters
211 {
212
213 int index;
214 int count;
215 AZStd::string filter;
216
217 bool BuildRequest(CloudGemFramework::RequestBuilder& request)
218 {
219 bool ok = true;
220 ok = ok && request.AddQueryParameter("index", index);
221 ok = ok && request.AddQueryParameter("count", count);
222 ok = ok && request.AddQueryParameter("filter", filter);
223 ok = ok && request.WriteJsonBodyParameter(*this);
224 return ok;
225 }
226
227 bool WriteJson(CloudGemFramework::JsonWriter& writer) const
228 {
229 bool ok = true;
230 return ok;
231 }
232
233 };
234
235 DetailedMessageList result;
236 Parameters parameters;
237
238 };
239
240 using GetAdminMessagesRequestJob =
CloudGemFramework::ServiceRequestJob<GetAdminMessagesRequest>;
241
242 // Notification bus for this component
243 class CloudGemMessageOfTheDayNotifications
244 : public AZ::ComponentBus
245 {
246 public:
247
248 /**
249 * Sent when the request is a success
250 *
251 * Params:
252 * jsonOutput: The output receieved from the Lambda call
253 * request: The AWS Lambda request object
254 */
255 virtual void OnPutAdminMessagesRequestSuccess(const PutAdminMessagesReturnType
response) { }
256
257 /**
258 * Sent when the request fails
Version 1.10
388
Lumberyard Developer Guide
Cloud Gem Framework
259 *
260 * Params:
261 * error: The output receieved from the Lambda call;
262 * could be function error or an issue with the request
263 * request: The AWS Lambda request object
264 */
265 virtual void OnPutAdminMessagesRequestError(const CloudGemFramework::Error
error) { }
266
267 /**
268 * Sent when the request is a success
269 *
270 * Params:
271 * jsonOutput: The output receieved from the Lambda call
272 * request: The AWS Lambda request object
273 */
274
275 virtual void OnGetAdminMessagesRequestSuccess(const DetailedMessageList
response) { }
276
277 /**
278 * Sent when the request fails
279 *
280 * Params:
281 * error: The output receieved from the Lambda call;
282 * could be function error or an issue with the request
283 * request: The AWS Lambda request object
284 */
285 virtual void OnGetAdminMessagesRequestError(const CloudGemFramework::Error
error) { }
286
287 };
288
289 using CloudGemMessageOfTheDayNotificationBus =
AZ::EBus<CloudGemMessageOfTheDayNotifications>;
290
291 class BehaviorCloudGemMessageOfTheDayNotificationBusHandler
292 : public CloudGemMessageOfTheDayNotificationBus::Handler, public
AZ::BehaviorEBusHandler
293 {
294 public:
295 AZ_EBUS_BEHAVIOR_BINDER(BehaviorCloudGemMessageOfTheDayNotificationBusHandler,
LmbrAWS_CodeGen_NotificationBus1_UUID, AZ::SystemAllocator
296 , OnPutAdminMessagesRequestSuccess
297 , OnPutAdminMessagesRequestError
298 , OnGetAdminMessagesRequestSuccess
299 , OnGetAdminMessagesRequestError
300 );
301
302 void OnPutAdminMessagesRequestSuccess(const PutAdminMessagesReturnType
response) override
303 {
304 Call(FN_OnPutAdminMessagesRequestSuccess, response);
305 }
306
307 void OnPutAdminMessagesRequestError(const CloudGemFramework::Error error)
override
308 {
309 Call(FN_OnPutAdminMessagesRequestError, error);
310 }
311
312 void OnPostAdminMessagesRequestSuccess(const DetailedMessageData response)
override
313 {
314 Call(FN_OnPostAdminMessagesRequestSuccess, response);
315 }
Version 1.10
389
Lumberyard Developer Guide
Cloud Gem Framework
316
317 void OnPostAdminMessagesRequestError(const CloudGemFramework::Error error)
override
318 {
319 Call(FN_OnPostAdminMessagesRequestError, error);
320 }
321
322 };
323
324 class CloudGemMessageOfTheDayResponseHandler;
325
326 // Request bus for this component
327 class CloudGemMessageOfTheDayRequests
328 : public AZ::ComponentBus
329 {
330
331 public:
332
333 virtual ~CloudGemMessageOfTheDayRequests() {}
334
335 virtual void PutAdminMessages(const AZStd::string& msg_id, const MessageData&
msg, CloudGemMessageOfTheDayResponseHandler* responseHandler) { }
336 virtual void GetAdminMessages(const int& index, const int& count, const
AZStd::string& filter, CloudGemMessageOfTheDayResponseHandler* responseHandler) { }
337
338 };
339
340 using CloudGemMessageOfTheDayRequestBus =
AZ::EBus<CloudGemMessageOfTheDayRequests>;
341
342 // This class is used as a parameter for all requests and throws the response on
the CloudGemMessageOfTheDayNotificationBus
343 // Inherit from this to define custom behavior.
344 class CloudGemMessageOfTheDayResponseHandler
345 {
346 public:
347 AZ_TYPE_INFO(CloudGemMessageOfTheDayResponseHandler,
LmbrAWS_CodeGen_ResponseHandler_UUID)
348 AZ_CLASS_ALLOCATOR(CloudGemMessageOfTheDayResponseHandler,
AZ::SystemAllocator, 0)
349
350 virtual ~CloudGemMessageOfTheDayResponseHandler() {}
351
352 virtual void HandlePutAdminMessagesSuccess(PutAdminMessagesRequestJob* job,
AZ::Entity* entity)
353 {
354 EBUS_EVENT_ID(entity->GetId(), CloudGemMessageOfTheDayNotificationBus,
OnPutAdminMessagesRequestSuccess, job->result);
355 }
356
357 virtual void HandlePutAdminMessagesError(PutAdminMessagesRequestJob* job,
AZ::Entity* entity)
358 {
359 EBUS_EVENT_ID(entity->GetId(), CloudGemMessageOfTheDayNotificationBus,
OnPutAdminMessagesRequestError, job->error);
360 }
361
362 virtual void HandleGetAdminMessagesSuccess(GetAdminMessagesRequestJob* job,
AZ::Entity* entity)
363 {
364 EBUS_EVENT_ID(entity->GetId(), CloudGemMessageOfTheDayNotificationBus,
OnGetAdminMessagesRequestSuccess, job->result);
365 }
366
367 virtual void HandleGetAdminMessagesError(GetAdminMessagesRequestJob* job,
AZ::Entity* entity)
Version 1.10
390
Lumberyard Developer Guide
Cloud Gem Framework
368 {
369 EBUS_EVENT_ID(entity->GetId(), CloudGemMessageOfTheDayNotificationBus,
OnGetAdminMessagesRequestError, job->error);
370 }
371
372 };
373
374 class CloudGemMessageOfTheDayClientComponent
375 : public AZ::Component
376 , public CloudGemMessageOfTheDayRequestBus::Handler
377 {
378 public:
379 AZ_COMPONENT(CloudGemMessageOfTheDayClientComponent,
LmbrAWS_CodeGen_Component_UUID);
380 virtual ~CloudGemMessageOfTheDayClientComponent() = default;
381
382 AZStd::scoped_ptr<CloudGemMessageOfTheDayResponseHandler>
m_defaultResponseHandler;
383
384 void Init() override
385 {
386 m_defaultResponseHandler.reset(new
CloudGemMessageOfTheDayResponseHandler());
387 CloudGemMessageOfTheDay::ServiceAPI::Configure();
388 }
389
390 void Activate() override
391 {
392 CloudGemMessageOfTheDayRequestBus::Handler::BusConnect(m_entity->GetId());
393 }
394
395 void Deactivate() override
396 {
397 CloudGemMessageOfTheDayRequestBus::Handler::BusDisconnect();
398 }
399
400 static void Reflect(AZ::ReflectContext* reflection)
401 {
402 MessageData::Reflect(reflection);
403 PutAdminMessagesReturnType::Reflect(reflection);
404 DetailedMessageData::Reflect(reflection);
405 DetailedMessageList::Reflect(reflection);
406 MessageList::Reflect(reflection);
407
408 AZ::SerializeContext* serializeContext =
azrtti_cast<AZ::SerializeContext*>(reflection);
409 if (serializeContext)
410 {
411 // we must include any fields we want to expose to the editor or lua
in the serialize context
412 serializeContext->Class<CloudGemMessageOfTheDayClientComponent>()
413 ->Version(1);
414
415 AZ::EditContext* editContext = serializeContext->GetEditContext();
416 if (editContext)
417 {
418 editContext-
>Class<CloudGemMessageOfTheDayClientComponent>("CloudGemMessageOfTheDayClientComponent",
"CloudGemMessageOfTheDay Component")
419 ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
420 ->Attribute(AZ::Edit::Attributes::Category, "Cloud Canvas
Gems")
421 -
>Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu, AZ_CRC("Game"));
422 }
423 }
Version 1.10
391
Lumberyard Developer Guide
Cloud Gem Framework
424
425 AZ::BehaviorContext* behaviorContext =
azrtti_cast<AZ::BehaviorContext*>(reflection);
426 if (behaviorContext)
427 {
428 behaviorContext-
>EBus<CloudGemMessageOfTheDayRequestBus>("CloudGemMessageOfTheDayRequestBus")
429 // one of these for each function
430 ->Event("PutAdminMessages",
&CloudGemMessageOfTheDayRequestBus::Events::PutAdminMessages)
431 ->Event("GetAdminMessages",
&CloudGemMessageOfTheDayRequestBus::Events::GetAdminMessages)
432 ;
433 behaviorContext-
>EBus<CloudGemMessageOfTheDayNotificationBus>("CloudGemMessageOfTheDayNotificationBus")
434 ->Handler<BehaviorCloudGemMessageOfTheDayNotificationBusHandler>()
435 ;
436 }
437 }
438
439 // Functions from the swagger definitions
440
441
442 void PutAdminMessages(const AZStd::string& msg_id, const MessageData& msg,
CloudGemMessageOfTheDayResponseHandler* responseHandler) override
443 {
444
445
446 if (responseHandler == nullptr)
447 {
448 responseHandler = AZStd::get_pointer(m_defaultResponseHandler);
449 }
450
451 // create job
452 PutAdminMessagesRequestJob* job = PutAdminMessagesRequestJob::Create(
453 [responseHandler, this](PutAdminMessagesRequestJob* job)
454 {
455 // handle success
456 responseHandler->HandlePutAdminMessagesSuccess(job, m_entity);
457 },
458 [responseHandler, this](PutAdminMessagesRequestJob* job)
459 {
460 // handle error
461 responseHandler->HandlePutAdminMessagesError(job, m_entity);
462 }
463 );
464
465 job->parameters.msg = msg;
466 job->parameters.msg_id = msg_id;
467
468 job->Start();
469
470 }
471
472 void GetAdminMessages(const int& index, const int& count, const AZStd::string&
filter, CloudGemMessageOfTheDayResponseHandler* responseHandler) override
473 {
474
475 if (responseHandler == nullptr)
476 {
477 responseHandler = AZStd::get_pointer(m_defaultResponseHandler);
478 }
479
480 // create job
481 GetAdminMessagesRequestJob* job = GetAdminMessagesRequestJob::Create(
482 [responseHandler, this](GetAdminMessagesRequestJob* job)
Version 1.10
392
Lumberyard Developer Guide
Cloud Gem Framework
483 {
484 // handle success
485 responseHandler->HandleGetAdminMessagesSuccess(job, m_entity);
486 },
487 [responseHandler, this](GetAdminMessagesRequestJob* job)
488 {
489 // handle error
490 responseHandler->HandleGetAdminMessagesError(job, m_entity);
491 }
492 );
493
494 job->parameters.index = index;
495 job->parameters.count = count;
496 job->parameters.filter = filter;
497
498 job->Start();
499
500 }
501
502 };
503
504 bool MessageData::OnJsonKey(const char* key, CloudGemFramework::JsonReader&
reader)
505 {
506
507 if (strcmp(key, "priority") == 0) return reader.Accept(priority);
508
509 if (strcmp(key, "message") == 0) return reader.Accept(message);
510
511 if (strcmp(key, "endTime") == 0) return reader.Accept(endTime);
512
513 if (strcmp(key, "startTime") == 0) return reader.Accept(startTime);
514
515 return reader.Ignore();
516 }
517
518 void MessageData::Reflect(AZ::ReflectContext* reflection)
519 {
520 AZ::SerializeContext* serializeContext =
azrtti_cast<AZ::SerializeContext*>(reflection);
521
522 if (serializeContext)
523 {
524 serializeContext->Class<MessageData>()
525 ->Version(1);
526 }
527
528 AZ::BehaviorContext* behaviorContext =
azrtti_cast<AZ::BehaviorContext*>(reflection);
529 if (behaviorContext)
530 {
531 behaviorContext->Class<MessageData>("CloudGemMessageOfTheDay_MessageData")
532 ->Attribute(AZ::Script::Attributes::Storage,
AZ::Script::Attributes::StorageType::Value)
533
534 ->Property("priority", BehaviorValueProperty(&MessageData::priority))
535
536 ->Property("message", BehaviorValueProperty(&MessageData::message))
537
538 ->Property("endTime", BehaviorValueProperty(&MessageData::endTime))
539
540 ->Property("startTime",
BehaviorValueProperty(&MessageData::startTime))
541
542 ;
543 }
Version 1.10
393
Lumberyard Developer Guide
Cloud Gem Framework
544 }
545
546 bool PutAdminMessagesReturnType::OnJsonKey(const char* key,
CloudGemFramework::JsonReader& reader)
547 {
548 return reader.Ignore();
549 }
550
551 void PutAdminMessagesReturnType::Reflect(AZ::ReflectContext* reflection)
552 {
553 AZ::SerializeContext* serializeContext =
azrtti_cast<AZ::SerializeContext*>(reflection);
554
555 if (serializeContext)
556 {
557 serializeContext->Class<PutAdminMessagesReturnType>()
558 ->Version(1);
559 }
560
561 AZ::BehaviorContext* behaviorContext =
azrtti_cast<AZ::BehaviorContext*>(reflection);
562 if (behaviorContext)
563 {
564 behaviorContext-
>Class<PutAdminMessagesReturnType>("CloudGemMessageOfTheDay_PutAdminMessagesReturnType")
565 ->Attribute(AZ::Script::Attributes::Storage,
AZ::Script::Attributes::StorageType::Value)
566
567 ;
568 }
569 }
570
571 bool DetailedMessageData::OnJsonKey(const char* key,
CloudGemFramework::JsonReader& reader)
572 {
573 if (strcmp(key, "priority") == 0) return reader.Accept(priority);
574 if (strcmp(key, "message") == 0) return reader.Accept(message);
575 if (strcmp(key, "endTime") == 0) return reader.Accept(endTime);
576 if (strcmp(key, "UniqueMsgID") == 0) return reader.Accept(UniqueMsgID);
577 if (strcmp(key, "startTime") == 0) return reader.Accept(startTime);
578 return reader.Ignore();
579 }
580
581 void DetailedMessageData::Reflect(AZ::ReflectContext* reflection)
582 {
583
584 AZ::SerializeContext* serializeContext =
azrtti_cast<AZ::SerializeContext*>(reflection);
585
586 if (serializeContext)
587 {
588 serializeContext->Class<DetailedMessageData>()->Version(1);
589 }
590
591 AZ::BehaviorContext* behaviorContext =
azrtti_cast<AZ::BehaviorContext*>(reflection);
592 if (behaviorContext)
593 {
594 behaviorContext-
>Class<DetailedMessageData>("CloudGemMessageOfTheDay_DetailedMessageData")
595 ->Attribute(AZ::Script::Attributes::Storage,
AZ::Script::Attributes::StorageType::Value)
596 ->Property("priority",
BehaviorValueProperty(&DetailedMessageData::priority))
597 ->Property("message",
BehaviorValueProperty(&DetailedMessageData::message))
Version 1.10
394
Lumberyard Developer Guide
Cloud Gem Framework
598 ->Property("endTime",
BehaviorValueProperty(&DetailedMessageData::endTime))
599 ->Property("UniqueMsgID",
BehaviorValueProperty(&DetailedMessageData::UniqueMsgID))
600 ->Property("startTime",
BehaviorValueProperty(&DetailedMessageData::startTime))
601 ;
602 }
603
604 }
605
606 bool DetailedMessageList::OnJsonKey(const char* key,
CloudGemFramework::JsonReader& reader)
607 {
608 if (strcmp(key, "list") == 0) return reader.Accept(list);
609 return reader.Ignore();
610 }
611
612 void DetailedMessageList::Reflect(AZ::ReflectContext* reflection)
613 {
614
615 AZ::SerializeContext* serializeContext =
azrtti_cast<AZ::SerializeContext*>(reflection);
616
617 if (serializeContext)
618 {
619 serializeContext->Class<DetailedMessageList>()->Version(1);
620 }
621
622 AZ::BehaviorContext* behaviorContext =
azrtti_cast<AZ::BehaviorContext*>(reflection);
623 if (behaviorContext)
624 {
625 behaviorContext-
>Class<DetailedMessageList>("CloudGemMessageOfTheDay_DetailedMessageList")
626 ->Attribute(AZ::Script::Attributes::Storage,
AZ::Script::Attributes::StorageType::Value)
627 ->Property("list", BehaviorValueProperty(&DetailedMessageList::list))
628 ;
629 }
630
631 }
632
633 } // ServiceAPI
634 } // CloudGemMessageOfTheDay
Examining the Generated Game Client Code
The following table provides additional information for the generated game client code example in the previous section. The line numbers indicate the location in the code that the comments refer to.
Line Number
24, 25
56, 75, 110, 124
67, 92, 112, 137
Description
The C++ namespace for the API. This is always
<resource-groupname>
::ServiceApi
.
The
PutAdminMessageReturnType
struct contains the PUT operation's return data as defined by the swagger file. In this case, it is an empty object and has no properties.
The
WriteJson
method is generated to handle the serialization of
PutAdminMessageReturnType
objects to JSON text format.
JSON format is required for the data to be sent to the service. A
Version 1.10
395
157, 202
291
340
344
374
200, 240
243
Line Number
150
152
Lumberyard Developer Guide
Cloud Gem Framework
Description
similar function is generated for each of the type definitions in the swagger.json
file.
The
CLOUD_GEM_SERVICE
macro defines a class that provides information that is common to all of the service's requests.
The
Configure
function is called when the generated component is initialized. You can add code to this function to change the default configuration for the service. For example, the following code increases the timeout for
GetServiceStatus
requests.
void Configure()
{
GetServiceStatusRequestJob::GetDefaultConfig()-
>requestTimeoutMs = 20000;
}
Note
If you regenerate the client, your changes to the
Configure method are lost.
A
Request
class such as
PutAdminMessagesRequest
is generated for each of the operations defined in the swagger.json
file. This class encapsulates the HTTP method and path that are used to make the request. The
Parameters
struct in the class defines the fields for each of the request's parameters that are specified by the swagger file.
The Lumberyard job system executes API requests asynchronously. This work is performed by the
CloudGemFramework::ServiceRequestJob class and specialized by the
PutAdminMessagesRequest
class declared previously. The C++ using
statement creates an alias for that type.
Defines the
CloudGemMessageOfTheDayNotifications
EBus that signals when a request has completed. Both a success and an error notification method are defined for each operation specified in the swagger.json
file.
Defines a handler
(
BehaviorCloudGemMessageOfTheDayNotificationBusHandler
) for the notification EBus that forwards notifications to Lua code.
Defines an EBus (
CloudGemMessageOfTheDayRequestBus
) that initiates requests.
Defines a class (
CloudGemMessageOfTheDayResponseHandler
) that handles responses. By default, responses are dispatched to the notification EBus previously defined.
Defines a client component
(
CloudGemMessageOfTheDayClientComponent
) that uses the using the request job classes
PutAdminMessagesRequest
(line 157) and
(line 202) to implement the request EBus
GetAdminMessagesRequest handler
BehaviorCloudGemMessageOfTheDayNotificationBusHandler
(line 291).
Version 1.10
396
Lumberyard Developer Guide
Cloud Gem Framework
Calling a Game API
To call your API operations, you can use C++, the client component, a request job, or Lua.
Topics
•
Calling an API from C++ (p. 397)
•
Using Lua to Call an API (p. 399)
Calling an API from C++
To invoke a service API from C++, you can use an EBus event handler from the generated client component. You can also use the generated service request job class directly. If you want to make requests from a component, consider using the client component. If you want to perform a sequence of operations, consider using the job class.
Using the Client Component to Call an API
The following example from the
CloudGemLeaderboard
service API shows a component that invokes
GetServiceStatusRequestJob
. There are two ways to receive the request's response:
1. Use an object that inherits from the service's response handler.
2. Connect to the generated component's notification bus.
The example shows both methods.
// Sample API Caller
#include <AzCore/Component/Component.h>
#include <AzCore/Component/Entity.h>
#include <AzCore/Serialization/EditContext.h>
#include <AzCore/Serialization/SerializeContext.h>
#include <AzCore/EBus/EBus.h>
#include <AWS/ServiceAPI/CloudGemLeaderboardClientComponent.h>
#include <CloudGemLeaderboard/CloudGemLeaderboardBus.h> class SampleResponseHandler
: public CloudGemLeaderboard::ServiceAPI::CloudGemLeaderboardResponseHandler
{ public:
void
HandleGetServiceStatusSuccess(CloudGemLeaderboard::ServiceAPI::GetServiceStatusRequestJob*
job, AZ::Entity* entity) override
{
//Look at job->result for response data
AZ_Printf("Got response: %s", job->result.status.c_str());
}
void
HandleGetServiceStatusError(CloudGemLeaderboard::ServiceAPI::GetServiceStatusRequestJob*
job, AZ::Entity* entity) override
{
//Look at job->error for error data
}
}; class SampleAPICallerComponent
: public AZ::Component
, public CloudGemLeaderboard::ServiceAPI::CloudGemLeaderboardNotificationBus::Handler
{ public:
SampleResponseHandler* m_responseHandler;
Version 1.10
397
Lumberyard Developer Guide
Cloud Gem Framework
AZ_COMPONENT(SampleAPICallerComponent, "{aedd6408-e2f0-4250-a181-b0ef41085a94}");
virtual ~SampleAPICallerComponent() = default;
static void Reflect(AZ::ReflectContext* reflection)
{
AZ::SerializeContext* serializeContext =
azrtti_cast<AZ::SerializeContext*>(reflection);
if (serializeContext)
{
// We must include any fields we want to expose to the editor or Lua in the
serialize context
serializeContext->Class<SampleAPICallerComponent>()
->Version(1);
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<SampleAPICallerComponent>("SampleAPICallerComponent",
"Component to call CloudGemLeaderboard GetServiceStatus")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu,
AZ_CRC("Game"));
}
}
}
void Activate() override
{
CloudGemLeaderboard::ServiceAPI::CloudGemLeaderboardNotificationBus::Handler::BusConnect(m_entity-
>GetId());
CallGetServiceStatus();
}
void CallGetServiceStatus()
{
// To get the response on the CloudGemLeaderboardNotificationBus
EBUS_EVENT_ID(m_entity->GetId(),
CloudGemLeaderboard::ServiceAPI::CloudGemLeaderboardRequestBus, GetServiceStatus,
nullptr);
// To get the response in a special response handler
m_responseHandler = new SampleResponseHandler();
EBUS_EVENT_ID(m_entity->GetId(),
CloudGemLeaderboard::ServiceAPI::CloudGemLeaderboardRequestBus, GetServiceStatus,
m_responseHandler);
}
void OnGetServiceStatusRequestSuccess(const
CloudGemLeaderboard::ServiceAPI::ServiceStatus response) override
{
// handle success
AZ_Printf("Got response: %s", response.status.c_str());
}
void OnGetServiceStatusRequestError(const CloudGemFramework::Error error) override
{
// handle failure
}
void Deactivate() override
{
CloudGemLeaderboard::ServiceAPI::CloudGemLeaderboardNotificationBus::Handler::BusDisconnect();
delete m_responseHandler;
}
};
Version 1.10
398
Lumberyard Developer Guide
Cloud Gem Framework
Using the Request Job to Call an API
In some situations you might want more control over how your background jobs are executed. For example, you might want to change the thread pool that certain requests use or perform multiple requests on a background thread. You can use the generated request job classes directly to make these changes.
In its simplest form, you can use the request job class in the following example. This is the same code that is in line 452 of the generated request component.
PutAdminMessagesRequestJob* job = PutAdminMessagesRequestJob::Create(
[responseHandler, this](PutAdminMessagesRequestJob* job)
{
// Handle success
responseHandler->HandlePutAdminMessagesSuccess(job, m_entity);
},
[responseHandler, this](PutAdminMessagesRequestJob* job)
{
// Handle error
responseHandler->HandlePutAdminMessagesError(job, m_entity);
}
); job->parameters.msg = msg; job->parameters.msg_id = msg_id; job->Start();
To learn about other ways to use the request job class, explore the
ServiceApiRequestJob
class
definition and see Running AWS API Jobs Using the Cloud Gem Framework (p. 364) .
Using Lua to Call an API
The following code example shows how to call a service API from a Lua script.
-- Service status getter local leaderboardstatusgetter = {
Properties = {
}
} function leaderboardstatusgetter:OnActivate()
self.notificationHandler = CloudGemLeaderboardNotificationBus.Connect(self,
self.entityId)
CloudGemLeaderboardRequestBus.Event.GetServiceStatus(self.entityId, nil) end function leaderboardstatusgetter:OnDeactivate()
self.notificationHandler:Disconnect() end function leaderboardstatusgetter:OnGetServiceStatusRequestSuccess(response)
Debug.Log(response.status) end function leaderboardstatusgetter:OnGetServiceStatusRequestError(error)
Debug.Log(error.message) end return leaderboardstatusgetter
Version 1.10
399
Lumberyard Developer Guide
Cloud Gem Framework
Publishing Your API
Service API operations are implemented by API Gateway , which has an open source serverless web application that you can use to create your own developer portal. A developer portal on API Gateway empowers you to do the following:
• List your API operations in catalog form.
• Allow developers to sign up.
• Display documentation that helps developers understand your API.
• Let developers test your API and provide feedback.
• Grow a developer ecosystem.
• Monetize your API and grow API product revenue.
For more information, see Generate Your Own API Gateway Developer Portal .
You can use the lmbr_aws cloud-gem-framework
command line for working with Cloud Canvas
Gems (p. 202) , the Cloud Gem Portal (p. 202) , and the
Cloud Gem Framework Service API (p. 373) .
Note
For general information on the lmbr_aws
command line tool, including common syntax, configuration, and arguments, see
Using the Cloud Canvas Command Line (p. 435)
.
Commands
Following are details of the lmbr_aws cloud-gem-framework
commands.
add-service-api-resources
Adds the resources to implement a swagger.json
file-based service API to a resource group.
The add-service-api-resources
command accepts the following arguments:
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Required. The name of the resource group or cloud gem.
•
--force
Optional. Forces the replacement of existing resource definitions. By default, existing resource definitions with the same names are not changed.
For more information about the add-service-api-resources
command, see
in the
Cloud Gem Framework Service API (p. 373)
documentation and Getting Started with the Cloud Gem
create-portal-administrator
Creates a Cloud Gem Portal administrator account if none is present.
The create-portal-administrator
command accepts the following argument:
•
--silent-create-admin
– Runs the command without outputs.
Version 1.10
400
Lumberyard Developer Guide
Cloud Gem Framework generate-service-api-code
Generates component and Lambda function code to support a service API described by a swagger.json
file that a resource group provides.
The generate-service-api-code
command accepts the following arguments:
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Required. The name of a resource group or cloud gem that provides a swagger.json
file.
•
--component-client-path
{component-client-path}
Optional. The output path for the component client code. The default location is the
Code\
{game}
\AWS
\
{group}
\ServiceAPI
directory. If a gem defines the resource group, the default location is the
Gem
\Code\Include\AWS\ServiceAPI
directory.
For more information about the generate-service-api-code
command, see Generating a Game Client
and Getting Started with the Cloud Gem Framework (p. 326)
.
open-cloud-gem-portal, open-portal, cloud-gem-portal
Generate a presigned URL and open the Cloud Gem Portal in the default browser using the presigned
URL.
The open-cloud-gem-portal
command and its equivalents accept the following arguments:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. If the
{role-name}
that is specified in the
--role
argument is a deployment access role, identifies the deployment used. If the
--deployment
argument is not specified, the default deployment for the project is used.
•
--duration-seconds
{duration-in-seconds}
Optional. Specifies the number of seconds before the URL and temporary credentials expire. You can
•
--show-current-encryption-object
Optional. Displays the active Cloud Gem Portal AES passphrase and initialization vector without generating a new encrypted payload.
•
--show-encryption-object
Optional. Displays the newly generated AES passphrase and initialization vector of the encryption object that the Cloud Gem Portal uses for decrypting data that Lumberyard sends.
•
--role
{role-name}
Specifies an IAM role to be assumed by the Cloud Gem Portal website. Can be
ProjectOwner
,
DeploymentOwner
, or any other project or deployment access role. The credentials taken from the
~/.aws/credentials
file must be able to assume the role that is specified.
remove-service-api-resources
Remove the resources that implement a swagger.json
file–based service API operation from a resource group.
The remove-service-api-resources
command accepts the following arguments:
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Version 1.10
401
Lumberyard Developer Guide
Cloud Gem Framework
Required. The name of the resource group.
service-api-process-swagger
Processes the Cloud Canvas extension objects that are defined in a swagger.json
file and produces swagger definitions that can be imported into Amazon API Gateway.
The service-api-process-swagger
command accepts the following arguments:
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Required. The name of the resource group.
•
--input
{file-path}
Optional. The file from which the swagger
JSON is read. For the cloud gems that are included with
Lumberyard, the default is dev\Gems\
{gem-name}
\swagger.json
.
•
--output
{file-path}
Optional. The file to which the processed swagger JSON is written. By default, the output is written to stdout
(the command line console window).
For more information about the service-api-process-swagger
command, see
upload-cloud-gem-portal, upload-portal
Upload all Cloud Gem Portal content.
The upload-cloud-gem-portal
command and its upload-portal
equivalent accept the following arguments:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. The name of the deployment for which portal content will be uploaded. If not specified, the default deployment is updated.
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Optional. The name of the resource group to which portal content will be uploaded. The default is to upload portal content for all resource groups.
•
--project
Optional. Specifies that the global portal content of the project will be updated instead of the deployment and resource group content.
The
lmbr_aws cloud-gem-framework add-service-api-resources (p. 400)
API to a resource group. Prior to Lumberyard version 1.10, it copied the the service Lambda code for dispatching service API calls from the
CloudGemFramework\AWS\resource-manager-code\defaultresource-group-content\lambda-function-code
directory to the resource group's lambda-functioncode
directory.
In version 1.10, Lumberyard adds a general purpose code sharing mechanism. You can use this this mechanism to include a single copy of the service API dispatch code in all the Lambda functions that require it. Place the code to be shared in a subdirectory of a gem's
AWS\common-code
directory. The subdirectory name is the name of the code package.
Version 1.10
402
Lumberyard Developer Guide
Cloud Gem Framework
An
.import
file can be found in a gem's AWS directory or a project's resource group directory. The file can be placed any of the following directories to indicate that the code depends on a set of specified packages:
• lambda-code\
<lambda-name>
\
• lambda-function-code\
•
<lambda-name>
-lambda-code\
• resource-manager-code\
• common-code\
<package-name>
\
You can use the common-code\
<package-name>
\
directory to add dependencies recursively. The lambdacode\
<lambda-name>
\
directory is new in Lumberyard 1.10. For more information about this directory,
see Lambda Code Directories (p. 310)
.
The
.import
file has the following format:
<gem-name>
.
<package-name>
<gem-name>
.
<package-name>
...
The entries in the
.import
file instruct the Cloud Gem framework to include the contents of the specified gem's
AWS\common-code\
<package-name>
directory. For Lambda code, the contents of the directory are included in the
.zip
file that contains other Lambda code. When resource manager loads the code specified by sys.path
(the Python default module search path, or
PYTHONPATH
), the resource-managercode
directory is included in that path.
The service API dispatch code can be found at
Gems\CloudGemFramework\v
<N>
\AWS\common-code
\LambdaService
. The
Gems\CloudGemFramework\v
<N>
\AWS\common-code\LambdaSettings
directory contains code for accessing injected settings.
In Lumberyard version 1.10, Cloud Canvas introduces a versioning system that makes it easier to update a project from one version of the Cloud Gem Framework and the
Cloud Canvas Resource Manager
to another. The versioning system has the following advantages:
• Cloud gems can have separate versions.
• Cloud gems can specify the version of Lumberyard that they work with.
• The resource manager and Cloud Gem Framework are implemented in directory structures that support versioning.
• Lumberyard can provide multiple versions of the Cloud Gem Framework and the resource manager at the same time.
• Lumberyard can innovate while still supporting gems that depend on early versions of the framework.
This document describes these changes at an architectural level. For concrete steps on updating existing
.
Versioning Convention
Lumberyard gems use a simplified semantic versioning , which defines version numbers in the form
major
.
minor
.
revision
. Lumberyard increments the major version for changes that cause previous code not to work, including any change that breaks the code or configuration that is not directly controlled by the Cloud Gem Framework.
Version 1.10
403
Lumberyard Developer Guide
Cloud Gem Framework
Every major version change is released by creating a new code base in a new
\dev\Gems
\CloudGemFramework\v
N
directory, where
N
is the major version number.
Minor updates replace the code in the
\dev\Gems\CloudGemFramework\v
N
directory. Earlier major versions of the framework continue to be released with Lumberyard for an unspecified amount of time before they are removed from the release.
Multiple Versions of the Cloud Gem Framework Gem
The new directory structure in Cloud Gem Framework 1.0.0 enables coexistence of multiple versions of the Cloud Gem Framework Gem. Gem implementation has moved from the
\dev\Gems
\CloudGemFramework\
directory to the
\dev\Gems\CloudGemFramework\v
<N>
\
directory. The intent is that all nonbreaking changes be made in the v
<Current>
directory. When breaking changes occur, a v
<Next>
directory is created to contain the updated implementation. The v
<Current>
directory contents remain either unchanged or updated without breaking changes. A gem can now have different versions of its gem.json
file in the v1
and the v2
directory, for example. This enables the gem to specify different versions. Lumberyard's build and project configurator tools support gems in subdirectories.
Note
The
Cloud Canvas Resource Manager
now allows gems to be in directories other than
\Gems
\
<gem-name>
. The resource-group add (p. 449)
lmbr_aws resource-group add
command's
--gem
option now takes an optional value that specifies the gem directory path. The specified directory path can be either relative to the current working directory or a full path.
Resource Manager Merged into the Cloud Gem Framework Gem
In Lumberyard 1.10, resource manager functionality has been taken over by the Cloud Gem Framework
Gem. Accordingly, and to allow resource manager to be versioned, the contents of the
\dev\tools
\lmbr_aws\
directory have moved to the dev\Gems\CloudGemFramework\v
<N>
\ResourceManager\ directory, with the following exceptions:
• The
\dev\tools\lmbr_aws\
directory still contains the cli.py
and gui.py
modules. These modules are loaded by the lmbr_aws.cmd
file and the resource manager user interface in Lumberyard Editor. These modules discover which project is current by looking in the
\dev\bootstrap.cfg
file. They then look in the project's
\dev\
<project>
\gems.json
file to get the
Version
value for
CloudGemFramework
. The modules then forward the request to the corresponding cli.py
or gui.py
module for the specified version of the framework. If no version of the framework is enabled, the user is informed that they must enable the gem.
• The dev\Tools\lmbr_aws\test\
directory still contains the
RunAllTests.cmd
, cleanup.cmd
, and Python module files that support them. The
RunAllTests.cmd
file has been updated to run tests from the
CloudGemFramework\v
<N>
\
directory. As new releases occur, the file will be updated to include all versions of the framework.
Global Project Code Directories and Project Templates
In Cloud Gem Framework 1.0.0 (Lumberyard version 1.10), the project code directories and project templates have also changed to support versioning.
Project Code Directories
The
\
<project>
\AWS\project-code
directory formerly contained code for the following Lambda functions:
•
ProjectPlayerAccessTokenExchangeHandler
•
ProjectResourceHandler
•
ProjectServiceLambda
Version 1.10
404
Lumberyard Developer Guide
Cloud Gem Framework
Previously, this Lambda code was copied from the
\dev\tools\lmbr_aws\AWSResourceManager\defaultproject-content\project-code
directory when the project was created.
This code is now located in the
\Gems\CloudGemFramework\v
N
\AWS\lambda-code\
directory in subdirectories divided by Lambda function.
Note
It is no longer possible for a gem or resource group to inject code into the project Lambda function by creating a
<gem>
\AWS\project-code
or a resource-group\
<resourcegroup>
\project-code
directory.
Project Templates
The following template files have moved to the
\Gems\CloudGemFramework\v
N
\ResourceManager
\resource_manager\templates
directory.
• deployment-access-template.json
• deployment-template.json
• project-template.json
When the framework updates a stack, it uses these templates as a base to create the project's actual templates. Then it uploads the templates to AWS CloudFormation.
Note
Starting in Lumberyard 1.10, you can use extension files to add resources to each of these templates. For more information, see
Template Extension Files (p. 309) .
Sharing Code
The
lmbr_aws cloud-gem-framework add-service-api-resources (p. 400)
API to a resource group. Before Lumberyard version 1.10, it copied the service Lambda code for dispatching service API calls from the
CloudGemFramework\AWS\resource-manager-code\defaultresource-group-content\lambda-function-code
directory to the resource group's lambda-functioncode
directory.
In version 1.10, Lumberyard adds a general purpose code sharing mechanism. You can use this mechanism to include a single copy of the service API dispatch code in all the Lambda functions that
require it. For more information, see Using Shared Code (p. 402)
.
A cloud gem is a gem that depends on the Cloud Gem Framework (p. 325) . Starting in Lumberyard
1.10 (and Cloud Gem Framework 1.0.0),
gem versioning support (p. 403) makes the work of updating
Lumberyard cloud gem projects much easier. However, manual steps are required to update projects and gems that were created before Cloud Gem Framework version 1.0.0.
Updating Existing Cloud Gem Projects
To update an existing cloud gem project, you must update the project's gems.json
file and run-time configuration.
To update an existing Lumberyard project
1. In the project's dev\
<project-name>
\gems.json
file, find the entry for
CloudGemFramework
. Change the
Version
value to
1.0.0
and the
Path
value to
Gems/CloudGemFramework/v1
, as in the following example.
{
Version 1.10
405
Lumberyard Developer Guide
Cloud Gem Framework
"Path": "Gems/CloudGemFramework/v1",
"Uuid": "6fc787a982184217a5a553ca24676cfa",
"Version": "1.0.0",
"_comment": "CloudGemFramework"
},
2. In a command prompt window, run the following command to update the project's run-time configuration.
dev\Tools\LmbrSetup\Win\lmbr.exe projects populate-appdescriptors -projects
<projectname>
For more information about populate-appdescriptors
, see Project Commands in the documentation for lmbr.exe
.
Update the Project's AWS Directory
To update the project's AWS directory, you must delete the project, deployment access, and deployment template files. But before you delete the template files, you must save any roles or resources that you added.
To update the AWS directory
1. Delete the
<project>
\AWS\project-code
directory. If you have made changes to this code, you must update the
CloudGemFramework\v
N
\lambda-code
directory content to preserve the changes that you made.
2. If you added roles or other resources to the
<project>
\AWS\project-template.json
file, create a
<project>
\AWS\project-template-extensions.json
file and copy those resource definitions into the project-template-extensions.json
file.
3. Delete the
<project>
\AWS\project-template.json
file.
4. If you added roles or other resources to the
<project>
\AWS\deployment-access-template.json
file, create a
<project>
\AWS\deployment-access-template-extensions.json
file and copy those resource definitions into the deployment-access-template-extensions.json
file.
5. Delete the
<project>
\AWS\deployment-access-template.json
file.
6. If you added resources to the
<project>
\AWS\deployment-template.json
file, create a
<project>
\AWS\deployment-template-extensions.json
file and copy those resource definitions into the deployment-template-extensions.json
file.
7. Delete the
<project>
\AWS\deployment-template.json
file.
Update the Project's Resource Group Directories
When no Lambda resources exist for a resource group, you can simply remove the resource group's
Lambda code directories.
To remove Lambda code directories from a project resource group
1. For each
<project>
\AWS\resource-group\
<resource-group-name>
directory, check whether its resource-template.json
file defines AWS Lambda function resources.
2. If the resource-template.json
file does not define any Lambda resources, delete the following directories:
•
<project>
\AWS\resource-group\
<resource-group-name>
\lambda-function-code
•
<project>
\AWS\resource-group\
<resource-group-name>
\
<lambda-name>
-lambda-code
3. If the resource-template.json
file defines AWS Lambda function resources, perform the steps described in
Updating Lambda Code (p. 407) .
Version 1.10
406
Lumberyard Developer Guide
Cloud Gem Framework
Updating Existing Cloud Gems
To update an existing cloud gem, you must update the gem's gem.json
file and either remove its Lambda code directories or update its Lambda code.
To update an existing cloud gem
1. In the
<gem>
\gem.json
file, find the entry for
CloudGemFramework
. Change
VersionConstraints
to the following value.
"VersionConstraints": [ "~>1.0" ],
2. If the
<gem>
\AWS\resource-template.json
file does not exist or does not define any AWS Lambda function resources, delete the
<gem>
\AWS\lambda-function-code
directory and any
<gem>
\AWS
\
<lambda-name>
-lambda-code
directories. Otherwise, perform the steps in Updating Lambda
.
Updating Lambda Code
Updating Lambda code involves reorganizing your existing Lambda code directories and creating
.import
files as needed. For information on the reasons for this directory restructuring, see Cloud Gem
Framework and Resource Manager Versioning (p. 403)
.
To update your Lambda code
1. For each of the following Lambda code directories, perform the steps that follow.
•
<project>
\AWS\resource-group\
<resource-group-name>
\lambda-function-code
•
<project>
\AWS\resource-group\
<resource-group-name>
\
<lambda-name>
-lambda-code
•
<gem>
\AWS\lambda-function-code
•
<gem>
\AWS\
<lambda-name>
-lambda-code
2. If the code directory contains the service.py
and errors.py
files that support service API dispatching, delete them and add an
.import
file with the following content to the directory:
CloudGemFramework.LambdaService
3. If the code directory contains a
CloudCanvas
subdirectory, delete the subdirectory. If you did not have to create an
.import
file in step 2, add an
.import
file that has the following content:
CloudGemFramework.LambdaSettings
If you already created an
.import
file in step 2, add
CloudGemFramework.LambdaSettings
to the
.import
file, as in the following example:
CloudGemFramework.LambdaService
CloudGemFramework.LambdaSettings
4. Move the contents of the code directory (along with the new
.import
file, if any) into a
<parentdir>
\lambda-code\
<lambda-name>
directory. Note the following:
• If you had code for multiple Lambda functions in the single lambda-function-code
directory, decide which modules to put into the subdirectory of the lambda-code
directory, and place them there.
• If you have code that is used by multiple Lambda functions, put that code in a
<parentdir>
\common-code\
<import-name>
directory. To include the code with the rest of the Lambda code when it is uploaded, use an
.import
file.
Version 1.10
407
Lumberyard Developer Guide
Administering Cloud Canvas
For more information about these changes, see Cloud Gem Framework and Resource Manager
This section provides information for administering your Lumberyard project's AWS account and its use of the AWS cloud.
Topics
•
Setting Up a Project to Use Resource Manager (p. 408)
•
Working with Deployments (p. 412)
•
Understanding the Resource Manager Security System (p. 420)
After initializing Cloud Canvas Resource Manager so that your Amazon Lumberyard project can use AWS, you can use Resource Manager to configure the stacks for your project.
Topics
•
Initializing Cloud Canvas Resource Manager (p. 408)
•
Working with Project Stacks (p. 409)
When you perform an operation that requires an AWS account, and no account has been associated with your Lumberyard project, the
Initialize Cloud Canvas Resource Manager
dialog prompts you for the required information.
Version 1.10
408
Lumberyard Developer Guide
Setting Up a Project to Use Resource Manager
To initialize Cloud Canvas Resource Manager
1. When prompted to initialize the
Cloud Canvas Resource Manager
, provide the following information:
• For
Project stack name
, type the name of an AWS CloudFormation stack that you will create.
The stack will contain the AWS resources that
Cloud Canvas Resource Manager
will use for your project. By default, Lumberyard uses the name of your project for the stack name. A stack with the name that you specify must not already exist in your AWS account for the region you select.
• For
AWS Credentials
, select from the list of available profiles or create a new one. If you have no
AWS profiles on your computer, you are prompted for an AWS secret key and an AWS access key.
You can also edit an existing one.
In order to use Lumberyard with AWS, you must provide administrative credentials for your AWS account either directly, or through an AWS profile. For information on how to get these credentials from AWS, see the Getting Started with Cloud Canvas Tutorial .
• For
AWS region
, specify the AWS data center where your resources will reside. You must choose a region that supports all the AWS services that your game uses. The region you choose must also support the Amazon Cognito service, which Lumberyard uses to establish player identity, and AWS
CloudFormation, which Lumberyard uses to create and manage resources. For more information about the capabilities of different regions, see AWS Regions and Endpoints .
2. Click
Create
to start the initialization process. In the navigation tree, the
node is selected, and in the detail pane, the
(p. 298) shows the progress of the
initialization.
When you select the
Project stack
node in the
Cloud Canvas Resource Manager
navigation pane, the detail pane shows information about the AWS CloudFormation stack that Cloud Canvas is using.
Note the following:
• If you select a project stack node and no AWS profile is configured, Lumberyard prompts you to provide one. A profile is required for Lumberyard to display the status of your project’s resources. For more information, see
Managing Cloud Canvas Profiles (p. 200)
.
Version 1.10
409
Lumberyard Developer Guide
Setting Up a Project to Use Resource Manager
• If you select the
Project stack
node when the project has not been initialized for use with Cloud
Canvas, Lumberyard prompts you to initialize the project and create a project stack. For more
information, see Initializing Cloud Canvas Resource Manager (p. 408) .
Project Stack Status Table
The
Project stack status
table shows the status of the AWS CloudFormation stack that contains the resources used by your project's resource groups.
This table has the following columns:
Pending
– Indicates when changes have been made to the local stack templates or code but not yet uploaded to AWS. Pausing your mouse pointer on a value in this column displays the reason why the change is pending. Following are the possible values:
•
Create
– The stack is defined locally but has not been created in AWS.
•
Update
– The stack's template and/or Lambda function code has been changed locally but not yet uploaded to AWS.
•
Delete
– The stack has been removed from the local definitions but has not been deleted in AWS. If you are using a source control system, this status can indicate that a new stack has been added to the project. However, your local copy of the source control is out of date and doesn't contain the definition for the new stack.
•
--
– No change is pending.
Status
– The status of the AWS CloudFormation stack. See
Descriptions (p. 296) for a description of the values this column can have. To see additional status
information, pause your pointer on the status indicator.
Created
– The time the stack was created.
Updated
– The time the stack status was updated.
ID
- A truncated version of the AWS ID for the stack. To see the full ID, pause your pointer on the truncated ID.
Upload Resources
Click
Upload resources
to start the process of modifying, creating, or deleting resources in AWS so that they match your local definitions of them. A dialog box shows the changes that will be applied.
Version 1.10
410
Lumberyard Developer Guide
Setting Up a Project to Use Resource Manager
The table of changes has the same columns as the stack resource status table but also includes a column for
Impacts
. If a change has the potential to affect the security of your project, the
Impacts
column contains the text
Security
. Before you can start an operation that has a security impact, you must select the option
It is OK that this will impact resource SECURITY
. Review any security changes carefully before you apply them.
Similarly, before you can start an operation that deletes one or more resources, you must select the option
It is OK that this will permanently DELETE resources
.
Stack Resources Table
The
Stack resources
table shows the status of the resources that your project is using.
This table has the following columns:
Pending
– Indicates that changes have been made locally but not yet uploaded to AWS. Pausing your mouse on a value in this column displays the reason why the change is pending. Following are the possible values:
•
Create
– The resource is defined locally but has not been created in AWS.
•
Update
– The resource has been changed locally but not yet uploaded to AWS.
•
Delete
– The resource has been removed from the local definitions but has not been deleted on AWS.
If you are using a source control system, this status can indicate that a new resource has been added to the project. However, your local copy of the source control is out of date and doesn't contain the definition for the new resource.
•
--
– No change is pending.
Resource Name
– The logical name of the resource. You can reference the resource in flow graph nodes by adding this resource name to the resource group name.
Type
– The type of the resource (for example, a Lambda function, Amazon S3 bucket, or a custom resource).
Status
– The current condition of the resource. For a description of the possible status values, see
pointer on the status.
Version 1.10
411
Lumberyard Developer Guide
Working with Deployments
Timestamp
– The time of the most recent change.
ID
- A truncated version of the AWS ID for the stack. To see the full ID, pause your pointer on the truncated ID.
A deployment is an independent copy of the AWS resources that your game uses. Deployments are useful for maintaining a safe separation among game lifecycle phases such as development, test, and production. In the resource manager navigation pane, the
Deployments
node shows you the status of your project’s deployments. You can also use it to create a new deployment.
Note
: If the
Deployments
node is selected when no AWS profile is configured, Lumberyard prompts you to provide a profile. The status of the project’s deployments cannot be displayed unless a profile is provided. For more information, see
Managing Cloud Canvas Profiles (p. 200) .
Click
Create deployment
to start the creation of a deployment:
When uploading resources for the first time, you may see this version of the dialog:
Version 1.10
412
Lumberyard Developer Guide
Working with Deployments
Provide a name for
Deployment name
. Lumberyard appends this name to the project stack name to create an AWS CloudFormation stack for the deployment.
To start the deployment creation process, click
OK
. In the resource manager navigation pane, a node for the deployment appears under
Deployments
. In the detail pane, the Viewing the Cloud Canvas Progress
Log (p. 298) provides details about the creation process.
The
Deployment status
table shows the status of the AWS CloudFormation stack for each deployment.
Deployment
shows the deployment name. For descriptions of the remaining fields in this table, see
Stack Resources Table (p. 411) in the
Working with Project Stacks (p. 409)
section.
The child nodes of the
Deployment
node each represent one of the Lumberyard project’s deployments.
When a
Deployment
node is selected, the detail pane shows the current status of the selected deployment.
Version 1.10
413
Lumberyard Developer Guide
Working with Deployments
Note
If a
Deployment
node is selected when no AWS profile is configured, Lumberyard prompts you to provide a profile. The status of the project’s deployments cannot be displayed unless a profile
is provided. For more information, see Managing Cloud Canvas Profiles (p. 200) .
Individual Deployment Status Table
The
<Deployment Name> deployment status
table shows the status of the AWS CloudFormation stack
Working with Project Stacks (p. 409) section.
Upload All Resources
Click
Upload all resources
to start the process of modifying, creating, or deleting resources in the current AWS deployment so that they match your local definitions for all resource groups.
Delete Deployment
Click
Delete deployment
to start the process of deleting the deployment’s resources from AWS. The resources defined by all resource groups will be deleted.
Version 1.10
414
Lumberyard Developer Guide
Working with Deployments
For more information about deleting deployments, see Deleting Cloud Canvas Deployments and Their
Stack Resources Table
The
Stack resources
table shows the status of each of the resources defined by all the resource
groups for the selected deployment. For descriptions of the fields in this table, see Stack Resources
Working with Project Stacks (p. 409) section.
Topics
•
Making a Cloud Canvas Deployment Active (p. 415)
•
Testing Different Mappings (p. 417)
•
Using Protected Deployments (p. 418)
•
Deleting Cloud Canvas Deployments and Their Resources (p. 419)
You can select the deployment that you want Lumberyard Editor to consider active. The active deployment is the deployment that you work with in Lumberyard Editor. Lumberyard Editor uses the active deployment's resources when you launch your game. When you select the
node or an
Managing Individual Resource Groups (p. 301)
node in the
Cloud Canvas
Resource Manager
navigation pane, the status information that appears corresponds to the active deployment.
You can also select the deployment that you want to be active by default for all team members.
Note
To select a deployment, you must have initialized
Cloud Canvas Resource Manager
to work
with your AWS account and created a deployment. For more information, see Initializing Cloud
Canvas Resource Manager (p. 408)
and Create Deployment (p. 412)
.
Making a Deployment Active
You have several ways to make a deployment active in
Cloud Canvas Resource Manager
.
To make a deployment active
• To make a deployment active, do one of the following:
• In Lumberyard Editor, click
AWS
,
Cloud Canvas
,
Select a deployment
.
Version 1.10
415
Lumberyard Developer Guide
Working with Deployments
• In the
Cloud Canvas Resource Manager
toolbar, click the name of the current deployment, or click
(none)
if none is configured:
When prompted, choose the deployment that you want to make active:
One or more of the deployments may be marked
protected
. For more information, see Using
Protected Deployments (p. 418)
.
• In the
Cloud Canvas Resource Manager
navigation pane, right-click the deployment that you want to make active, and then click
Make active deployment
:
Making a Deployment the Default
You can use the
Cloud Canvas Resource Manager
to make a deployment the default.
To make a deployment active by default for all team members
1. In Lumberyard Editor, click
AWS
,
Cloud Canvas
,
Cloud Canvas Resource Manager
.
2. In the
Cloud Canvas configuration
navigation tree, expand
Administration (advanced)
, and then expand
Deployments
.
3. Right-click the deployment that you want to make the default, and then click
Make default deployment
:
To use the command line to make a deployment the default
• To use the command line to make a deployment the default, type the following command:
Version 1.10
416
Lumberyard Developer Guide
Working with Deployments lmbr_aws deployment default --set
<deployment name>
To test your client with different Cloud Canvas resource deployments, you can export mappings by using
Cloud Canvas Resource Manager or the lmbr_aws
command line.
To export a mapping from Cloud Canvas Resource Manager
• In Resource Manager, do one of the following:
• Left click a deployment and click
Export Mapping
in the main window.
• Right click the name of a deployment name the list, and then select
Export Mapping
from the context menu.
The following image shows both options.
To exporting a mapping from the command line
• Type the following command, where
<name>
is the name of your deployment.
Version 1.10
417
Lumberyard Developer Guide
Working with Deployments lmbr_aws mappings update --deployment
<name>
The mapping file for the specified deployment is created in the
<project_directory>
\Config
directory and has the format
<deployment_name>
.awsLogicalMappings.json
.
Tip
Using the command line to export mappings makes it easy for you to create scripts for testing or development.
Selecting a Deployment with a PC Launcher
After you have exported one or more mappings, you can choose the mapping to use when you run a game launcher such as the one at dev\Bin64\SamplesProjectLauncher.exe
.
To direct the launcher to use a specific deployment, use the command line option cc_override_resource_map
, as in the following example.
SamplesProjectLauncher.exe -cc_override_resource_map Config\dev.awsLogicalMappings.json
The argument for the cc_override_resource_map
parameter specifies the mapping file that you want to use.
If you have exported a single mapping file to the launcher, the launcher uses that mapping file by default. If you have exported multiple mapping files to the launcher, you must select a mapping by using the cc_override_resource_map
parameter. If you don't specify a mapping after multiple mappings have been exported, the launcher gives an error message, and no mapping is loaded.
You can use Cloud Canvas to mark specific deployments as protected. Protected status makes it more difficult for users (typically, testers or developers) to inadvertently connect a development game client to live resources.
When a user starts a protected game, a message box notifies the user that he or she is attempting to use a protected deployment. The user is given the option to not connect before any potentially harmful data is transmitted.
The protection feature purposely uses a message box that "breaks" automation. If the scripts that run tests are configured to use a protected deployment, the Lumberyard client will not continue without human intervention.
When Protected Deployments Are Detected
When a game is run from Lumberyard Editor, protection is always detected. When a game is run from a
Windows launcher, protection is detected only when the launcher is running in debug mode.
Marking a Deployment as Protected
Currently, you must set the protection from the lmbr_aws
command line tool by using the protectdeployment
command.
The protect-deployment
command uses the following parameters.
--set
<deployment_name>
– Specifies that the deployment is protected.
Version 1.10
418
Lumberyard Developer Guide
Working with Deployments
--clear
<deployment_name>
– Specifies the deployment is not protected.
--show
- Displays a list of currently protected deployments.
To display the protected status of deployments, you can also use either the list-deployments
or listmappings
command.
Viewing Protected Status in Cloud Canvas Resource Manager
In Cloud Canvas Resource Manager, you can view, but not change, the status of protected deployments.
The ability to change the protected status of deployments from Lumberyard Editor is planned for a future release.
Note
Setting a deployment to protected does not prevent you from deploying or deleting resources by using Cloud Canvas Resource Manager or the lmbr_aws
command line tool; it only enables the warning functionality. For this reason, be careful not to make unnecessary changes to critical deployments. A more comprehensive model for protecting deployments is planned for a future version of Lumberyard.
To remove Cloud Canvas functionality from your Lumberyard project and the AWS resources related to it, you can use
Cloud Canvas Resource Manager
or the Cloud Canvas command line.
Warning
Only administrators should perform these actions. If you remove all AWS resources managed by
Cloud Canvas for your Lumberyard project, the players of your game will not be able to access any of the Cloud Canvas resource groups that implement your game's cloud connected features.
To use Cloud Canvas Resource Manager to delete Cloud Canvas deployments and their resources
1. If you have checked Lumberyard into source control, ensure that the
<root>
\
<game>
\AWS\projectsettings.json
file has been checked out and is writeable.
2. In Lumberyard Editor, choose
AWS
,
Cloud Canvas
,
Cloud Canvas Resource Manager
.
3. In the
Cloud Canvas configuration
navigation pane, expand
Administration (advanced)
, and then expand
Deployments
. The list of the deployments in the project appears.
4. Select the deployment to delete and click
Delete deployment
.
5. When prompted to confirm, click
Yes
to start the process of deleting the deployment’s resources from AWS. The process might take a few minutes.
6. To remove all of the project's resources from AWS, follow the same steps to delete each of the project’s deployments.
Version 1.10
419
Lumberyard Developer Guide
Understanding the Resource Manager Security System
To use the command line to delete Cloud Canvas deployments and their resources
1. If you have checked Lumberyard into source control, ensure that the
<root>
\
<game>
\AWS\projectsettings.json
file has been checked out and is writeable.
2. Open a command line prompt and change to your the Lumberyard
\dev
directory.
3. Determine the project’s deployment names by typing the following command: lmbr_aws deployment list
4. Type the following command for each of the deployments that you want to delete: lmbr_aws deployment delete --deployment
<deployment name>
Note
To remove all Cloud Canvas functionality from your project, use the delete-deployment command to delete all of deployments that were listed by list-deployments
. Then remove the project stack as described in the step that follows.
5. After you have deleted all deployments, you can delete the resources that Cloud Canvas uses to manage your project by typing the following command: lmbr_aws project delete
This removes all AWS resources that are related to your Cloud Canvas project.
Cloud Canvas Resource Manager provides a robust set of features for securing your Amazon Lumberyard project and its cloud-connected resources. You can control the access to project resources of team members, players, Lambda functions, and specify other custom access control configuration for your project.
Topics
•
Controlling Access to Resources (p. 420)
•
Cloud Canvas Built-In Roles and Policies (p. 423)
•
•
Using the Cloud Canvas Command Line to Manage Roles and Permissions (p. 429)
Setting access permissions correctly is key to ensuring that Cloud Canvas Resource Manager manages your project's cloud-connected features securely.
Access Scenarios and ProjectResourceHandler
Cloud Canvas Resource Manager requires that the following access scenarios be supported. Additional roles with more nuanced permissions can be created, but the table below describes the core access requirements.
Version 1.10
420
Lumberyard Developer Guide
Understanding the Resource Manager Security System
A project team member must be able to create resource group stacks that contain arbitrary resources, but not be able to create or modify roles and policies. This introduces a significant complexity. Some resources like Lambda functions require that the developer also provide a role that is assumed by the resource. The developer must be able to create such roles and manage their policies. However, granting
IAM permissions such as these directly to team members would effectively make them administrators.
To enable the required functionality while still limiting what a project team member can do directly,
Cloud Canvas Resource Manager uses AWS CloudFormation custom resources. The custom resource handlers for Cloud Canvas Resource Manager are implemented in the
ProjectResourceHandler
Lambda function in the project stack. The Lambda function's execution role (
ProjectResourceHandlerExecution
) grants permissions that Cloud Canvas Resource Manager requires. These permissions are not granted to project team members.
For example, the
Custom::CloudGemFramework::AccessControl
resource, described in detail later in this document, is responsible for managing inline policies on various roles. It can perform these actions on the project team member's behalf. However, the
Custom::CloudGemFramework::AccessControl handler also must know what to put into these policies. It can't trust the project team member to provide this information directly. Instead, it must construct the information from trusted sources. To do this,
AccessControl
uses metadata on resource definitions from AWS CloudFormation. It also constructs ARNs for the stack's resources identified by AWS CloudFormation. In this way, only a user with permission to update the stack can influence the policies that are constructed for the resources in that stack.
Version 1.10
421
Lumberyard Developer Guide
Understanding the Resource Manager Security System
Using the Custom::CloudGemFramework::AccessControl Resource
As described above, Cloud Canvas Resource Manager security depends on IAM Roles and the credentials used from assuming such roles. The
Access Scenarios and ProjectResourceHandler (p. 420)
section earlier in this topic explains why Cloud Canvas Resource Manager has the responsibility of managing the inline policies attached to these roles.
This section describes the data used by the
Custom::CloudGemFramework::AccessControl
resource handler to configure the project's roles. A
Custom::CloudGemFramework::AccessControl
resource must be defined in the following templates:
Template
projecttemplate.json
deploymentaccesstemplate.json
resource-grouptemplate.json
Description
Causes policies on the roles defined in the project-template.json
file to be updated. These roles can provide access to any resource defined in any resource groups across all deployments.
Causes policies on the roles defined in the deployment-access-template.json
file to be updated. These roles can provide access to any resource in any resource of a given deployment.
Causes policies on the roles defined in the project-template.json
and deployment-access-template.json
files to be updated. Only permissions for the resource defined in the resource-group-template.json
file are updated. For roles defined in the deployment-access-template.json
file, only the instances of those roles for the deployment that contains the resource group stack are updated.
This process is illistrated in the following diagram. The diagram shows the metadata that is read and roles that are updated when a resource group stack, deployment access stack, or project stack is updated.
Version 1.10
422
Lumberyard Developer Guide
Understanding the Resource Manager Security System
Custom::CloudGemFramework::AccessControl Resource Definitions
The
Custom::CloudGemFramework::AccessControl
resource supports the following properties:
Property Description
Identifies the location in the configuration bucket where data for the stack operation is stored. However, the custom resource handler depends on this value changing on each update. Property changes such as this cause AWS CloudFormation to invoke the custom resource handler on each stack operation.
ServiceToken
Identifies the Lambda function that is invoked for the custom resource. This should be the project global
ProjectResourceHandler
Lambda function that is defined in the project-template.json
file.
The
DependsOn
attribute of the
Custom::CloudGemFramework::AccessControl
resource definition must list the following resources.
• All the resources in the project-template.json
, deployment-access-template.json
, or resourcegroup-template.json
files that provide permissions metadata.
• All the
AWS::IAM::Role
resources that have
RoleMapping
metadata.
• Any custom resources that create implicit roles, such as
Custom::CloudGemFramework::LambdaConfiguration
and
Custom::CloudGemFramework::ServiceApi resources.
When you use the AWS CLI to manage roles and permissions, these resources are listed for you. However, if you edit these files yourself, it is important that you maintain these dependencies. Without these dependencies, the
Custom::CloudGemFramework::AccessControl
resource might be updated before the other resources have been updated. If this occurs, the
Custom::CloudGemFramework::AccessControl
no longer has access to the latest metadata from the resources, and the changes that were intended might not be made.
Setting Access Permissions
For information on setting
Custom::CloudGemFramework::AccessControl
Metadata for Resource Definitions (p. 310)
.
You can use the built-in Cloud Canvas roles and policies to manage resource and deployment permissions for your project.
Roles
You can use the AWS::IAM:Role resource to define roles in your project-template.json
or deploymentaccess-template.json
files. Cloud Canvas Resource Manager defines the following roles for you:
Version 1.10
423
Lumberyard Developer Guide
Understanding the Resource Manager Security System
Role
ProjectOwner
ProjectAdmin
DeploymentOwner
DeploymentAdmin
Player
File
template.json
template.json
projecttemplate.json
projecttemplate.json
deployment-accesstemplate.json
deployment-accesstemplate.json
deployment-accesstemplate.json
Description
Grants the
ProjectResourceHandler
Lambda function the permissions it has at run time.
Grants the
ProjectServiceLambda
Lambda function the permissions that it has at run time.
Grants project administrators full access to all the project's resources. To modify the default permissions granted by this role, edit the
ProjectOwnerAccess
policy definition.
Note
Permissions added to
ProjectOwnerAccess
are also granted to
ProjectAdmin
unless they are denied by
ProjectAdminRestrictions
.
Similar to the
ProjectOwner
role, but cannot create, update, or delete deployments with names that start with "Release." This is a convenience measure that makes using
ProjectAdmin
safer than using
ProjectOwner
. To add additional restrictions to the
ProjectAdmin
role, edit the
ProjectAdminRestrictions
definition.
Grants developers full access to all the resources in a deployment. To modify the default permissions granted by this role, edit the
DeploymentOwnerAccess
policy definition.
Note
Permissions added to
DeploymentOwnerAccess are also granted to
DeploymentAdmin unless they are denied by
DeploymentAdminRestrictions
.
Similar to the
DeploymentOwner
role, but cannot create or delete resource group stacks. This is a convenience measure that makes using
DeploymentAdmin
safer than using
DeploymentOwner
. To add additional restrictions to the
DeploymentAdmin
role, edit the
DeploymentAdminRestrictions
policy definition.
Grants players limited access to specific resources in a deployment.
The configuration file in which you define a role determines the resources to which the role provides access.
File
projecttemplate.json
deploymenttemplate.json
Scope
Applies to all resources in all resource groups for all
deployments. Only a single instance of the role is created for the entire project.
Applies to all resources in all resource groups for a specific
deployment. A separate instance of the role is created for each deployment.
Version 1.10
424
Lumberyard Developer Guide
Understanding the Resource Manager Security System
You can use the lmbr_aws
command line tool to manage the role definitions in the projecttemplate.json
and deployment-access-template.json
files. For more information, see Using the Cloud
Canvas Command Line to Manage Roles and Permissions (p. 429)
.
Implicit Roles
Some Cloud Canvas custom resources also create roles. For example, when a Lambda function is executed, it assumes the role that the
Custom::CloudGemFramework::LambdaConfiguration
resource creates. When API Gateway invokes a Lambda function or accesses other resources, it assumes the role that the
Custom::CloudGemFramework::ServiceApi
resource creates. Including these custom resources in a resource-group-template.json
file causes these implicit roles to be created (and deleted when the
resource is deleted). For information on implicit role names, see Implicit Role Mappings (p. 427)
.
Managed Policies
You can use
AWS::IAM::ManagedPolicy
resources to define permissions that are shared across any number of roles. Cloud Canvas defines the following managed policies for you:
Policy File
ProjectAccess projecttemplate.json
template.json
template.json
DeploymentAccessdeploymentaccesstemplate.json
accesstemplate.json
accesstemplate.json
Description
Defines the permissions needed to access the project and deployment configuration that must be read before a project-
wide role can be assumed. For more information, see Assuming a
.
Defines the default permissions granted to the
ProjectOwner
and
ProjectAdmin
roles.
Defines restrictions to the
ProjectOwnerAcess
policy that apply only to the
ProjectAdmin
role.
Defines the permissions needed to access project and deployment configuration that must be read before a deployment-specific role can be assumed. For more information,
see Assuming a Role (p. 429) .
Defines the default permissions granted to the
DeploymentOwner and
DeploymentAdmin
roles.
Defines restrictions to the
DeploymentOwnerAccess
policy that apply only to the
DeploymentAdmin
role.
The
ProjectAdmin
and
DeploymentAdmin
roles are granted the same permissions as the
ProjectOwner and
DeploymentOwner
roles, minus any permissions specifically denied by the
ProjectAdminRestrictions and
DeploymentAdminRestrictions
managed policies, respectively. In effect an, "admin" is granted all the permissions of an "owner" minus any special actions that the "admin" should not be able to perform.
Role Mapping Metadata
The
AbstractRole
property in the
Permission
metadata object does not directly specify the actual role that receives the described permission. These values must be mapped to actual IAM roles. This makes it possible to setup roles in whatever way makes sense for your project. It also removes the need to modify the permissions defined by individual resource groups.
The ability to map abstract roles to actual IAM roles is important when you use a cloud gem across multiple projects or from a third party. Cloud gems acquired from a third party might have roles that are
Version 1.10
425
Lumberyard Developer Guide
Understanding the Resource Manager Security System different from the roles that you use in your organization. (A cloud gem is a Lumberyard gem that uses the AWS resources defined by a Cloud Canvas Resource Group. For more information, see Cloud Gems .)
The
Custom::CloudGemFramework::AccessControl
resource looks for CloudCanvas
RoleMappings metadata on
AWS::IAM::Role
resources to determine which abstract roles map to that physical role. In the following example, the
CustomerSupport
abstract role from all resource groups is mapped to the
DevOps
physical role.
...
"
DevOps
": {
"Type": "AWS::IAM::Role",
"Properties": {
"Path": { "Fn::Join": [ "", [ "/", { "Ref": "ProjectStack" }, "/", { "Ref":
"DeploymentName" }, "/" ]] }
},
"Metadata": {
"CloudCanvas": {
"RoleMappings": [
{
"
AbstractRole
": [ "*.
CustomerSupport
" ],
"
Effect
": "Allow"
}
]
}
}
},
...
Each Cloud Canvas
RoleMapping
metadata object can have the following properties.
Property Description
Effect
Required string or list of strings of the form
<resource-group-name>
.
<abstract-role-name>
.
To match abstract roles defined in any resource group, use * for the
<resource-group-name>
.
To match abstract roles defined only in a specific resource group, use an actual resource group name.
Required string. Must be either
Allow
, to allow an action defined by permission metadata, or
Deny
to deny an action. This is used as the Effect property in a statement in the policy.
You can use the lmbr_aws
command line tool to manage
RoleMappings
metadata on role resource definitions in the project-template.json
and deployment-access-template.json
files. For more information, see Using the Cloud Canvas Command Line to Manage Roles and Permissions.
Default Role Mappings
Cloud Canvas defines role mappings for the following roles:
Role File
ProjectResourceHandlerExecutionproject-template.json
ProjectServiceLambdaExecution project-template.json
ProjectOwner project-template.json
Default Role Mapping
none none
*.ProjectAdmin
*.ProjectOwner
Version 1.10
426
Lumberyard Developer Guide
Understanding the Resource Manager Security System
Role
ProjectAdmin
DeploymentOwner
DeploymentAdmin
Player
File
project-template.json
deployment-accesstemplate.json
deployment-accesstemplate.json
deployment-accesstemplate.json
Default Role Mapping
*.ProjectAdmin
*.DeploymentAdmin
*.DeploymentOwner
*.DeploymentAdmin
*.Player
Implicit Role Mappings
As mentioned in Implicit Roles (p. 425)
, role mappings are automatically defined for the implicit roles created by Cloud Canvas resources like
Custom::CloudGemFramework::LambdaConfiguration
. These mappings are only used with permission metadata in the same resource-group-template.json
file as the custom resource that creates the role. The name of the abstract role used in permission metadata to reference an implicit role depends on the custom resource type.
Resource Implicit Role Name
The name of the Lambda function, as specified by the
Function
property in the
Custom::CloudGemFramework::LambdaConfiguration
resource definition. This is also the logical ID of the
AWS::Lambda::Function resource.
The logical ID of the
Custom::CloudGemFramework::ServiceApi resource.
A Lumberyard cloud-connected game must use AWS credentials that grant the desired access when calling AWS APIs (using either the C++ AWS SDK or the AWS flow nodes). Cloud Canvas uses an Amazon
Cognito identity pool to get these credentials.
Using a Amazon Cognito identity pool has the benefit of providing the game with a unique identity for each individual player. This identity can be used to associate the player with their saved games, high scores, or any other data stored in DynamoDB tables, Amazon S3 buckets, or other locations. If you use the Player Account Cloud Gem, this identity is mapped to an account ID that can be used instead.
Amazon Cognito identity pools support both unauthenticated and authenticated identities.
Unauthenticated identities are associated with a single device such as a PC, tablet, or phone, and have no associated user name or password.
Authenticated identities are associated with the identity of an user as determined by an external identity provider such as Amazon, Facebook, or Google, or an Amazon Cognito user pool. This allows Amazon
Cognito to provide the game with the same player identity everywhere a user plays a game. The user's saved games, high scores, and other data effectively follow the user from device to device.
Cloud Canvas supports both anonymous (unauthenticated) and authenticated player identities. The
Player Account Cloud Gem is the easiest way to add authentication. Authenticated identity support for other providers is more complex and requires additional setup and coding.
Version 1.10
427
Lumberyard Developer Guide
Understanding the Resource Manager Security System
Anonymous (Unauthenticated) Player Login
The Cloud Canvas client configuration system is automatically initialized by calling gEnv-
>lmbrAWS->GetClientManager()->ApplyConfiguration()
, or by using a Cloud Canvas
(AWS):Configuration:ApplyConfiguration
flow node. An existing anonymous identity is loaded from the local identities cache. If an anonymous identity is not found in the cache, a new identity is acquired from the pool. The identity cache is stored in an
.aws/.identities
file in your home directory.
Authenticated Player Login
In order to understand how to use Cloud Canvas to implement authenticated player identities for your game, you must be familiar with Amazon Cognito's Enhanced (Simplified) Authflow. For information, see the article Authentication Flow in the Amazon Cognito Developer Guide .
The login process for authenticated player identities is more complex than the anonymous player login process. The Player Account Cloud Gem handles this for Amazon Cognito user pools. For other providers, this login process requires additional setup beyond what Cloud Canvas provides by default.
The authenticated player login process takes place automatically when the Cloud Canvas client configuration system is initialized by calling gEnv->lmbrAWS->GetClientManager()-
>ApplyConfiguration()
, or by using a Cloud Canvas
(AWS):Configuration:ApplyConfiguration
flow node. If an authenticated identity is found in the local identities cache, it is loaded and the access token is refreshed if needed using the stored refresh token. If no existing identity is found, it falls back to using the anonymous identity for AWS calls.
All the code that implements the authenticated login flow can be found in the
{root}
\Code\CryEngine
\LmbrAWS\Configuration
directory. A description of the files follows.
•
ClientManagerImpl.*
– Configures the game's AWS clients to use the
TokenRetrievingPersistentIdentityProvider
identity provider.
•
ResourceManagementLambdaBasedTokenRetrievalStrategy.*
– Implements the token exchange process that calls the
PlayerAccessTokenExchange
Lambda function.
•
TokenRetrievingPersistentIdentityProvider.*
– An implementation of the
PersistentCognitoIdentityProvider
interface defined in the AWS SDK that uses
ResourceManagementLambdaBasedTokenRetrievalStrategy
instances to implement the token exchange process.
Configuring a Cognito Identity Provider (Cognito User Pool)
Cloud Canvas provides the
Custom::CloudGemFramework::CognitoUserPool
resource for adding the
Amazon Cognito user pools and linking them to a Amazon Cognito identity pool. The Player Account
work with the user pool and the sample level that has an in-game menu.
Configuring External Identity Providers
Cloud Canvas does not automate the process of retrieving an auth code from an external identity provider. This is your responsibility as a game developer. After retrieving the auth code, call gEnv-
>lmbrAWS->->GetClientManager()->Login(providerName, code)
.
External identity providers are configured using the lmbr_aws
loginprovider update (p. 442) , and
login-provider remove (p. 441) commands. These commands save the
Version 1.10
428
Lumberyard Developer Guide
Understanding the Resource Manager Security System configuration in a
/player-access/auth-settings.json
object in the project's configuration bucket so that the
PlayerAccessTokenExchange
Lambda function can access it.
Note
You must run lmbr_aws project update
after running login-provider add
, login-provider update
, or login-provider remove
so that the
PlayerAccessIdentityPool (p. 309)
configuration will be updated to reflect the change.
Automatic Token Refresh
When using Amazon Cognito with external identity providers, it is necessary to periodically refresh the token from that provider and then get updated credentials for that token from Amazon Cognito. Cloud
Canvas performs this token refresh process automatically by using the
PlayerAccessTokenExchange
Lambda function.
You can use the lmbr_aws
command line tool to manage Cloud Canvas Resource Manager access control.
For example, you can use the tool to assume a role when you run a command, or to manage roles, permissions, and role mappings.
Assuming a Role
Most lmbr_aws
commands support an
--assume-role
<role-name>
argument. You can use this argument to assume a role when you run a command.
If specified,
<role-name>
must be the logical resource ID of an IAM role resource defined in either the project-template.json
or deployment-access-template.json
files.
Note
You should avoid defining roles that have the same name in both files. If you do, the role from the deployment file takes precedence.
If you specify a deployment access role, the actual role used depends on the deployment on which the command is operating. If the
--deployment
argument has been specified, then the specified deployment is used. If the
--deployment
argument has not been specified and the user has specified a default deployment, the default deployment is used. If a default deployment has not been specified, the project’s default deployment is used.
lmbr_aws
uses uses your configured AWS credentials to assume the specified role. See Using the Cloud
Canvas Command Line - Configuration for a description of how the credentials are determined. The credentials must have permission to assume the role. For more information, see Granting a User
Permission to Switch Roles .
Before assuming the role, the lmbr_aws
tool uses credentials to read project configuration data from AWS. The
ProjectAccess
managed policy in the project-template.json file
and the
DeploymentAccess
managed policy in the deployment-access-template.json
file grant the permissions necessary to read this information. You can attach the corresponding managed policy to any IAM user that works on a project or deployment.
Note that administrative users created for an AWS account normally have permissions to assume roles and read project configuration. Administrative users typically have permission to perform any action on any resource owned by an account.
Role Management Commands
Role management commands manage the AWS::IAM::Role (p. 423)
resource definitions in the projecttemplate.json
and deployment-access-template.json
files. After you use these commands to make
Version 1.10
429
Lumberyard Developer Guide
Understanding the Resource Manager Security System changes, you must update the project or deployment access stacks for the changes to take effect. For information about the permissions to perform this action, see Setting Access Permissions .
lmbr_aws role add
Adds an AWS IAM Role resource definition to the project-template.json file
or deployment-accesstemplate.json
file.
Argument Description
##role
Required. The name of the role resource definition.
##project
Optional. When present, specifies that the role resource definition be added to the project-template.json file
. Otherwise, the role resource definition is added to the deployment-access-template.json
file.
lmbr_aws role remove
Removes an AWS IAM role resource definition from the project-template.json file
or deploymentaccess-template.json
file.
Argument
##role
<role‑name>
##project
Description
Required. The name of the role resource definition.
Optional. When present, specifies that the role resource definition be removed from the project-template.json file
. Otherwise, the role resource definition is removed from the deployment-accesstemplate.json
file.
lmbr_aws role list
Lists the AWS IAM role definitions in the project-template.json
and/or deployment-accesstemplate.json
files.
Argument Description
Optional. Either
--deployment
or
--project
can be specified. If
--deployment
is specified, only the roles in the deployment-access-template.json
file are listed.
##project
Optional. Either
--deployment
or
--project
can be specified. If
--project
is specified, only the roles in the project-template.json file
are listed.
Output
The output is similar to the following example.
Scope Name
---------- -------------------------------------------
Deployment DeploymentAdmin
Deployment DeploymentOwner
Deployment Player
Deployment PlayerLoginRole
Project ProjectAdmin
Project ProjectOwner
Version 1.10
430
Lumberyard Developer Guide
Understanding the Resource Manager Security System
Project PlayerAccessTokenExchangeExecution
Project ProjectResourceHandlerExecution
Column
Scope
Name
Description
Indicates whether the role is defined in the deployment-access-template.json
or project-template.json
file.
Shows the resource definition name. This is the "logical" resource name, not the "physical" resource name which identifies an actual instance of the role. To see the physical resource names, use the lmbr_aws project list-resources
or lmbr_aws deployment listresources
command.
Permission Metadata Management
The permission metadata management commands manage CloudCanvas
Permissions metadata (p. 310) on resource definitions in the
resource-group-template.json
files. After you use these commands to make changes, you must update the project or deployment access stacks for the changes to take effect. For information about the permissions to perform this action, see Setting Access
Permissions .
lmbr_aws permission add
Adds Cloud Canvas
Permissions
metadata to an resource definition in a resource-group-template.json
file.
Argument Description
##resource#group
Required. The name of a resource group. The metadata will be added to a resource definition in that resource group's resource-group-template.json
file.
##resource
<resource‑name>
template.json
file.
resource-group-
##role
<abstractrole‑name>
Required. Identifies the role that is granted the permission.
##action
Required. The action that is allowed. You can specify more than one action.
##suffix
Optional. A string appended to the resource ARN. You can specify more than one suffix.
lmbr_aws permission remove
Removes Cloud Canvas
Permissions
metadata from a resource definition in a resource-grouptemplate.json
file.
Argument Description
##resource#group
Required. The name of a resource group. The metadata is removed from a resource definition in the specified resource group's resource-grouptemplate.json
file.
##resource
Required. The name of the resource definition in the resource-grouptemplate.json
file.
Version 1.10
431
Lumberyard Developer Guide
Understanding the Resource Manager Security System
Argument Description
##role
Required. Identifies the roles from which permissions are removed.
##action
Optional. The action that is removed. You can specify more than one action. If not specified, all permissions for the role are removed.
##suffix
Optional. A string appended to the resource ARN, which is removed. You can specify more than one suffix.
lmbr_aws permission list
Removes Cloud Canvas
Permissions
metadata from an resource definition in a resource-grouptemplate.json
file.
Argument Description
##resource#group
Optional. Lists the metadata from resource definitions in the resource group's resource-group-template.json
resource groups.
file. The default lists permissions from all
##resource
Optional. The name of the resource definition in the resource-grouptemplate.json
file. The default lists metadata from all resource definitions.
##role
Optional. Lists metadata for the specified abstract role. The default lists metadata for all abstract roles.
Output
The output is similar to the following example.
Resource Group Resource Resource Type Roles Actions
ARN Suffixes
-------------- -------------------- --------------------- --------------
---------------------------------------------------- ------------
DynamicContent ContentBucket AWS::S3::Bucket ServiceLambda s3:GetObject
/*
DynamicContent ContentBucket AWS::S3::Bucket ContentRequest s3:*
/*
DynamicContent ContentRequest AWS::Lambda::Function Player
lambda:InvokeFunction
DynamicContent ServiceLambda AWS::Lambda::Function ServiceApi
lambda:InvokeFunction
DynamicContent StagingSettingsTable AWS::DynamoDB::Table ServiceLambda dynamodb:GetItem,
dynamodb:Scan, dynamodb:UpdateItem
DynamicContent StagingSettingsTable AWS::DynamoDB::Table ContentRequest dynamodb:GetItem
Column Description
Resource
Group
Shows the resource group where the permission metadata was found.
Resource
Shows the name of the resource definition with the metadata.
Resource
Type
Shows the type of the resource definition with the metadata.
Version 1.10
432
Lumberyard Developer Guide
Understanding the Resource Manager Security System
Column Description
Roles
Shows the abstract roles specified by the permission metadata.
Actions
Shows the actions specified by the permission metadata.
ARN
Suffixes
Shows the suffix added to the resource ARN, as specfied by the permission metadata.
Tip
To see all the resources players have access to through the game client, use the command: lmbr_aws permission list --role Player
Role Mapping Metadata Management
Role mapping metadata management commands manage CloudCanvas
RoleMappings
metadata on
AWS::IAM:Role
resource definitions in the project-template.json
and deployment-accesstemplate.json
files. After you use these commands to make changes, you must update the project or deployment access stacks for the changes to take effect. For information about the permissions to perform this action, see Setting Access Permissions .
lmbr_aws role-mapping add
Adds Cloud Canvas
RoleMappings
metadata to an AWS IAM Role definition in the projecttemplate.json
or deployment-access-template.json
file.
Argument Description
##role
<role‑name>
##allow
Required. The name of the role resource definition.
##pattern
Identifies the abstract roles mapped to the role. Has the form
<resourcegroup-name>
.
<abstract-role-name>
, where
<resource-group-name>
can be *.
Either
--allow
or
--deny
must be specified. Indicates that the permissions requested for the abstract role are allowed.
##deny
##project
Either
--allow
or
--deny
must be specified. Indicates that the permissions requested for the abstract role are denied.
Optional. Indicates that the role definition is in the project-template.json
file. The default is for the role definition to be in the deployment-accesstemplate.json
file.
lmbr_aws role-mapping remove
Removes an AWS IAM Role resource definition from the project-template.json file
or deploymentaccess-template.json
file.
Argument Description
##role
<role‑name>
Required. The name of the role resource definition.
##pattern
Identifies the abstract roles mapped to the role. Has the form
<resource-groupname>
.
<abstract-role-name>
, where
<resource-group-name>
can be *.
Version 1.10
433
Lumberyard Developer Guide
Understanding the Resource Manager Security System
Argument
##project
Description
Optional. Indicates that the role definition is in the project-template.json
file
. The default is for the role definition to be in the deployment-accesstemplate.json
file.
lmbr_aws role-mapping list
Lists the AWS IAM Role definitions in the project-template.json
and/or deployment-accesstemplate.json
files.
Argument
##role
<role‑name>
Description
Required. The role definition with the metadata to list. The default is to list metadata from all role definitions.
##pattern
The abstract role pattern specified by the metadata listed. The default is to list metadata with any abstract role pattern.
##deployment
##project
Optional. Either
--deployment
or
--project
can be specified. Lists metadata from role definitions in the deployment-access-template.json
file. The default is to list metadata from role definitions in the project-template.json
and deployment-access-template.json
files.
Optional. Either
--deployment
or
--project
can be specified. Lists metadata from role definitions in the project-template.json file
. The default is to list metadata from role definitions in the project-template.json
and deployment-access-template.json
files.
Output
The output is similar to the following example.
Scope Actual Role Abstract Role Effect
---------- ------------------------------- ----------------------------- ------
Deployment DeploymentAdmin *.DeploymentAdmin Allow
Deployment DeploymentOwner *.DeploymentAdmin Allow
Deployment DeploymentOwner *.DeploymentOwner Allow
Deployment Player *.Player Allow
Project ProjectAdmin *.ProjectAdmin Allow
Project ProjectOwner *.ProjectAdmin Allow
Project ProjectOwner *.ProjectOwner Allow
Column Description
Scope
Shows whether the role mapping came from the access-template.json
files.
project-template.json
or deployment-
Actual
Role
Shows the name of the role resource definition with the mapping metadata.
Shows the abstract roles (as specified on permission metadata) that map to the role.
Abstract
Role
Effect
Shows whether the permissions requested for the abstract role are allowed or denied.
Version 1.10
434
Lumberyard Developer Guide
Using the Command Line
Cloud Canvas provides the
\dev\lmbr_aws.cmd
command line tool for working with AWS resources. The tool invokes Python code that is located in the
\dev\Tools\lmbr_aws
directory.
Notes
• Lumberyard 1.9 has renamed some lmbr_aws
commands. The older commands still work but might be removed at a future date. For a list of the older commands and their newer equivalents, see
• For information on using Dynamic Content Cloud Gem lmbr_aws
commands to update dynamic
content, see Using lmbr_aws for Dynamic Content (p. 241) .
• For information on lmbr_aws
commands for the Cloud Gem Portal and the cloud gem framework, see
Using the Cloud Gem Framework Command Line (p. 400)
.
• For information on lmbr_aws
commands that manage roles and permissions, see Using the Cloud
Canvas Command Line to Manage Roles and Permissions (p. 429)
.
lmbr_aws
{command} {command-arguments}
{command}
is one of commands in the command summary section that follows.
{command-arguments}
are the arguments accepted by the command. Arguments common to most commands are listed in the
section. Arguments unique to a command are listed in the detail section for the command.
The tool gets its default AWS configuration from the same
~/.aws/credentials
and
~/.aws/config
files as the AWS command line tools (for information, see Configuring the AWS Command Line Interface ). The lmbr_aws
tool does not require that the AWS command line interface be installed.
As with the AWS command line tools, the default AWS configuration can be overridden by using the following environment variables.
•
AWS_ACCESS_KEY_ID
The access key for your AWS account.
•
AWS_SECRET_ACCESS_KEY
The secret key for your AWS account.
•
AWS_DEFAULT_REGION
The default region to use; for example, us-east-2
.
•
AWS_PROFILE
The default credential and configuration profile to use, if any.
The following arguments can be used to override the AWS configuration from all other sources:
•
--assume-role
{role-name}
or
-R
{role-name}
– Specifies the IAM role to assume to perform the requested actions. The credentials in the
~/.aws/credentials
file must be able to assume the specified role.
•
--aws-access-key
{access-key}
– The AWS access key that is used.
•
--aws-secret-key
{secret-key}
– The AWS secret key that is used.
Version 1.10
435
Lumberyard Developer Guide
Common Arguments
•
--profile
{profile-name}
or
-P
{profile-name}
– The AWS command line tool profile that is used.
Most of the lmbr_aws
commands accept the following arguments, in addition to their own individual arguments:
•
--aws-directory
{aws}
– Identifies the
{game}
\AWS
directory to use. The default is the value of the sys_game_folder
property from
{root}
\bootstrap.cfg
with
AWS
appended.
•
--game-directory
{directory}
– Location of the game project directory. The default is
{root}
\
{game}
where
{game}
is determined by the sys_game_folder
setting in the
{root}
\bootstrap.cfg
file.
•
--help
or
-h
– Display help for the command.
•
--no-prompt
– Suppresses calls that request user input.
•
--root-directory
{root}
– Identifies the Lumberyard
\dev
directory. The default is the current working directory.
•
--user-directory
{user}
– Location of the user cache directory. The default is
{root}
\Cache
\
{game}
\AWS
where
{game}
is determined by the sys_game_folder
setting in the
{root}
\bootstrap.cfg
file.
•
--verbose
– Shows additional output when executing commands.
Following are details of the lmbr_aws
commands.
Create a complete and independent copy of all the resources needed by the Lumberyard project.
In addition to the Common Arguments (p. 436) , the
deployment create
command accepts the following arguments:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Required. The name of the deployment to create.
•
--enable-capability
{capability}
Optional. A list of capabilities that you must specify before AWS CloudFormation can create or update certain stacks. Some stack templates might include resources that affect permissions in your
AWS account. For those stacks, you must explicitly acknowledge their capabilities by specifying this argument. Possible values include:
CAPABILITY_IAM
.
•
--confirm-aws-usage
or
-C
Optional. Confirms that you know that the deployment create
command will create AWS resources for which you may be charged and that may perform actions that can affect permissions in your AWS account. Specify this argument to disable the related confirmation prompt.
Set or show the default user and project deployments.
In addition to the Common Arguments (p. 436) , the
deployment default
command accepts the following arguments:
Version 1.10
436
Lumberyard Developer Guide
Commands
•
--set
{deployment}
Optional. Sets the default to the provided deployment name.
•
--clear
Optional. Clears the defaults.
•
--show
Optional. Shows the defaults.
•
--project
Optional. Applies
--set
and
--clear
to the project default instead of the user default. Ignored for
-show
.
Only one of the
--set
,
--clear
, and
--show
arguments is allowed.
If
--set
or
--clear
is specified, this command updates the
{root}
\user\AWS\user-settings.json
file.
If
--project
is provided, the
{root}
\
{game}
\AWS\project-settings.json
file is updated.
Delete a complete and independent copy of all the resources needed by the Lumberyard project.
In addition to the Common Arguments (p. 436) , the
deployment delete
command accepts the following arguments:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Required. The name of the deployment to delete.
•
--enable-capability
{capability}
Optional. A list of capabilities that you must specify before AWS CloudFormation can create or update certain stacks. Some stack templates might include resources that can affect permissions in your
AWS account. For those stacks, you must explicitly acknowledge their capabilities by specifying this argument. Possible values include:
CAPABILITY_IAM
.
•
--confirm-resource-deletion
Optional. Acknowledges that the command will permanently delete the resources belonging to the specified deployment. If not specified, the user is prompted to confirm the deletion.
Note
AWS CloudFormation cannot delete stacks that define Amazon S3 buckets that contain data. To allow project stacks to be deleted, the project-template.json
file specifies a
DeletionPolicy of
Retain
for the configuration bucket. This causes AWS CloudFormation to not delete the bucket when the project stack is deleted. After the project stack has been deleted, the command removes all the objects from the configuration bucket and then deletes the bucket.
List all deployments in the local project.
Example output:
Name Status Reason
Timestamp Id
Version 1.10
437
Lumberyard Developer Guide
Commands
----------------- ---------------
----------------------------------------------------------------------------
-----------------
--------------------------------------------------------------------------------------------------------------------------
AnotherDeployment CREATE_PENDING Resource is defined in the local project template but
does not exist in AWS.
Development CREATE_COMPLETE
03/04/16 18:43:11 arn:aws:cloudformation:useast-2:
<ACCOUNTID>
:stack/foo-hw-Development-ZDLXUB7FKR94/8e6492f0e248-11e5-8e7e-50d5ca6e60ae
User Default Deployment: (none)
Project Default Deployment: Development
Release Deployment: (none)
List all of the resources associated with the project.
In addition to the Common Arguments (p. 436) , the
deployment list-resources
command accepts the following arguments:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. The name of the deployment to list resources for. If not specified, lists all the project's resources.
Marks a deployment as protected and issues a warning when a user (for example, a developer or tester) attempts to connected a development game client to live resources. For more information, see
Protected Deployments (p. 418) .
In addition to the Common Arguments (p. 436) , the
deployment protect
command accepts the following arguments:
•
--set
{deployment-name}
Optional. Specifies that the deployment is protected.
•
--clear
{deployment-name}
Optional. Specifies that the deployment is not protected.
•
--show
Optional. Displays a list of the deployments that are currently protected.
Note
To display the protected status of deployments, you can also use either the deployment list (p. 437)
or
command.
Sets, shows, or removes the release deployment.
In addition to the Common Arguments (p. 436) , the
deployment release
command accepts the following arguments:
Version 1.10
438
Lumberyard Developer Guide
Commands
•
--set
{deployment-name}
Required. The name of the deployment to set as the release.
•
--clear
{capability}
Removes the release designation from the current release deployment.
•
--show
Shows the deployment that is currently configured as the release deployment.
Sets, shows, or removes the release deployment.
In addition to the Common Arguments (p. 436) , the
deployment update-access
command accepts the following arguments:
•
--confirm-aws-usage
or
-C
Optional. Confirms that you know this command creates AWS resources for which you can be charged and that it may perform actions that can affect permissions in your AWS account. Specify this argument to disable the related confirmation prompt.
•
--confirm-resource-deletion
Optional. If the operation will delete resources permanently, confirms your acknowledgement and approval. If this argument is not specified, you are prompted to confirm completion of the operation.
Specify this argument to disable the related confirmation prompt.
•
--confirm-security-change
Optional. Confirms that you know that this command may make security-related changes. Specify this argument to disable the related confirmation prompt.
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. The name of the deployment whose access stack is updated. If omitted, the default deployment is updated. Use * to update all deployments.
Updates a deployment. deployment upload
or deployment update
can be used instead of deployment upload-resources
.
In addition to the Common Arguments (p. 436) , the
deployment upload
command accepts the following arguments:
•
--confirm-aws-usage
or
-C
Optional. Confirms that you know this command creates AWS resources for which you can be charged and that it may perform actions that can affect permissions in your AWS account. Specify this argument to disable the related confirmation prompt.
•
--confirm-resource-deletion
Optional. If the operation will delete resources permanently, confirms your acknowledgement and approval. If this argument is not specified, you are prompted to confirm completion of the operation.
Specify this argument to disable the related confirmation prompt.
•
--confirm-security-change
Version 1.10
439
Lumberyard Developer Guide
Commands
Optional. Confirms that you know that this command may make security-related changes. Specify this argument to disable the related confirmation prompt.
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. The name of the deployment to update. If omitted, the default deployment is updated.
Retrieves data from a CloudWatch Logs log file.
In addition to the Common Arguments (p. 436) , the
function get-log
command accepts the following arguments:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. The name of a deployment. If this argument is specified, the
--resource-group
argument must also be specified. If this argument is omitted, then the function must exist in the project stack.
•
--function
{function-name}
or
-f
{function-name}
Required. The logical name of a Lambda function resource.
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Optional. The name of a resource group. If specified, the
--deployment
argument must also be specified.
•
--log-stream-name
{log-stream-name}
or
-l
{log-stream-name}
Optional. The log stream name or partial log stream name. If omitted, the most recent log stream is shown.
asdf
In addition to the Common Arguments (p. 436) , the
function upload-code
command accepts the following arguments:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. The name of a deployment to update. If this argument is not specified, the default deployment is updated.
•
--function
{function-name}
Required. The name of the Lambda function to update. If not specified, all Lambda functions in the resource group are updated.
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Optional. The name of a resource group to update. If not specified, all resource groups in the deployment are updated.
Add a player login provider to the Amazon Cognito identity pool configuration. Login providers allow your game's players to log in using their social network identity, such as Facebook or using their Amazon
user identity. For more information, see Controlling Access to Resources (p. 420) .
Version 1.10
440
Lumberyard Developer Guide
Commands
In addition to the Common Arguments (p. 436) , the
login-provider add
command accepts the following arguments:
•
--provider
{provider-name}
Required. The name of the provider. The name must be amazon
or facebook
, or, if you are using a generic OpenID provider, a name that you choose.
•
--app-id
{application-id}
Required. The application id from your login provider (this is usually different from your client ID).
•
--client-id
{client-id}
Required. The unique application client ID for the login provider.
•
--client-secret
{client-secret}
Required. The secret key to use with your login provider.
•
--redirect-uri
{redirect-uri}
Required. The redirect URI to use with your login provider.
•
--provider-uri
{provider-uri}
Optional. The URI for a generic open ID connect provider. This is only use for generic OpenID providers.
•
--provider-port
{provider-port}
Optional. The port your provider listens on for its API. This is only used for generic OpenID providers.
•
--provider-path
{provider-path}
Optional. The path portion of your provider's URI. This is only used for generic OpenID providers.
This command saves its configuration in a player-access/auth-settings.json
object in the project's configuration bucket so that the
PlayerAccessTokenExchange
Lambda function can access it.
Note
You must run project upload
after running this command so that the
PlayerAccessIdentityPool (p. 309)
configuration is updated to reflect the change.
Remove a player login provider from the Amazon Cognito identity pool configuration.
In addition to the Common Arguments (p. 436) , the
login-provider remove
command accepts the following argument:
•
--provider
{provider-name}
Required. The name of the provider.
The login-provider remove
command saves the configuration in a
/player-access/authsettings.json
object in the project's configuration bucket so that the
PlayerAccessTokenExchange
Lambda function can access it.
Note
You must run lmbr_aws project upload
after running this command so that the
PlayerAccessIdentityPool (p. 309)
configuration is updated to reflect the change.
Version 1.10
441
Lumberyard Developer Guide
Commands
Update a player login provider in the Amazon Cognito identity pool configuration. Login providers allow your game's players to log in using their social network identity, such as Facebook, or using their Amazon
user identity. For more information, see Controlling Access to Resources (p. 420) .
In addition to the Common Arguments (p. 436) , the
login-provider update
command accepts the following arguments:
•
--provider
{provider-name}
Required. The name of the updated provider. The name must be amazon
or facebook
, or, if you are using a generic OpenID provider, the name that you chose when the provider was added.
•
--app-id
{application-id}
Optional. The application ID from your login provider (this is usually different from your client ID).
•
--client-id
{client-id}
Optional. The unique application client ID for the login provider.
•
--client-secret
{client-secret}
Optional. The secret key to use with your login provider.
•
--redirect-uri
{redirect-uri}
Optional. The redirect URI to use with your login provider.
•
--provider-uri
{provider-uri}
Optional. The URI for a generic open id connect provider. This argument is used only for generic
OpenID providers.
•
--provider-port
{provider-port}
Optional. The port the provider listens on for the provider's API. This argument is used only for generic
OpenID providers.
•
--provider-path
{provider-path}
Optional. The path portion of the provider's URI. This argument is used only for generic OpenID providers.
The login-provider update
command saves its configuration in a
/player-access/authsettings.json
object in the project's configuration bucket so that the
PlayerAccessTokenExchange
Lambda function can access it.
Note
You must run lmbr_aws project upload
after running this command so that the
PlayerAccessIdentityPool (p. 309)
configuration is updated to reflect the change.
Show the logical to physical resource name mappings.
Example output:
Name Type Id
--------------------------------------- ---------------------------
----------------------------------------------------------------
Version 1.10
442
Lumberyard Developer Guide
Commands
HelloWorld.SayHello AWS::Lambda::Function foo-hw-Development-
ZDLXUB7FKR94-HelloWo-SayHello-1FADMFNE5M1CO
PlayerAccessIdentityPool Custom::CloudGemFramework::CognitoIdentityPool
us-east-2:108f6d6a-f929-4212-9947-a03269b9582e
PlayerLoginIdentityPool Custom::CloudGemFramework::CognitoIdentityPool
us-east-2:3020e175-0ddd-4860-8dad-1db57162cbb2
PlayerAccessTokenExchange AWS::Lambda::Function foo-hw-
PlayerAccessTokenExchange-1BG6JJ94IZAUV account_id Configuration
<ACCOUNTID>
region Configuration us-east-2
Update the friendly name to physical resource ID mappings to reflect the current default deployment or the release deployment.
In addition to the Common Arguments (p. 436) , the
mappings update
command accepts the following arguments:
•
--release
Optional. Causes the release mappings to be updated. By default, only the mappings used when launching the game from inside the editor are updated.
The command looks in the resource-template.json (p. 307) file for
Metadata.CloudCanvas.PlayerAccess
properties on resource definitions. It then queries AWS
CloudFormation for the physical names of those resources in the current default deployment. If the
-release
argument is specified, the release deployment is queried.
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. Exports a mapping file for the specified deployment to the
{project_directory}
\Config directory in the format
{deployment-name}
.awsLogicalMappings.json
.
When you run a game launcher such as the one at dev\Bin64\SamplesProjectLauncher.exe
, you can choose the mapping to use by using the
-cc_override_resource_map
argument. For more information, see
Selecting a Deployment with a PC Launcher (p. 418)
.
Clears the specified parameter configuration for your project. The project must be initialized (a project stack must have been created) before you can clear parameters.
In addition to the Common Arguments (p. 436) , the
parameter clear
command accepts the following arguments:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. Clears the parameter value for the specified deployment.
{deployment-name}
can be *, in which case the parameter value used for all deployments that do not override the value is cleared. If omitted, the parameter value is cleared for all deployments, including *.
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Optional. Clears the parameter value for the specified resource-group.
{resource-group-name}
can be *, in which case the parameter value used for all resource groups that do not override the value is cleared. If omitted, the parameter value is cleared for all resource groups, including *.
•
--parameter
{parameter-name}
or
-p
{parameter-name}
Required. The parameter to clear.
Version 1.10
443
Lumberyard Developer Guide
Commands
Lists the parameters currently configured for your project. The project must be initialized (a project stack must have been created) before you can list parameters.
In addition to the Common Arguments (p. 436) , the
parameter list
command accepts the following arguments:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Required. Limits the list to the specified deployment.
{deployment-name}
can be *, in which case parameters that apply to all deployments are listed.
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Required. Limits the list to the specified resource group.
{resource-group-name}
can be *, in which case parameters that apply to all resource groups are listed.
•
--parameter
{parameter-name}
or
-p
{parameter-name}
Optional. Limits the list to the specified parameter.
Sets parameter configuration for your project. The project must be initialized (a project stack must have been created) before you can set parameters.
In addition to the Common Arguments (p. 436) , the
parameter set
command accepts the following arguments:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Required. Sets the parameter value for the specified deployment.
{deployment-name}
can be *, in which case the parameter value is used for all deployments that do not override the value.
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Required. Sets the parameter value for the specified resource group.
{resource-group-name}
can be *, in which case the parameter value is used for all resource groups that do not override the value.
•
--parameter
{parameter-name}
or
-p
{parameter-name}
Required. Specifies the parameter whose value will be set.
•
--value
{parameter-value}
or
-v
{parameter-value}
Required. Specifies the value to set.
Add an AWS profile to the AWS command line tool configuration.
In addition to the Common Arguments (p. 436) , the
profile add
command accepts the following arguments:
•
--aws-access-key
{accesskey}
Required. The AWS access key associated with the added profile.
•
--aws-secret-key
{secretkey}
Version 1.10
444
Lumberyard Developer Guide
Commands
Required. The AWS secret key associated with the added profile.
•
--profile
{profile-name}
or
-P
{profile-name}
Required. The name of the AWS profile to add.
•
--make-default
Optional. Make the new profile the default profile.
Set, clear, or show the default profile in the AWS command line tool configuration.
In addition to the Common Arguments (p. 436) , the
profile default
command accepts the following arguments:
•
--set
{deploymentname}
Optional. Set the default profile to the provided deployment name.
•
--clear
Optional. Clear the default profile.
•
--show
Optional. Show the default profile.
List the AWS profiles that have been configured.
Remove an AWS profile from the AWS command line tool configuration.
In addition to the Common Arguments (p. 436) , the
profile remove
command accepts the following argument:
•
--profile
{profile-name}
or
-P
{profile-name}
Required. The name of the AWS profile to remove.
Rename an AWS profile in the AWS command line tool configuration.
In addition to the Common Arguments (p. 436) , the
profile rename
command accepts the following arguments:
•
--old
{old-profile-name}
Required. The name of the AWS profile to change.
•
--new
{new-profile-name}
Required. The new name of the AWS profile.
Version 1.10
445
Lumberyard Developer Guide
Commands
Update an AWS profile.
In addition to the Common Arguments (p. 436) , the
profile update
command accepts the following arguments:
•
--aws-access-key
{accesskey}
Optional. The AWS access key associated with the updated profile. The default is to not change the
AWS access key associated with the profile.
•
--aws-secret-key
{secretkey}
Optional. The AWS secret key associated with the updated profile. The default is to not change the
AWS secret key associated with the profile.
•
--profile
{profilename}
or
-P
{profile-name}
Required. The name of the AWS profile to update.
Note
To make an existing profile the default profile, use the
command.
Initialize Cloud Canvas resource management for a Lumberyard project. This includes creating a set
of default Resource Definitions (p. 306) in the
dev\
{game}
\AWS
directory and a AWS CloudFormation stack that contains the resources that the Cloud Canvas resource manager uses to manage your game resources.
In addition to the Common Arguments (p. 436) , the
project create
command accepts the following arguments:
•
--stack
{stack-name}
Optional. The name used for the project's AWS CloudFormation stack. The default is the name of the
{game}
directory.
•
--confirm-aws-usage
or
-C
Optional. Confirms that you know this command will create AWS resources for which you may be charged and that it may perform actions that can affect permissions in your AWS account. Specify this argument to disable the related confirmation prompt.
•
--enable-capability
{capability}
[
{capability}
...]
Optional. A list of capabilities that you must specify before AWS CloudFormation can create or update certain stacks. Some stack templates might include resources that can affect permissions in your
AWS account. For those stacks, you must explicitly acknowledge their capabilities by specifying this argument. Possible values include
CAPABILITY_IAM
.
•
--files-only
Optional. Writes the default configuration data to the
{game}
\AWS
directory and exits. The directory must be empty or must not exist.
•
--region
{region}
Required. The AWS region in which the project stack will be created.
Version 1.10
446
Lumberyard Developer Guide
Commands
Note
The region
argument can be used only with the project create
and resource-importer list-importable-resources
commands.
How project create
works
1. The project create
command creates the project's AWS CloudFormation stack using a bootstrap template that defines only the
Configuration Bucket (p. 317) resource.
2. The
project-template.json (p. 308)
file and the zipped up contents of the
project-code subdirectory (p. 310)
are uploaded to the Configuration Bucket (p. 317)
.
3. An AWS CloudFormation stack update operation is performed by using the uploaded projecttemplate.json
file. The project-code .zip
file is used to create the Lambda function resources defined by the project-template.json
file.
Note
• If the
{root}
\
{game}
\AWS
directory is empty or does not exist, project create creates the directory if necessary and copies the contents of the dev\Tools\lmbr_aws
\AWSResourceManager\default-project-content
directory to that directory.
• project create
fails if a stack with the specified name already exists in the configured AWS account and region. In this case you can use the
--stack
argument to specify a different name for the project stack.
• project create
fails if the dev\
{game}
\AWS\local-project-settings.json
file has a nonempty
ProjectStackId
property. Initially, the
ProjectStackId
property is not present in the local-project-settings.json
file. After the project stack is created in step 1, the
ProjectStackId
property is written to the file and is the project's AWS CloudFormation stack
ID .
• If the stack update process in step 2 fails on the first attempt, you can retry by using the project upload
command.
Creates an extension template for adding project, deployment, or deployment access resources that complement the existing project-template.json
, deployment-template.json
, or deployment-accesstemplate.json
files.
In addition to the Common Arguments (p. 436) , the
project create-extension-template
command accepts the following arguments:
•
--project
Optional. Creates a project-template-extensions.json
file in the project directory.
•
--deployment
Optional. Creates a deployment-template-extensions.json
file in the project directory.
•
--deployment-access
Optional. Creates a deployment-access-template-extensions.json
file in the project directory.
Version 1.10
447
Lumberyard Developer Guide
Commands
Delete the AWS CloudFormation stack that contains your project's resources. You must delete all of the project's deployments before deleting the project stack. After deleting the project stack, you must create a new project stack before you can use AWS CloudFormation resource manager for your project.
In addition to the Common Arguments (p. 436) , the
project delete
command accepts the following argument:
•
--confirm-resource-deletion
Optional. Confirms your acknowledgement and approval that the operation will delete resources permanently. If this argument is not specified, you will be prompted to confirm completion of the operation. Specify this argument to disable the related confirmation prompt.
AWS CloudFormation cannot delete stacks that define Amazon S3 buckets that contain data. To allow project stacks to be deleted, the project-template.json
file specifies a
DeletionPolicy
of
Retain
for the configuration bucket. This causes AWS CloudFormation to not delete the bucket when the project stack is deleted. After the project stack has been deleted, the command removes all the objects from the configuration bucket and then deletes the bucket.
List all of the resources associated with the project.
In addition to the Common Arguments (p. 436) , the
project list-resources
command accepts the following argument:
•
--stack-id
{stackid}
Optional. The ARN of the stack to list resources for. Defaults to project, deployment, or resource group
ID as determined by the
--deployment
and
--resource-group
arguments.
Updates the code for a project.
In addition to the Common Arguments (p. 436) , the
project update-code
command accepts the following argument:
•
--confirm-replacement
Optional. Confirm that it is OK to replace existing files. Specify this argument to disable the related confirmation prompt.
Update the project's AWS CloudFormation stack. project update
can be used instead of project upload
.
In addition to the Common Arguments (p. 436) , the
project upload
command accepts the following arguments:
•
--confirm-aws-usage
or
-C
Version 1.10
448
Lumberyard Developer Guide
Commands
Optional. Confirms that you know this command will create AWS resources for which you may be charged and that it may perform actions that can affect permission in your AWS account. Specify this argument to disable the related confirmation prompt.
•
--confirm-resource-deletion
Optional. If the operation will delete resources permanently, confirms your acknowledgement and approval. If this argument is not specified, you are prompted to confirm completion of the operation.
Specify this argument to disable the related confirmation prompt.
•
--enable-capability
{capability}
[
{capability}
...]
Optional. A list of capabilities that you must specify before AWS CloudFormation can create or update certain stacks. Some stack templates might include resources that can affect permissions in your
AWS account. For those stacks, you must explicitly acknowledge their capabilities by specifying this argument. Possible values include
CAPABILITY_IAM
.
How project upload
works
1. The
project-template.json (p. 308)
file and the zipped up contents of the
project-code subdirectory (p. 310)
are uploaded to the Configuration Bucket (p. 317)
.
2. An AWS CloudFormation stack update operation is performed by using the uploaded projecttemplate.json
file. The project-code.zip
file is used when creating the Lambda function resources defined by the templates.
Note
The project upload
command fails if the dev\
{game}
\AWS\local-project-settings.json
file does not exist or does not have a valid
ProjectStackId
property.
Add a
ResourceGroupConfiguration
and AWS CloudFormation stack resources to your deploymenttemplate.json
file. For more information, see
deployment-template.json (p. 308) .
The command also creates a
{game}
\resource-group\
{resource-group-name}
directory with a default resource-template.json
file and lambda-function-code
subdirectory.
In addition to the Common Arguments (p. 436) , the
resource-group add
command accepts the following argument:
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Required. The name of the resource group to add.
•
--gem
{gem-directory-path}
Optional. If the path argument is not present, specifies that a gem resource group definition is in the
\dev\Gem\
{resource-group-name}
directory. The
{resource-group-name}
is the resource group that is specified in the
--resource-group
argument. The optional
{gem-directory-path}
argument specifies a relative or full path to the gem directory. "Relative" means relative to the current working directory.
•
--include-example-resources
Optional. Includes "Hello World" example resources.
Version 1.10
449
Lumberyard Developer Guide
Commands
List all the resource groups found in the local deployment template and in the selected deployment in
AWS.
In addition to the Common Arguments (p. 436) , the
resource-group list
command accepts the following argument:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. The name of the deployment to list resource groups for. If not given, the default deployment is used.
Example output:
Name Status Reason
Timestamp Id
-------------- ---------------
-------------------------------------------------------------------------------
-----------------
--------------------------------------------------------------------------------------------------------------------------------------------------
AnotherResourceGroup CREATE_PENDING Resource is defined in the local deployment template
but does not exist in AWS.
HelloWorld CREATE_COMPLETE
03/04/16 18:42:57 arn:aws:cloudformation:useast-2:
<ACCOUNTID>
:stack/foo-hw-Development-ZDLXUB7FKR94-HelloWorld-WSGZ15EUWX52/9b909d20e238-11e5-a98d-50fae987c09a
List all of the resources associated with the project.
In addition to the Common Arguments (p. 436) , the
resource-group list-resources
command accepts the following arguments:
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. The name of the deployment to list resources for. If not specified, lists all the project's resources.
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Optional. The name of the resource group to list resources for. If specified, deployment
must also be specified. If not specified, all deployment or project resources are listed.
Remove a resource group's
ResourceGroupConfiguration
and AWS CloudFormation stack resources from your deployment-template.json
file. You must update your deployment stacks before the resources defined by your resource group can be removed from AWS.
The command does not delete the
{game}
\resource-group\
{resource-group-name}
directory.
In addition to the Common Arguments (p. 436) , the
resource-group remove
command accepts the following argument:
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Required. The name of the resource group to be removed.
Version 1.10
450
Lumberyard Developer Guide
Commands
AWS CloudFormation cannot delete stacks that define Amazon S3 buckets that contain data. To allow project stacks to be deleted, the project-template.json
file specifies a
DeletionPolicy
of
Retain
for the configuration bucket. This causes AWS CloudFormation to not delete the bucket when the project stack is deleted. After the project stack has been deleted, the command removes all the objects from the configuration bucket and then deletes the bucket.
Update a resource group's AWS CloudFormation stack in a deployment. resource-group upload
or resource-group update
can be used instead of resource-group upload-resources
.
In addition to the Common Arguments (p. 436) , the
resource-group upload
command accepts the following arguments:
•
--confirm-aws-usage
or
-C
Optional. Confirms that you know this command will create AWS resources for which you may be charged and that it may perform actions that can affect permissions in your AWS account. Specify this argument to disable the related confirmation prompt.
•
--confirm-resource-deletion
Optional. If the operation will delete resources permanently, confirms your acknowledgement and approval. Specify this argument to disable the related confirmation prompt.
•
--confirm-security-change
Optional. Confirms that you know that this command may make security-related changes. Specify this argument to disable the related confirmation prompt.
•
--deployment
{deployment-name}
or
-d
{deployment-name}
Optional. The name of the deployment to update. If not specified, the default deployment is updated.
•
--resource-group
{resource-group-name}
, or
-r
{resource-group-name}
Required. The name of the resource group to update. If not specified, all resource groups in the deployment are updated.
Import a resource to a resource group.
In addition to the Common Arguments (p. 436) , the
resource-importer import-resource
command accepts the following arguments:
•
--type
{dynamodb|s3|lambda|sns|sqs}
Optional. The type of the AWS resource to import. Choose from
dynamodb
,
s3
,
lambda
,
sns
or
sqs
.
•
--arn
ARN
Required. The ARN of the AWS resource to import.
•
--resource-name
{resource-name}
Required. The name of the resource to import.
•
--resource-group
{resource-group-name}
or
-r
{resource-group-name}
Required. The name of the resource group to import.
•
--download
Optional. If specified, downloads the contents of the Amazon S3 bucket.
Version 1.10
451
Lumberyard Developer Guide
Command Reorganization
List all supported resources currently existing on AWS.
In addition to the Common Arguments (p. 436) , the
resource-importer list-importable-resources command accepts the following arguments:
•
--type
{dynamodb|s3|lambda|sns|sqs}
Required. The type of the AWS resource to list. Choose from
dynamodb
,
s3
,
lambda
,
sns
or
sqs
.
•
--region
{region}
Optional. The AWS region of the resources. The default value is the region of the project stack, if it exists.
Note
The region
argument can be used only with the resource-importer list-importableresources
and project create
commands.
As of Lumberyard 1.9, the commands made available by the lmbr_aws
command line tool have been reorganized. The previous commands are still functional but are subject to removal in a future release.
The following table shows how the previous commands map to the new commands. In a few cases single commands have been split into two or more commands for clarity and ease of use. These are
commented accordingly. For information about the commands, see Using the Cloud Canvas Command
Previous
Command
New Command
add#login#providerlogin#provider add add#profile profile add add#resource#groupresource#group add clear#parameter parameter clear create#deployment deployment create default#deploymentdeployment default default#profile profile default delete#deployment deployment delete get#function#log function get#log import#resource resource#importer import#resource list#deployments deployment list
Version 1.10
452
Lumberyard Developer Guide
Command Reorganization
Previous
Command
New Command
list#mappings mappings list list#parameters parameter list list#profiles profile list list#resources project list#resources deployment list#resources resource#group list#resources
The list#resources
command supported
##deployment
and
##resource#group arguments. It also supported a
##stack#id
argument.
The project list#resources
command is the same as list#resources without the
##deployment
and
##resource#group
arguments. The project list#resources
command still supports the
##stack#id
argument.
The deployment list#resources
command is the same as list#resources
with only the
##deployment
argument. The deployment list#resources
command does not support the
##stack#id
argument.
The resource#group list#resources
command is the same as list#resources with both the
##deployment
and
##resource#group
arguments. The resource#group list#resources
command does not support the
##stack#id argument.
protect#deploymentdeployment protect release#deploymentdeployment release remove#profile profile remove rename#profile set#parameter profile rename parameter set update#mappings mappings update update#profile profile update
You can use project update
instead of project upload
.
upload#lambda#codefunction upload#code
Version 1.10
453
Lumberyard Developer Guide
Command Reorganization
Previous
Command
New Command
upload#resources deployment upload resource#group upload
The upload#resources
command supported a
##resource#group
argument.
The deployment upload
command is the same as upload#resources
without the
##resource#group
argument.
The resource#group upload
command is the same as upload#resources
with the
##resource#group
argument.
You can use deployment update
and resource#group update
instead of deployment upload
and resource#group upload
.
As a convenience, aliases have been added for the following common arguments.
Argument
##assume#role
##confirm#aws#usage
##deployment
##function
##log#stream#name
##parameter
##profile
##resource#group
##value
Alias Equivalent
#l
#p
#P
#r
#v
#R
#C
#d
#f
Version 1.10
454
Lumberyard Developer Guide
Programmer's Guide to Entities and Components
The component entity system is currently in preview and is undergoing active development. It will
replace the legacy Entity System (p. 551)
.
Amazon Lumberyard's component entity system provides a modular and intuitive way to construct games. The component entity system works at both the system level and the entity level. It employs reflection, serialization, event bus (EBus) messaging, and fully cascading prefabs (slices).
This section of the Amazon Lumberyard Developer Guide offers a
Programmer's Guide to Entities and
that covers these topics in depth. For information on using the component entity system in Lumberyard Editor, see Component Entity System in the Amazon Lumberyard User Guide .
Topics
•
Programmer's Guide to Entities and Components (p. 455)
•
•
•
Slices and Dynamic Slices (p. 488)
•
Using Gems to Add C++ Code to a Lumberyard Game (p. 491)
The component entity system is currently in preview and is undergoing active development. It will
replace the legacy Entity System (p. 551)
.
This guide provides engine and game programmers with examples and best practices for creating and reflecting custom Lumberyard components in C++. For information on using the component entity system in Lumberyard Editor, see Component Entity System in the Amazon Lumberyard User Guide . For
C++ API reference documentation on the component entity system, see the Amazon Lumberyard C++ API
Reference .
Topics
•
•
Registering Your Component (p. 458)
•
Reflecting a Component for Serialization and Editing (p. 458)
Version 1.10
455
Lumberyard Developer Guide
Creating a Component
•
Defining and Using Component Services (p. 463)
•
•
Creating System Components (p. 467)
•
Components and EBuses (p. 469)
•
Tick Bus and Components (p. 472)
•
Exposing Custom Components to Track View for Animation (p. 473)
•
Components and EBuses: Best Practices (p. 478)
A component in Lumberyard is a simple class that inherits from Lumberyard's
AZ::Component
. A component's behavior is determined by its reflected data and the actions it takes when it is activated.
This section shows you how to create Lumberyard components programmatically. For information about adding and customizing the components available in Lumberyard Editor, see Component Entity System in the Amazon Lumberyard User Guide .
An example component class skeleton follows: class MyComponent
: public AZ::Component
{ public:
AZ_COMPONENT(MyComponent, "{0C09F774-DECA-40C4-8B54-3A93033EC381}");
// AZ::Component interface implementation.
void Init() override {}
void Activate() override {}
void Deactivate() override {}
// Required Reflect function.
static void Reflect(AZ::ReflectContext* context);
// Optional functions for defining provided and dependent services.
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType&
provided);
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType&
dependent);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType&
required);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType&
incompatible);
};
The required and optional members that a component comprises are as follows:
AZ::Component
Every component must include
AZ::Component
somewhere in its inheritance ancestry. Noneditor components generally inherit directly from
AZ::Component
, as in the following example: class MyComponent
: public AZ::Component
Version 1.10
456
Lumberyard Developer Guide
Creating a Component
You can also create your own component class hierarchies.
AZ_COMPONENT Macro
Every component must specify the
AZ_COMPONENT
macro in its class definition. The macro takes two arguments:
1. The component type name.
2. A unique UUID. You may use any UUID generator to produce the value. Visual Studio provides this functionality through
Tools
,
Create GUID
. Use the
Registry Format
setting, and then copy and paste the value that is generated.
A sample
AZ_COMPONENT
macro follows:
AZ_COMPONENT(MyComponent, "{0C09F774-DECA-40C4-8B54-3A93033EC381}");
AZ::Component Functions
To define a component's behavior, you generally override three
AZ::Component
functions:
Init
,
Activate
, and
Deactivate
: void
Init
() override {} void
Activate
() override {} void
Deactivate
() override {}
These functions are as described as follows:
Init()
(Optional) Called only once for a given entity. It requires minimal construction or setup work, since the component may not be activated anytime soon. An important best practice is to minimize your component's CPU and memory overhead while the component is inactive.
Activate()
(Required) Called when the owning entity is being activated. The system calls your component's
Activate()
function only if all dependent or required services are present. Your
Activate function is always called after any components that it depends on. In addition, the component makeup of an entity never changes while the entity is active. Consequently, it is safe to cache pointers or references to other components on the entity when performance is critical.
Deactivate()
Reflect()
(Required) Called when the owning entity is being deactivated. The order of deactivation is the reverse of activation, so your component is deactivated before the components it depends on. As a best practice, make sure your component returns to a minimal footprint when it is deactivated. In general, deactivation should be symmetric to activation.
Note
Deactivation does not necessarily precede destruction. An entity can be deactivated and then activated again without being destroyed, so ensure that your components support this efficiently. However, when you do destroy your entity, Lumberyard ensures that your
Deactivate()
function is called first. Components must be authored with this in mind.
(Required) All components are AZ reflected classes. Because all components must be serializable and editable, they must contain a
Reflect()
function, as in the following example:
// Required Reflect function.
static void
Reflect
(AZ::ReflectContext* context);
Version 1.10
457
Lumberyard Developer Guide
Registering Your Component
For more information, see
Reflecting a Component for Serialization and Editing (p. 458) .
Logical Services
(Optional) Components can define any combination of logical services that they provide, depend on, require, or are incompatible with. To define these logical services, use the following functions:
// Optional functions for defining provided and dependent services.
static void
GetProvidedServices
(AZ::ComponentDescriptor::DependencyArrayType&
provided); static void
GetDependentServices
(AZ::ComponentDescriptor::DependencyArrayType&
dependent); static void
GetRequiredServices
(AZ::ComponentDescriptor::DependencyArrayType&
required); static void
GetIncompatibleServices
(AZ::ComponentDescriptor::DependencyArrayType&
incompatible);
You register a component during application startup. You implement the registration in the
AZ::Module class
of the module in which the component is written.
The following example module creates descriptors for the components that are declared within the module.
//MyModule.cpp
MyModule::MyModule()
{
// Create descriptors for components declared within this module.
m_descriptors.insert(m_descriptors.end(), {
MyComponent::CreateDescriptor(),
});
}
For more information, see the Module Class
section of the AZ Modules (p. 161)
documentation.
Components use AZ reflection to describe the data they serialize and how content creators interact with them.
The following example reflects a component for serialization and editing: class MyComponent
: public AZ::Component
{
...
enum class SomeEnum
{
EnumValue1,
EnumValue2,
}
float m_someFloatField;
AZStd::string m_someStringField;
SomeEnum m_someEnumField;
AZStd::vector<SomeClassThatSomeoneHasReflected> m_things;
Version 1.10
458
Lumberyard Developer Guide
Reflecting a Component for Serialization and Editing
int m_runtimeStateNoSerialize;
}
/*static*/ void MyComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
if (serialize)
{
// Reflect the class fields that you want to serialize.
// In this example, m_runtimeStateNoSerialize is not reflected for serialization.
serialize->Class<MyComponent>()
->Version(1)
->Field("SomeFloat", &MyComponent::m_someFloatField)
->Field("SomeString", &MyComponent::m_someStringField)
->Field("Things", &MyComponent::m_things)
->Field("SomeEnum", &MyComponent::m_someEnumField)
;
AZ::EditContext* edit = serialize->GetEditContext();
if (edit)
{
edit->Class<MyComponent>("My Component", "The World's Most Clever Component")
->DataElement(AZ::Edit::DefaultHandler, &MyComponent::m_someFloatField,
"Some Float", "This is a float that means X.")
->DataElement(AZ::Edit::DefaultHandler, &MyComponent::m_someStringField,
"Some String", "This is a string that means Y.")
->DataElement("ComboBox", &MyComponent::m_someEnumField, "Choose an Enum",
"Pick an option among a set of enum values.")
->EnumAttribute(MyComponent::SomeEnum::EnumValue1, "Value 1")
->EnumAttribute(MyComponent::SomeEnum::EnumValue2, "Value 2")
->DataElement(AZ::Edit::DefaultHandler, &MyComponent::m_things, "Bunch of
Things", "A list of things for doing Z.")
;
}
}
}
The preceding example adds five data members to
MyComponent
. The first four data members will be serialized. The last data member will not be serialized because it contains only the run-time state. This is typical; components commonly contain some members that are serialized and others that are not.
It is common for fields to be reflected for serialization, but not for editing, when using advanced
reflection features such as change callbacks (p. 462)
. In these cases, components may conduct complex internal calculations based on user property changes. The result of these calculations must be serialized but not exposed for editing. In such a case, you reflect the field to
SerializeContext
but do not add an entry in
EditContext
. An example follows: serialize->Class<MyComponent>()
->Version(1)
...
->Field("SomeFloat", &MyComponent::m_someFloatField)
->Field("MoreData", &MyComponent::m_moreData)
...
;
...
AZ::EditContext* edit = serialize->GetEditContext(); if (edit)
{
edit->Class<MyComponent>("My Component", "The World's Most Clever Component")
->DataElement(AZ::Edit::DefaultHandler, &MyComponent::m_someFloatField, "Some
Float", "This is a float that means X.")
->EnumAttribute("ChangeNotify", &MyComponent::CalculateMoreData)
Version 1.10
459
Lumberyard Developer Guide
Reflecting a Component for Serialization and Editing
// m_moreData is not reflected for editing directly.
;
}
Lumberyard has reflection contexts for different purposes, including the following:
•
SerializeContext
– Contains reflection data for serialization and construction of objects.
•
EditContext
– Contains reflection data for visual editing of objects.
•
BehaviorContext
– Contains reflection for run-time manipulation of objects from Lua, flow graph, or other external sources.
•
NetworkContext
– Contains reflection for networking purposes, including marshaling, quantization, and extrapolation.
Note
This guide covers only
SerializeContext
and
EditContext
.
All of Lumberyard's reflection API operations are designed to be simple, human readable, and human writable, with no forced dependency on code generation.
A component's
Reflect()
function is invoked automatically for all relevant contexts.
The following code dynamically casts the anonymous context provided to a serialize context, which is how components discern the type of context that
Reflect()
is being called for.
AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context);
Reflecting a class for serialization involves a builder pattern style markup in C++, as follows: serialize->Class<TestAsset>()
->Version(1)
->Field("SomeFloat", &MyComponent::
m_someFloatField
)
->Field("SomeString", &MyComponent::
m_someStringField
)
->Field("Things", &MyComponent::
m_things
)
->Field("SomeEnum", &MyComponent::
m_someEnumField
)
;
The example specifies that m_someFloatField
, m_someStringField
, m_things
, and m_someEnumField should all be serialized with the component. Field names must be unique and are not user facing.
Tip
We recommend that you keep field names simple for future proofing. If your component undergoes significant changes and you want to write a data converter to maintain backward data compatibility, you must reference the field names directly.
The preceding example reflects two primitive types—a float, and a string—as well as a container (vector) of some structure. AZ reflection, serialization, and editing natively support a wide variety of types:
• Primitive types, including integers (signed and unsigned, all sizes), floats, and strings
• Enums
•
AZStd
containers (flat and associative), including
AZStd::vector
,
AZStd::list
,
AZStd::map
,
AZStd::unordered_map
,
AZStd::set
,
AZStd::unordered_set
,
AZStd:pair
,
AZStd::bitset
,
AZStd::array
, fixed C-style arrays, and others.
• Pointers, including
AZStd::smart_ptr
,
AZStd::intrusive_ptr
, and raw native pointers.
• Any class or structure that has also been reflected.
Version 1.10
460
Lumberyard Developer Guide
Reflecting a Component for Serialization and Editing
Note
The example omits the reflection code for
SomeClassThatSomeoneHasReflected
. However, you need only reflect the class. After that, you can freely reflect members or containers of that class in other classes.
For C++ API reference documentation on the serialize context, see the SerializeContext Class Reference in the Amazon Lumberyard C++ API Reference .
When you run Lumberyard tools such as Lumberyard Editor, an
EditContext
and a
SerializeContext
are provided. You can use the robust facilities in these contexts to expose your fields to content creators.
The following code demonstrates basic edit context reflection:
AZ::
EditContext
* edit = serialize->GetEditContext(); if (edit)
{
edit->Class<TestAsset>("My Component", "The World's Most Clever Component")
->
DataElement
(
AZ::Edit::DefaultHandler
, &MyComponent::m_someFloatField, "Some
Float", "This is a float that means X.")
->
DataElement
(
AZ::Edit::DefaultHandler
, &MyComponent::m_someStringField, "Some
String", "This is a string that means Y.")
->
DataElement
("ComboBox", &MyComponent::m_someEnumField, "Choose an Enum", "Pick an
option among a set of enum values.")
->EnumAttribute(MyComponent::SomeEnum::EnumValue1, "Value 1")
->EnumAttribute(MyComponent::SomeEnum::EnumValue2, "Value 2")
->
DataElement
(
AZ::Edit::DefaultHandler
, &MyComponent::m_things, "Bunch of Things",
"A list of things for doing Z.")
;
}
Although this example demonstrates the simplest usage, many features and options are available when you reflect structures (including components) to the edit context. For the fields to be exposed directly to content creators, the example provides a friendly name and a description (tooltip) as the third and fourth parameters of
DataElement
. For three fields, the first parameter of
DataElement
is the default UI handler
AZ::Edit::DefaultHandler
. The property system's architecture supports the ability to add any number of UI handlers, each valid for one or more field types. A given type can have multiple available handlers, with one handler designated as the default. For example, floats by default use the
SpinBox
handler, but a
Slider
handler is also available.
An example of binding a float to a slider follows:
->DataElement("
Slider
", &MyComponent::m_someFloatField, "Some Float", "This is a float that
means X.")
->Attribute("Min", 0.f)
->Attribute("Max", 10.f)
->Attribute("Step", 0.1f)
The
Slider
UI handler expects
Min
and
Max
attributes. Optionally, a value for
Step
may also be provided.
The example provides incremental increases of
0.1
. If no
Step
value is provided, a default stepping of
1.0
is used.
Note
The property system supports external UI handlers, so you can implement your own UI handlers in your own modules. You can customize the behavior of the field, the
Qt
control that it uses, and the attributes that it observes.
For C++ API reference documentation on the edit context, see the EditContext Class Reference in the
Amazon Lumberyard C++ API Reference .
Version 1.10
461
Lumberyard Developer Guide
Reflecting a Component for Serialization and Editing
The example also demonstrates the use of attributes. Attributes are a generic construct on the edit context that allows the binding of literals, or functions that return values, to a named attribute. UI handlers can retrieve this data and use it to drive their functionality.
Attribute values can be bound to the following:
Literal values
Attribute("Min", 0.f)
Static or global variables
Attribute("Min", &g_globalMin)
Member variables
Attribute("Min", &MyComponent::m_min)
Static or global functions
Attribute(AZ::Edit::Attributes::ChangeNotify, &SomeGlobalFunction)
Member functions
Attribute(AZ::Edit::Attributes::ChangeNotify, &MyComponent::SomeMemberFunction)
Another commonly used feature of the edit context is its ability to bind a change notification callback:
->DataElement(AZ::Edit::DefaultHandler, &MyComponent::m_someStringField, "Some String",
"This is a string that means Y.")
->Attribute("
ChangeNotify
", &MyComponent::OnStringFieldChanged)
The example binds a member function to be invoked when this property is changed, which allows the component to conduct other logic. The
ChangeNotify
attribute also looks for an optional returned value that tells the property system if it needs to refresh aspects of its state. For example, if your change callback modifies other internal data that affects the property system, you can request a value refresh.
If your callback modifies data that requires attributes be reevaluated (and any bound functions be reinvoked), you can request a refresh of attributes and values. Finally, if your callback conducts work that requires a full refresh (this is not typical), you can refresh the entire state.
The following example causes the property grid to refresh values when m_someStringField is modified through the property grid.
RefreshValues
signals the property grid to update the GUI with changes to the underlying data.
->DataElement(AZ::Edit::DefaultHandler, &MyComponent::
m_someStringField
, "Some String",
"This is a string that means Y.")
->Attribute("ChangeNotify", &MyComponent::OnStringFieldChanged)
...
AZ::u32 MyComponent::OnStringFieldChanged()
{
m_someFloatField = 10.0f;
// We've internally changed displayed data, so tell the property grid to refresh values
(cheap).
return AZ_CRC("
RefreshValues
");
}
RefreshValues
is one of three refresh modes that you can use:
Version 1.10
462
Lumberyard Developer Guide
Defining and Using Component Services
•
RefreshValues
– Refreshes only values. The property grid updates the GUI to reflect changes to underlying data that may have occurred in the change callback.
•
RefreshAttributesAndValues
– Refreshes values but also reevaluates attributes. Since attributes can be bound to data members, member functions, global functions, or static variables, it's sometimes necessary to ask the property grid to reevaluate them. Doing so might include reinvoking bound functions.
•
RefreshAll
– Completely reevaluates the property grid. This is seldom needed, as
RefreshAttributesAndValues
should cover all requirements for rich dynamic editor reflection.
The following more complex example binds a list of strings as options for a combo box. The list of strings is attached to a string field
Property A
. Suppose you want to modify the options available in the combo box for Property A with the values from another
Property B
. In that case you can bind the combo box
StringList
attribute to a member function that computes and returns the list of options.
In the
ChangeNotify
attribute for Property B, you tell the system to reevaluate attributes, which in turn reinvokes the function that computes the list of options.
...
bool m_enableAdvancedOptions;
AZStd::string m_useOption;
...
->DataElement(AZ::Edit::DefaultHandler, &MyComponent::m_enableAdvancedOptions, "Enable
Advanced Options", "If set, advanced options will be shown.")
->Attribute("
ChangeNotify
", AZ_CRC("RefreshAttributesAndValues"))
->DataElement("
ComboBox
", &MyComponent::m_useOption, "Options", "Available options.")
->Attribute("
StringList
", &MyComponent::
GetEnabledOptions
)
...
AZStd::vector<const char*> MyComponent::
GetEnabledOptions
()
{
AZStd::vector<const char*> options;
options.reserve(16);
options.push_back("Basic option");
options.push_back("Another basic option");
if (m_enableAdvancedOptions)
{
options.push_back("Advanced option");
options.push_back("Another advanced option");
}
return options;
}
Components can optionally specify a list of services that they provide, are incompatible with, depend on, or require. When you create a component, you can use this service specification to define relationships between various components. The component entity system uses this list for the conditional addition and removal of components at both edit time and at run time. The service specification also defines the order in which components are activated when an entity is activated. Specifically, components that provide services that another component depends on are activated first.
The following example shows a service specification.
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
Version 1.10
463
Lumberyard Developer Guide
Editor Components
{
provided.push_back(AZ_CRC("ProvidedService"));
provided.push_back(AZ_CRC("AnotherProvidedService"));
} static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
{
required.push_back(AZ_CRC("RequiredService"));
required.push_back(AZ_CRC("AnotherRequiredService"));
} static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType&
incompatible)
{
incompatible.push_back(AZ_CRC("IncompatibleService"));
} static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
{
dependent.push_back(AZ_CRC("DependentOnService"));
}
ProvidedService
– Specifies the service that the component provides. For example, a
TransformComponent
could provide a
TransformService
that in turn provides locational information.
RequiredService
– Specifies a service that the component requires. The components that provide the required services are guaranteed to be present and active before this component is activated.
For example, an audio component might need to know where it is located and therefore require a
TransformService
. Because of this requirement, the audio component can be added only to entities that have the component that provides the
TransformService
.
DependentService
– Specifies a service on which the component depends but does not require. The component entity system guarantees that the components that provide dependent services are activated before the component itself is activated. For example, an audio component could depend on the physics component. If the entity has physics, the audio component can query the physics
component for physical material information. However, the audio component does not require that physics be present.
IncompatibleService
– Specifies a service that cannot work with the component. Consider these examples:
• An entity can have only one type of collider. Therefore, the
PrimitiveColliderService
specifies that the
MeshColliderService
is incompatible with it and vice versa.
• The same effect can be achieved if two collider components already provide the
ColliderService themselves and therefore specify the
ColliderService
as incompatible. Marking a component as incompatible with
ColliderService
ensures that no other component that has the same service is added to the entity.
• The
IncompatibleService
specification is frequently used to specify that multiples of the same component cannot exist on an entity.
Some components in Lumberyard have separate editor
and runtime
versions. The editor version is active in the editor. The run-time version is used for running the level in game or in the editor by pressing
Ctrl+G
or clicking
AI/Physics
below the viewport. Lumberyard uses editor components to maintain a clean separation between tools-specific code and data on one hand, and leaner run-time component data on the other. In general, run-time game components do not require editor counterparts.
Components rarely need to be fully active at edit time. The light and mesh components are exceptions because they must behave the same at edit time as at run time.
Version 1.10
464
Lumberyard Developer Guide
Editor Components
EditContext
reflection is fully supported in run-time components. Edit time is the only time when editor components are active. At run time, when Lumberyard processes a level or dynamic slice, it uses the runtime equivalents of editor components. Using the
EditContext
from a run-time component is usually sufficient to provide a rich editing experience.
Important
Editor components are not required. An editor component is necessary only if one of the following is true:
• Your component must be fully active at edit time. Edit time refers to standard editing mode; run-time components are used for the
AI/Physics
mode and gameplay (
Ctrl+G
).
• You must add special tools functionality to your component that requires that you compile only into your editor binaries.
• Your component provides functionality only in the editor and does not export a run-time component (for example, if your component manages selection logic).
The following code shows a sample editor component.
class MyEditorComponent
: public AzToolsFramework::Components::EditorComponentBase
, private AzFramework::EntityDebugDisplayEventBus::Handler
{ public:
AZ_EDITOR_COMPONENT(MyEditorComponent, "{5034A7F3-63DB-4298-83AA-915AB23EFEA0}");
// AZ::Component interface implementation.
void Init() override {}
void Activate() override {}
void Deactivate() override {}
// AzFramework::EntityDebugDisplayEventBus::Handler.
void DisplayEntity(bool& handled) override;
// Required Reflect function.
static void Reflect(AZ::ReflectContext* context);
// Optional functions for defining provided and dependent services.
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType&
provided)
static void GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType&
dependent);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType&
required);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType&
incompatible);
void BuildGameEntity(AZ::Entity* gameEntity) override;
};
The code for editor components is similar to the code for run-time components. The following sections list the key differences. It is safe to assume that editor component code is the same as it is
for run-time component code other than the differences listed. For more information, see Creating a
.
Version 1.10
465
Lumberyard Developer Guide
Editor Components
Base Classes
All editor components include the
AzToolsFramework::Components::EditorComponentBase
class somewhere in their inheritance ancestry. If a component must display edit-time visualization, it must be a handler on the
AzFramework::EntityDebugDisplayEventBus::Handler
bus, as in the following example.
class MyComponent
: public AzToolsFramework::Components::EditorComponentBase
, private AzFramework::EntityDebugDisplayEventBus::Handler
Macro
Every editor component must specify the
AZ_EDITOR_COMPONENT
macro within its class definition. The macro takes two arguments:
1. The component type name.
2. A unique UUID. You may use any UUID generator to produce the value. Visual Studio provides this functionality through
Tools
,
Create GUID
. Use the
Registry Format
setting, and then copy and paste the value that is generated.
A sample
AZ_EDITOR_COMPONENT
macro follows.
AZ_EDITOR_COMPONENT(MyEditorComponent, "{5034A7F3-63DB-4298-83AA-915AB23EFEA0}");
Note
Some older editor components specify
AzToolsFramework::Components::EditorComponentBase as the base class but use the
AZ_COMPONENT
instead of the
AZ_EDITOR_COMPONENT
macro, as in the following example.
AZ_COMPONENT(EditorMannequinComponent, "{C5E08FE6-E1FC-4080-A053-2C65A667FE82}",
AzToolsFramework::Components::EditorComponentBase);
The DisplayEntity Method
To render special visualizations in the editor, implement the
DisplayEntity
method of the
AzFramework::EntityDebugDisplayEventBus
interface. Use this location for custom primitive edit-time visualization code.
// AzFramework::EntityDebugDisplayEventBus::Handler void DisplayEntity(bool& handled) override;
The BuildGameEntity Method
The
BuildGameEntity
method facilitates the translation of an editor component into a run-time component. Its syntax is as follows.
void BuildGameEntity(AZ::Entity* gameEntity) override;
A typical implementation of the
BuildGameEntity
method performs the following actions:
1. Create a run-time component based on the editor component of the specified gameEntity
.
2. Copy the configuration data from the editor component into the run-time component.
3. Add the run-time component to the gameEntity
that was specified.
Version 1.10
466
Lumberyard Developer Guide
Creating System Components
At this point, the run-time component serializes the gameEntity
and reloads it to create a new, clean version of the run-time entities.
The Transform Component Example
The
TransformComponent
is a good example of how editor and run-time components can differ. In the run-time component, values are stored in a fully composed
AZ::Transform
. In the editor component, values are stored in decomposed format. Position, rotation, and scale values are stored separately, and rotation is represented as Euler angles. This difference in format enables the editor component to provide user-friendly display and storage while providing optimal storage in the run-time component.
System components are similar to other components in Lumberyard's component entity framework.
However, instead of creating game entity behavior, they control the behavior of the engine itself.
Currently Lumberyard enables the creation of custom system components through AZ modules and gems. (Gems are a specialization of AZ modules; for more information, see Gems and AZ Modules ).
Most games organize their game code in one or more gems that are specific to the game. These gems can contain both components that you can use on game entities and system components that you want to integrate with the engine. The system components that a given gem or module specifies are first-class elements of the game engine and are included at a deep level early in the initialization process. For more information, see
section.
Like any Lumberyard component, a system component can provide services and can be dependent on or require other system component services. This is an elegant way to control engine initialization order and system dependencies.
When you author system components, follow the best practices for component authoring. For example, your system components should use the following:
•
EBuses (p. 576) to expose their interfaces
•
to serialize and edit settings in the Advanced Settings dialog of the Project
• The same AZ::Component Functions (p. 457) for activation and deactivation
Important
Just like game components, system components often provide request and notification buses.
However, because system components are global systems, they should not specify IDs for their buses like game components do. Your users should be able to call your system's EBuses without having to deal with or know about the system entity that contains all system components.
The following code example shows a system component EBus.
class AnimationGraphAssetRequests : public AZ::EBusTraits
{
public:
virtual ~AnimationGraphAssetRequests() = default;
virtual AZStd::vector<AZ::Uuid> GetGraphNodeTypes(AZ::SerializeContext&
serializeContext) = 0;
virtual GraphAssetPtr CreateGraphAsset() = 0;
virtual NodeId CreateGraphNode(const GraphAssetPtr& asset, const AZ::Uuid&
nodeTypeId, AZ::SerializeContext& serializeContext) = 0;
virtual bool DeleteGraphNode(const GraphAssetPtr& asset, NodeId nodeId) = 0;
virtual NodePtr FindGraphNode(const GraphAssetPtr& asset, NodeId nodeId) = 0;
}; using AnimationGraphAssetRequestBus = AZ::EBus<AnimationGraphAssetRequests>;
Version 1.10
467
Lumberyard Developer Guide
Creating System Components
The following code shows part of the system component itself.
class AnimationGraphSystemComponent
: public AZ::Component
, private AnimationGraphSystemRequestBus::Handler
{ public:
AZ_COMPONENT(AnimationGraphSystemComponent, "{2D497170-E4C7-40B0-
A9D1-2D987CC8932A}");
AnimationGraphSystemComponent();
~AnimationGraphSystemComponent() override;
// AnimationGraphSystemRequestBus::Handler
AZStd::intrusive_ptr<PoseBufferStorage> AllocatePoseBufferStorage(AZ::u32 jointCount)
override;
void FreePoseBufferStorage(PoseBufferStorage* storage) override;
AZ::u32 GetActivePoseBufferCount() override;
void ExecuteGraph(const AZ::Data::AssetId& assetId, const PlaybackContext& context,
PoseBuffer& targetBuffer) override;
void UpdateGraph(const AZ::Data::AssetId& assetId, const PlaybackContext& context,
float& expectedDuration, float& normalizedTime) override;
....
// AZ::Component
static void Reflect(AZ::ReflectContext* reflect);
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType&
provided);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType&
required); private:
// AZ::Component
void Activate() override;
void Deactivate() override;
To designate a component as a system component, you must set the
AppearsInAddComponentMenu
field to
System
when you reflect to the
EditContext
, as in the following example.
if (AZ::EditContext* editContext = serializeContext->GetEditContext())
{
editContext->Class<AnimationGraphSystemComponent>(
"Animation Graph", "Manages animation graph system component and features.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Engine")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu,
AZ_CRC("System"))
;
}
This code exposes the component to the editor and other parts of the user interface that are visible to users. The optional
Category
field determines which submenu contains the component in the
Add
Component
menu in Lumberyard Editor Entity Inspector. In the following example, the
Area Light
component appears in the submenu
Add Component
,
Rendering
,
Lights
.
...
editContext->Class<EditorAreaLightComponent>(
"
Area Light
", "Attach area lighting to an entity.")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
Version 1.10
468
Lumberyard Developer Guide
Components and EBuses
->Attribute(AZ::Edit::Attributes::
Category
, "
Rendering/Lights
")
...
EBuses are not required for components, nor are they directly bound to components in any way. But because they form the backbone of communication among all Lumberyard components, EBuses offer many benefits. We highly recommend that you learn how to use them in your game, systems, and
components. For more information, see Event Bus (EBus) (p. 576) .
Most components provide two EBuses to facilitate communication: a request bus and a notification bus. Both these EBuses use the
EBusAddressPolicy::ById
address policy and the ID of the entity for identification.
A component's request bus allows other components or external systems to make requests of the component. Usually the run-time version of the component implements the request bus. However, the editor component can service the bus in special cases.
The following sections examine the individual parts of an example request bus.
Transform Request Event Group
The following example defines a group of events that the
TransformComponent
handles.
class TransformComponentRequests
: public AZ::ComponentBus // EBus traits for component buses: identification is based
on an entity ID.
{
public:
// EBusTraits overrides - Only a single handler is allowed for a given entity ID.
// Only one component on a entity can implement the events.
static const EBusHandlerPolicy HandlerPolicy = EBusHandlerPolicy::Single;
// Returns the local transform (parent transform excluded).
virtual const Transform& GetLocalTM() = 0;
// Sets the local transform and notifies all interested parties.
virtual void SetLocalTM(const Transform& /*tm*/) {}
// Returns the world transform (including parent transform).
virtual const Transform& GetWorldTM() = 0;
// Sets the world transform and notifies all interested parties.
virtual void SetWorldTM(const Transform& /*tm*/) {}
// Returns both local and world transforms.
virtual void GetLocalAndWorld(Transform& /*localTM*/, Transform& /*worldTM*/) {}
...
};
Base Class and Trait Specification
The base class for most
AZ::Component
request buses is
AZ::ComponentBus
. This class is a convenience to help set up EBus traits typical of component EBuses. You could also set up EBus traits by inheriting the
Version 1.10
469
Lumberyard Developer Guide
Components and EBuses default
AZ::EbusTraits
. Then you could optionally override any or all of the following traits. For more information, see EBus Configuration Options .
• Address policy
• Bus ID type
• Connection policy
• Handler policy
• Lock type
• Priority sorting
These two approaches are shown in the following examples.
// Example using AZ::ComponentBus.
class TransformComponentRequests
: public
AZ::ComponentBus
{...}
// Example using AZ::EBusTraits class TransformComponentRequests
: public
AZ::EBusTraits
{
...
// EBusTraits overrides.
static const EBusAddressPolicy AddressPolicy = EBusAddressPolicy::ById; // OR YOUR
CHOSEN POLICY
static const AZ::EBusHandlerPolicy HandlerPolicy =
AZ::EBusHandlerPolicy::Multiple; // OR YOUR CHOSEN POLICY
using BusIdType = EntityId;
...
}
EBus Request Bus Events
EBus event definitions are the main part of the bus specification. This interface defines what your component does. In the following example, the
TransformComponent
allows the retrieval and modification of the local and world transforms. It also creates interfaces for setting parent–child relationships.
...
// Returns the local transform (parent transform excluded).
virtual const Transform& GetLocalTM() = 0;
// Sets the local transform and notifies all interested parties.
virtual void SetLocalTM(const Transform& /*tm*/) {}
// Returns the world transform (including parent transform).
virtual const Transform& GetWorldTM() = 0;
// Sets the world transform and notifies all interested parties.
virtual void SetWorldTM(const Transform& /*tm*/) {}
// Returns both local and world transforms.
virtual void GetLocalAndWorld(Transform& /*localTM*/, Transform& /*worldTM*/) {}
...
Version 1.10
470
Lumberyard Developer Guide
Components and EBuses
EBus Request Bus Definition
After the event group has been declared, the EBus must be defined. Although you can use
AZ::EBus<TransformComponentRequests>
to define an EBus, we recommend that you use a typedef instead, as in the following example. This improves readability at bus call sites.
typedef AZ::EBus<TransformComponentRequests> TransformComponentRequestBus;
Another best practice is to use descriptive names in EBuses and avoid overloaded functions. Explicit and descriptive function names prevent future API name collisions as classes inherit (potentially many of) your EBus interfaces. Avoiding overloaded functions improves the experience of using your EBuses from scripting environments. In Lua and in visual scripting, the extra expressiveness improves readability and clarity.
A component uses its notification bus to inform other components and the rest of the engine about relevant changes. To do this, it sends notifications in the form of EBus events to any class that monitors the bus. To monitor the bus, classes implement the notification bus handler interface (in the case of
TransformComponent
, this is
AZ::TransformNotificationBus::Handler
.)
Note
A request bus sends messages
to
a component; a notification bus sends messages
from
a component.
Transform Notification Event Group
The following example defines a group of notification events that the
TransformComponent
sends.
class TransformNotifications
: public AZ::ComponentBus
{
public:
...
// Called when the local transform of the entity has changed. Local transform update
always implies world transform change too.
virtual void OnTransformChanged(const Transform& /*local*/, const Transform& /
*world*/) {}
...
}; typedef AZ::EBus<TransformNotifications> TransformNotificationBus;
The notification bus can also change its
EBusTrait
specification if required.
After you have created the EBus event groups and defined the EBuses, your component can implement the EBus interface by deriving the EBus handler. The following example is from the
TransformComponent
.
class TransformComponent
: public AZ::Component
, private AZ::TransformComponentRequestBus::Handler
{
...
// TransformBus.
Version 1.10
471
Lumberyard Developer Guide
Tick Bus and Components
/// Returns true if the tm was set to the local transform.
const AZ::Transform& GetLocalTM() override { return m_localTM; }
/// Sets the local transform and notifies all interested parties.
void SetLocalTM(const AZ::Transform& tm) override;
/// Returns true if the transform was set to the world transform.
const AZ::Transform& GetWorldTM() override { return m_worldTM; }
/// Sets the world transform and notifies all interested parties.
void SetWorldTM(const AZ::Transform& tm) override;
/// Returns both local and world transforms.
void GetLocalAndWorld(AZ::Transform& localTM, AZ::Transform& worldTM) override
{ localTM = m_localTM; worldTM = m_worldTM; }
...
}
At this point you can implement the defined methods in the
TransformComponent
. After the
TransformComponent
connects to the EBus for its entity ID, its event handlers are invoked whenever an event is sent on that bus or ID.
The tick bus is the primary mechanism by which components subscribe to events that occur per CPU tick. If your component requires tick-based functionality, it implements the tick bus interface's
OnTick method and connects to the tick bus for the required period of time. To avoid poor scalability of pollingbased update structures, components should limit the time that they are connected to the tick bus.
Your components should connect to the tick bus only in the
Activate
method and disconnect only in the
Deactivate
method. If possible, components should connect only when necessary and disconnect as soon as feasible. For example, a component might use the
OnTick
method to check the state continuously but actively do processing for only a fraction of the connected time. Instead, the component should connect to the tick bus only when the state changes and disconnect after processing is complete. This approach is closer to that of event-based programming, in which polling is conducted only for short periods of time or not at all.
As an example, imagine a component that monitors the state of an entity after the entity enters a trigger. The component should avoid subscribing to the tick bus until the entity has entered the trigger.
It should then disconnect from the tick bus as soon as the entity has left the trigger.
In the following example, the
NavigationComponent
implements the
OnTick
method.
class NavigationComponent
: public AZ::Component
, public NavigationComponentRequestBus::Handler
, public AZ::TickBus::Handler
{
...
// TickBus
virtual void OnTick(float deltaTime, AZ::ScriptTimePoint time);
...
}
To connect and disconnect from the tick bus, the component uses code like the following.
Version 1.10
472
Lumberyard Developer Guide
Exposing Custom Components to Track View for Animation
AZ::TickBus::Handler::
BusConnect
();
AZ::TickBus::Handler::
BusDisconnect
();
It is important to know when to use the tick bus and when to use event-driven programming patterns instead.
Event-Based Polling
It is often convenient to tick a component every frame and monitor the state of other entities. For example, a
LookAt
camera component is commonly implemented to tick each frame, retrieve the transform of the target entity, and update its own transform accordingly.
Event-Based Programming
In Lumberyard, a more event-driven approach is to use the
TransformBus
to monitor the target entity for transform changes in a purely event-driven fashion. If the target entity doesn't move, no work is done and no polling is required. When the target entity moves, the
LookAt
component adjusts its own entity's transform accordingly.
Use Notifications to Make Your Components Easy to Use
When authoring a component, try to anticipate the requirements of components that might depend on yours. Use a notification bus to expose the appropriate notifications for your component. This approach enables others to write code that consumes the services of your components in a faster and more scalable way.
For more best practices, see
Components and EBuses: Best Practices (p. 478)
.
To include custom components in cinematic cut scenes and movies rendered to disk, you must expose animatable component properties to Lumberyard’s
Track View
editor and
Entity Inspector
. To expose a custom component and its properties, you must perform three steps:
1. Create getter and setter methods for the animated property on one of the component’s request event buses.
2. Implement the getter and setter request handlers in your component.
3. Reflect your component to the edit context and the behavior context. Edit context reflection exposes your component in
Entity Inspector
, and behavior context reflection exposes it in the
Track View
editor.
The following example assumes that a custom component called
ImaginaryTargetComponent
has been created. The component has a
Vector3
property called
ImaginaryPosition
that you want to animate in
Track View
. A request bus called
ImaginaryTargetComponentBus
has also been created for the component. This example assumes that you are familiar with programming event buses and
Version 1.10
473
Lumberyard Developer Guide
Exposing Custom Components to Track View for Animation
component handlers for them. For more information, see Event Bus (EBus) (p. 576) and
.
To expose a custom component to Track View
1.
Create getter and setter methods
Each property must provide a method to set its value and get its current value. To implement this, create setter and getter methods on one of the component’s request buses. Then reflect those methods to the behavior context as part of the class reflection for the component.
The following example creates setter and getter requests on the
ImaginaryTargetComponentRequestBus
.
/*!
* ImaginaryTargetComponentRequests EBus Interface
* Messages serviced by ImaginaryTargetComponents.
*/ class ImaginaryTargetComponentRequests
: public AZ::ComponentBus
{ public:
// EBusTraits overrides - Application is a singleton.
// Only one component on an entity can implement the events.
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
// Getter/Setter methods for ImaginaryTargetPosition.
virtual AZ::Vector3 GetImaginaryTargetPosition() = 0;
virtual void SetImaginaryTargetPosition(const AZ::Vector3& newPosition) = 0;
}; using ImaginaryTargetComponentRequestBus = AZ::EBus<ImaginaryTargetComponentRequests>;
2.
Implement handlers in your component
Implement handlers in your component for the setter and getter requests that you declared in the first step, as in the following example.
class ImaginaryTargetComponent
: public AzToolsFramework::Components::EditorComponentBase
, public LmbrCentral::ImaginaryTargetComponentRequestBus::Handler
{ public:
AZ_EDITOR_COMPONENT(ImaginaryTargetComponent, "{4491D282-C120-4B2E-BC63-
AC86296956A2}");
ImaginaryTargetComponent() : m_imaginaryPosition(.0f) {};
// ImaginaryTargetComponentRequestBus::Handler implementation.
// Implementations for Getter/Setter methods for ImaginaryTargetPosition.
// Presumably these would be used for something useful; this example just
// stores and returns the value.
AZ::Vector3 GetImaginaryTargetPosition() override { return m_imaginaryPosition; }
void SetImaginaryTargetPosition(const AZ::Vector3& newPosition) override
{ m_imaginaryPosition = newPosition; } protected:
// Required Reflect function.
static void Reflect(AZ::ReflectContext* context); private:
Version 1.10
474
Lumberyard Developer Guide
Exposing Custom Components to Track View for Animation
AZ::Vector3 m_imaginaryPosition;
};
3.
Reflect your component
Using the edit context and behavior contexts, reflect the component’s class, request event bus, and setter and getter methods.
Track View
uses the setter and getter methods that you reflect in this step to set and get values for your animated property. You must also reflect a
VirtualProperty declaration that tells
Track View
that your component is capable of being animated.
/*static*/ void ImaginaryTargetComponent::Reflect(AZ::ReflectContext* context)
{
AZ::SerializeContext* serializeContext =
azrtti_cast<AZ::SerializeContext*>(context);
if (serializeContext)
{
serializeContext->Class<ImaginaryTargetComponent,
AzToolsFramework::Components::EditorComponentBase>()
->Version(0)
->Field("ImaginaryPosition",
&ImaginaryTargetComponent::m_imaginaryPosition);
AZ::EditContext* editContext = serializeContext->GetEditContext();
if (editContext)
{
editContext->Class<ImaginaryTargetComponent>("ImaginaryTarget", "A Code
Sample enabling Track View Animation")
->ClassElement(AZ::Edit::ClassElements::EditorData, "")
->Attribute(AZ::Edit::Attributes::Category, "Game")
->Attribute(AZ::Edit::Attributes::AppearsInAddComponentMenu,
AZ_CRC("Game", 0x232b318c))
->DataElement(0, &ImaginaryTargetComponent::m_imaginaryPosition,
"Imaginary Target Pos", "Imaginary Target Position")
;
}
}
AZ::BehaviorContext* behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context);
if (behaviorContext)
{
// Reflect the setter and getter methods and create a virtual property that
refers to them.
behaviorContext-
>EBus<ImaginaryTargetComponentRequestBus>("ImaginaryTargetRequestBus")
->Event("GetImaginaryTargetPosition",
&ImaginaryTargetComponentRequestBus::Events::GetImaginaryTargetPosition)
->Event("SetImaginaryTargetPosition",
&ImaginaryTargetComponentRequestBus::Events::SetImaginaryTargetPosition)
->VirtualProperty("ImaginaryPosition", "GetImaginaryTargetPosition",
"SetImaginaryTargetPosition");
// Attach the "ImaginaryTargetRequestBus" EBus that you reflected to the
behavior context of the ImaginaryTargetComponent class.
behaviorContext->Class<ImaginaryTargetComponent>()-
>RequestBus("ImaginaryTargetRequestBus");
}
}
4.
(Optional) Place Unit Attributes on Getters
The
Track View
user interface depends on the data type that the getter and setter use. The foregoing example uses a type of
AZ::Vector3
, so
Track View
creates a compound x,y,z
track from the property. By contrast, if the getter and setters use a bool
,
Track View
creates a Boolean track.
Version 1.10
475
Lumberyard Developer Guide
Exposing Custom Components to Track View for Animation
For the majority of animatable properties, the type is sufficient. However, in some cases you might have to set units for a reflected property. For example, if your property’s
AZ::Vector3
represents a color, you must add an attribute to the reflection of the getter event. The attribute instructs
Track
View
to use a color picker for that property. If you have a property called
ImaginaryTargetColor that calls a getter event called
GetImaginaryTargetColor
, use reflection code like the following:
->Event("GetImaginaryTargetColor",
&ImaginaryTargetComponentRequestBus::Events::GetImaginaryTargetColor)
->Attribute("
Units
", AZ::Edit::Attributes:: PropertyUnits8BitColor)
Track View
then uses a color track for the property, as the following image shows.
Other units can be found in the file dev\Code\Framework\AZCore\AZCore\Serialization
\EditContextConstants.inl
. As of Lumberyard release 1.8, these units are the following.
const static AZ::Crc32 PropertyUnitsRadian = AZ_CRC("Radians"); const static AZ::Crc32 PropertyUnits8BitColor = AZ_CRC("8BitColor");
If you have an angular parameter in radians that you want to
Track View
to convert to degrees in its user interface, use
AZ::Crc32 PropertyUnitsRadian
.
Now you can view how the example component and property appear in the
Entity Inspector
and the
Track View
editor.
In the following
Entity Inspector
image,
EditContext
reflection has exposed the
ImaginaryTarget
component and its
Imaginary Target Pos
property.
Version 1.10
476
Lumberyard Developer Guide
Exposing Custom Components to Track View for Animation
In the following
Track View
image,
BehaviorContext
reflection has exposed the
ImaginaryTarget
component and the
ImaginaryPosition
track from the corresponding virtual property.
Version 1.10
477
Lumberyard Developer Guide
Components and EBuses: Best Practices
Follow these best practices for authoring components.
The following EBus naming conventions remove ambiguity and provide consistency.
• Use the name format
MyComponentRequestBus
for the bus that others use to invoke functions on
MyComponent
, as in the following example.
class CheeseburgerComponentRequests : public AZ::ComponentBus
{
bool ICanHasCheeseburger() const = 0;
}; using CheeseburgerComponentRequestBus = AZ::EBus<CheeseburgerComponentRequests>;
• Use the name format
MyComponentNotificationBus
for events that are broadcast from
MyComponent
, as in the following example.
class CheeseburgerComponentNotifications : public AZ::ComponentBus
{
void OnCheeseburgerEaten(AZ::u8 yelpRating) {};
}; using CheeseburgerComponentNotificationBus =
AZ::EBus<CheeseburgerComponentNotifications>;
Version 1.10
478
Lumberyard Developer Guide
Components and EBuses: Best Practices
Notification buses typically provide default implementations of the methods within the interface. Many other components can monitor your component's events, but not all of them are interested in every event that your component sends. If you provide default implementations for all your methods, other components that subscribe to your events can implement only those events that are relevant to them.
Good EBus event names are verbose. Classes can monitor multiple buses, so descriptive event names makes it clear which bus the function corresponds to. This practice also prevents potential name collisions among event interfaces from different buses.
The following example is a clearly named
PhysicsComponentNotificationBus
event.
virtual void
OnPhysicsEnabled
() = 0;
The following example is an ambiguously named
PhysicsComponentNotificationBus
event.
virtual void
OnEnabled
() = 0;
An instructive example from Lumberyard shows the importance of using classes instead of type definitions for serialized data. Formerly,
EntityId
used the type definition uint32_t
. When the decision was made to change this to 64-bit, upgrade functions had to be written for every class that contained an
EntityId
. If
EntityId
had been a class, a single upgrade function could have been written for the class, and no further work would have been required. Obviously, this principle does not apply to primitive types like bool
, float
, int
, and string
. However, if you have a specific type that is serialized and might change in the future, implement it as a reflected class. This provides a single context where you can easily make the conversion for the class or type.
Always initialize a variable before calling an EBus event that overwrites the variable. Even if you are sure that a particular class or component is listening on the bus, it's worth handling the exceptional case.
This is especially true in distributed environments in which entities can come and go as part of area-ofinterest or other dynamic patterns.
The following example initializes a result variable before calling an EBus event that produces a result.
AZ::Transform targetEntityTransform = AZ::Transform::Identity(); // initialize result
variable...
EBUS_EVENT_ID_RESULT(targetEntityTransform, targetEntityId, AZ::TransformBus,
GetWorldTM); // ...in case of no response
Following are some best practices for the timing of EBus actions.
• In the
Activate() (p. 457) function, make sure that connecting to buses is the last step.
• In the
function, make sure that disconnecting from buses is the first step.
Version 1.10
479
Lumberyard Developer Guide
Behavior Context
• In a multithreaded environment, it's possible to receive bus events from the moment that you connect to the bus until the moment you disconnect. For this reason, make sure of the following:
• Your component is fully activated before it starts reacting to events.
• Your component stops receiving events before it starts deactivation.
This practice prevents your component from being in a half-activated state when it starts reacting to events, or in a half-deactivated while still receiving events.
• When you send events on a notification-style bus, the last step in a function should ensure that the data is fully populated.
The following is an example to avoid.
EBUS_EVENT_ID(GetEntityId(), OnTransformChanged, newTransform); m_transform =
newTransform
;
If a component is monitoring the
OnTransformChanged
event and sets your transform in response to the event, the component's action will be undone by the m_transform = newTransform;
assignment.
Consider the following when deciding to make functions public or private.
• Make your bus functions public
if they constitute the public interface for your class. While it's discouraged, Lumberyard does not prevent users from getting direct pointers to components and calling functions directly. To avoid this, make sure that your useful functions are public. For example,
MyComponent
should probably implement functions from
MyComponentRequestBus
publicly.
• Make your bus functions protected
if they contain the private workings of your class. For example, your component's reaction to the
TransformNotificationBus::OnTransformChanged
event would likely be a private implementation detail.
In general, all EBus methods are meant to be implemented by external code. As the author of an EBus interface, you do not want to force the use of const
declarations upon any particular implementation of a method. Because end developers will write these for their own data, it is best to avoid const
in EBus event group functions.
Note
This is true for request buses but is particularly important with regard to notification buses.
In Lumberyard 1.8, the
behavior context
replaces
script context
. The behavior context works with
serialize context
,
edit context
, and
network context
to provide rich C++ reflection. The behavior context focuses on the runtime aspects of C++ code and allows you to manipulate C++ code and objects while they are being created. All script bindings, including Lua, use this reflection. Reflection is also used for modification of objects while in running state (such as animating object properties) and reading of current properties for component state transitions. You can have multiple behavior contexts that are specialized for different purposes, and you can unreflect the behavior contexts in order to implement
Version 1.10
480
Lumberyard Developer Guide
Reflection API reloading. At a high level, the behavior context uses only a few primitives on which to build: properties, methods, classes, EBuses and attributes.
With the introduction of the behavior context, you can no longer reflect directly into the script context.
For more information, see the migration notes for Lumberyard 1.8
. For C++ API reference documentation on the behavior context, see the BehaviorContext Class Reference in the Amazon Lumberyard C++ API
Reference .
This section describes how methods, properties, classes, and other primitives are used in the Lumberyard reflection API.
Methods reflect a C++ function. You can have global or class methods. Each method must have a unique name for its scope (global or class). You can also provide default values; this allows you to call reflected methods with fewer arguments. Default values are used right to left. You can also provide a debug description for your method. It's highly recommended that you do so. The debug description information is provided to users for context when they use the reflection, as is done with
ClassView
in the Lua editor.
The system automatically generates a description that includes result and argument types. However, adding intent and additional details to your descriptions greatly improves the usability of your reflection.
This is especially important when a method has many attributes.
Properties access data and can be global properties or class properties. Each property must have a unique name for its scope. As is customary, a property has getter and setter methods. If you don't provide a setter method for a property, the property is read only. If you don't provide a getter method, the property is write only.
Lumberyard does support global functions, member functions, and Lambda functions as property getters and setters.
Lumberyard provides macros that you can use to wrap a class value. You can use
BehaviorValueProperty(&value)
to implement getter and setter methods, or you can implement them individually by using
BehaviorValueGetter
and
BehaviorValueSetter
. These macros implement Lambda functions for those values. When the state of your object is modified, you might have to perform operations other than simply setting the value. For this reason, it is a best practice to always implement your getters and setters. You can always change your implementation later.
Constants are implemented as read-only properties and can be global or restricted to a class. A behavior context macro called
BehaviorConstant
implements the Lambda getter for you.
Because class enums often require casting, Lumberyard currently treats all enums values as int
. Enums are implemented as read-only int
properties.
Reflects a C++ class or struct. You can provide an optional name. If you do not provide a name, the class name from
AzTypeInfo
is used. That name must be unique for the scope. Because the system uses
AzRTTI
to build the class hierarchy, you can use RTTI if you want to reflect base class functionality.
Version 1.10
481
Lumberyard Developer Guide
Reflection API
•
Allocator
- You can provide a custom allocator/ deallocator for your class. This allows you to override any existing allocation schema. If you do not provide a custom allocator, aznew/delete is used
(
AZ_CLASS_ALLOCATOR
).
•
Constructor
- Allows you to enumerate the class constructors that you want to reflect. You must pass all constructor arguments as template augments.
•
Wrapping/WrappingMember
- Allows code to inform the system that it is a wrapper of another class.
This is useful when you reflect smart pointers and string wrappers.
•
Userdata
- Allows you to provide a pointer to user data. The pointer is accessible from all callbacks
(like a custom allocator) that you implement for the class.
•
Method
- Reflects a C++ class function. The first argument is the class pointer. This is the same usage as global methods.
•
Property
- Reflects class data. The first argument is the class pointer. This is the same usage as global properties.
•
Enum
- Enums are int read-only properties.
•
Constant
- Constants are read-only properties.
Nested Classes
To bind a nested class to the behavior context, you must do it from within a function on the nested class.
C++ rules about nested class member access from outside scopes make this requirement necessary.
The following counterexample shows a poorly formed nested class. The code does not work.
//Bad nested class class Outer
{ public:
AZ_TYPE_INFO(Outer, "...");
static void Reflect(AZ::ReflectContext* context);
class Inner
{
public:
AZ_TYPE_INFO(Inner, "...");
int m_member = 0;
};
}; void Outer::Reflect(AZ::ReflectContext* context)
{
if (AZ::BehaviorContext* behavior = azrtti_cast<AZ::BehaviorContext*>(context))
{
behavior->Class<Inner>("OuterInner")
->Property("member", BehaviorValueProperty(&Inner::m_member))
;
}
}
The following code shows a well formed nested class.
//Good nested class class Outer
{ public:
AZ_TYPE_INFO(Outer, "...");
static void Reflect(AZ::ReflectContext* context);
class Inner
Version 1.10
482
Lumberyard Developer Guide
Example
{
public:
AZ_TYPE_INFO(Inner, "...");
static void Reflect(AZ::ReflectContext* context);
int m_member = 0;
};
}; void Outer::Reflect(AZ::ReflectContext* context)
{
Inner::Reflect(context);
} void Outer::Inner::Reflect(AZ::ReflectContext* context)
{
if (AZ::BehaviorContext* behavior = azrtti_cast<AZ::BehaviorContext*>(context))
{
behavior->Class<Inner>("OuterInner")
->Property("member", BehaviorValueProperty(&Inner::m_member))
;
}
}
EBus
Reflects Lumberyard event bus messages. Depending on your EBus configuration,
Broadcast
,
Event
(with ID) and
Queuing
are reflected. Queuing is a generic function to be executed when the bus messages are consumed.
•
Event
- Reflects an EBus event. Depending on your EBus configuration, Lumberyard automatically reflects
Broadcast
,
Event
,
QueueBroadCast
, and
QueueEvent.
•
Handler
- Reflects a class that you must implement to forward messages from the EBus to behavior context methods. You must create a class that can monitor the specified EBus and forward messages to the behavior context. This is a requirement because the behavior context can not guarantee that there is a handler for each message. If a message expects a result, you must provide a default result in case the message is not handled by the behavior context user. Keep in mind that the system creates as many of these handlers as the behavior context requires. Handlers can also execute in different threads. As a result, you should avoid static storage for values that change. The best way to understand this is to examine the example that follows.
The following code example shows the use of the Lumberyard reflection API.
// Global Property behaviorContext.Property("globalProperty",&GlobalPropertyGetter, &GlobalPropertySetter); //
Property with getter and setter function behaviorContext.Property("globalProperty",[]() { return g_globalValue; }, [](int value)
{ g_globalValue = value;}); // Property with Lambda functions.
behaviorContext.Property("globalProperty", BehaviorValueProperty(&g_globalValue)); //
Property from a value with helper macro. The macro implements the code above.
behaviorContext.Property("globalReadOnlyProperty", &GlobalPropertyGetter, nullptr); // Read
only property with a getter function.
behaviorContext.Property("globalReadOnlyProperty", []() { return g_globalValue; },
nullptr); // Read only property with a Lambda function.
behaviorContext.Property("globalReadOnlyProperty", BehaviorValueGetter(&g_globalValue),
nullptr); // Read only property with a value and a helper macro.
// Write only is the same as ReadOnly, but with the setter enabled and the getter set to
nullptr. These properties are rare.
Version 1.10
483
Lumberyard Developer Guide
Example
// Global Methods behaviorContext.Method("GlobalMethod",&GlobalMethod);
// Global Constants and Enums (implemented using properties). The functions are provided
for clarity.
behaviorContext.Constant("PI", []() { return 3.14f; }); behaviorContext.Constant("PI", BehaviorConstant(3.14f)); behaviorContext.Enum<EnumIntValue>("EnumIntValue");
// Class - When you declare a class, if you want to reflect base class functionality, just
use RTTI.
behaviorContext.Class<MyClass>() // The name of the class comes from AzTypeInfo. In this
case the name is "MyClass".
// AzType information is a requirement for all classes
used with reflection in
// Lumberyard (including serialization and networking)
->Constructor<int>() // Optional additional constructors. You can have as many as
needed.
->Constant("epsilon",BehaviorConstant(0.001f)) // Class constant. All features from the
global versions apply.
->Enum<MyClass::ENUM_VALUE>("ENUM_VALUE") // Class enum. All features from the global
versions apply.
->Method("Method",&MyClass::Method) // Class method. All features from the global
versions apply.
->Property("data", &MyClass::GetData(), &MyClass::SetData) // Class features. All
features from the global versions apply.
;
// EBus class MyEBusBehaviorHandler : public MyEBus::Handler, public AZ::BehaviorEBusHandler
{ public:
AZ_EBUS_BEHAVIOR_BINDER(MyEBusBehaviorHandler ,"{19F5C8C8-4260-46B1-
B624-997CD3F10CBD}", AZ::SystemAlloctor, // Name, TypeId and default allocator.
OnEvent); // List of event names to handle and support for
BehaviorContext.
void OnEvent(int a) override // This is an event listener like other EBus listeners.
{c
Call(FN_OnEvent,a); // Forward the event to a behavior listener if there is one.
FN_***EventName*** events are declared by the AZ_EBUS_BEHAVIOR_BINDER macro.
}
}; behaviorClass.EBus<MyEBus>("MyEBus") // EBuses are not required to have TypeInfo, so you
must always provide a name.
->Handler<MyEBusBehaviorHandler >() // Allow systems that use behavior context to
create handlers for this EBus every time
// they must listen for events. If you reflect a
bus without a handler, behavior context users can only send events.
->Event("OnEvent",&MyEBus::Events::OnEvent) // Allow behavior context system to
send an "OnEvent" event. The code automatically generates
// Broadcast, Event, QueueBroadcast,
QueueEvent, and QueueFunctions if the EBus configuration
// supports them. You don't have to
provide events; you can provide only a handler if
// you don't have behavior context
systems to send events.
;
// Properties, methods, classes and ebuses can have attributes. An attribute is a
combination of a Crc32 ID and a value. The value
// can be a constant, a variable address, a global function, a class member function, or a
class member variable address.
behaviorClass.Method("GlobalMethod",&GlobalMethod)
Version 1.10
484
Lumberyard Developer Guide
Gameplay Bus
->Attribute("ValueAttr",10) // Value attribute.
->Attribute("MethodAttr", &SomeOtherGlobalMethod)
;
// You add the same attributes to a property...
behaviorClass.Property("GlobalProperty", BehaviorValueProperty(&g_globalValue)
->Attribute("MyAttr",20)
;
// or to a class or class method or property.
behaviorClass.Class<MyClass>()
->Attribute("ClassAttr",100)
->Attribute("CalssAttr1",&MyClass::SomeMethod)
->Method("Method",&MyClass::Method)
->Attribute("MethodAttr",100)
->Property("data", BehaviorValueProperty(&MyClass::m_data))
->Attribute("PropertyAttr",500)
;
The gameplay bus alerts gameplay systems that an event has occurred. You can use the bus to send contextual messages between the visual scripting, scripting, and code parts of your game in a generic and extensible way.
The gameplay bus passes an
AZStd::any
, a class that uses type erasure to hold any C++ reflected type or any Lua primitive (string, number, Boolean, etc.). It includes mechanisms for type safety to ensure that it returns the same type that it is passed. In Lua, the type can be inspected if it has been exposed to the behavior context through the typeid()
function, which uses the
AZ_RTTI
system.
Example
function MyComponent:OnEventBegin(param)
if typeid(param) == typeid(Uuid) then
-- param is a Uuid
elseif typeid(param) == typeid(Vector3) then
-- param is a Vector3
end end
The
GameplayNotificationId
is the type used as the ID for the gameplay bus. Its syntax is as follows.
GameplayNotificationId(const AZ::EntityId& entityChannel, AZ::Crc32 actionNameCrc)
The entityChannel
and actionNameCrc
parameters create a unique bus ID. You can use this ID to communicate with the bus.
When you write your events, choose the ID of an entity channel that makes sense in the context of your game. Components are automatically aware of the following two entity IDs, which you can use for channels. These IDs do not require an entity reference.
1. The component's own entity ID. To obtain it, call
GetEntityId().
Version 1.10
485
Lumberyard Developer Guide
GameplayNotifications
2. The default
AZ::EntityId()
.
To communicate directly to a specific entity, use
GetEntityId()
. To communicate indirectly to a generic audience, use
AZ::EntityId()
.
You can pass the actionNameCrc
parameter as a string or as the
AZ::Crc32
of that string when you construct the ID. This parameter should be the name of the event that gives context to the event data.
The
GameplayNotifications
class contains the gameplay bus type traits. It establishes the
GameplayNotificationId
as the bus ID. It defines the following events.
void OnEventBegin(const AZStd::any& value) void OnEventUpdate(const AZStd::any& value) void OnEventEnd(cosnt AZStd::any& value)
You can use
GameplayEventHandlerNode
to control the flow of gamplay events.
The following table describes the flow graph nodes for handling a gameplay event.
Input Port
ChannelId
EventName
Enable
Disable
Description
The channel on which to send your event. For information on choosing a channel, see
GameplayNotificationId
.
The name of the event that you want to handle. For information on available events, see
GameplayNotifications
.
Calls the
BusConnect
method and connects to
GameplayNotificationBus
.
When the node connects, it begins handling events that are received when the flowgraph updates.
Note
If you send multiple events in a flowgraph update, only the last event is used.
Calls
BusDisconnect
, disconnects from
GameplayNotificationBus
, and stops the handling of events.
The output ports for the
GameplayEventHandlerNode
are the same as those for the
GameplayNotifications
class (
OnEventBegin
,
OnEventUpdate
, and
OnEventEnd
).
Version 1.10
486
Lumberyard Developer Guide
GameplayEventSenderNode
The following image shows how the flow graph might be used be to change the position of (move) an entity.
You can use
GameplayEventSenderNode
to sent gameplay events.
The following table describes the flow graph nodes for sending a gameplay event.
Input Port
Activate
Description
Causes a gameplay event to be sent.
ChannelId
The channel on which to send your event. For information on choosing a channel, see
GameplayNotificationId
.
SendEventValue
Stores the
AZStd::any
value for delivery with the event.
EventName
EventType
The name of the event that you want to handle. For information on choosing a channel, see
GameplayNotificationId
.
Specifies the event. The options are
OnEventBegin
,
OnEventUpdating
, and
OnEventEnd
. These events are defined in the
GameplayNotfications
class.
The following image shows how the flow graph might be used to send an event when an entity enters lava.
The Lua script examples in this section illustrate the use of
GameplayNotificationBus
to control what happens when an entity enters and then exits lava.
1. The following example implements the
OnActivate
function when the entity enters lava.
local InLavaBehavior ={
Version 1.10
487
Lumberyard Developer Guide
Slices and Dynamic Slices
Properties =
{
},
} function InLavaBehavior:
OnActivate
()
local gameplayId = GameplayNotificationId(self.entityId, "InLava")
self.gameplayBus = GameplayNotificationBus.CreateHandler(self, inputBusId) end
2. The following example implements the
OnEventBegin
function to start an animation associated with the event.
function InLavaBehavior:
OnEventBegin
(floatValue)
local animInfo = AnimatedLayer("LavaHotFootDance", 0, true, 1.0, 0.0);
SimpleAnimationComponentRequestBus.Event.StartAnimation(self.entityId, animInfo)
-- tell our flow graph HUD to transition the screen effect to "In Lava"
local gameplayId = GameplayNotificationId(EntityId(), "TransitionScreenEffect")
GameplayNotificationBus.Event.OnEventBegin(gameplayId, "In Lava") end
3. The following example implements the
OnEventUpdating
function to update a health component regarding the status of the entity.
function InLavaBehavior:
OnEventUpdating
(floatValue)
-- alert the health component (this gameplay component is an example only) that we are
taking damage, it can handle any death transitions
HealthComponentBus.Event.TakeDamage(self.entityId, floatValue) end
4. The following example implements the
OnEventEnd
function to end the animation and return status to normal.
function InLavaBehavior:
OnEventEnd
(floatValue)
local animInfo = AnimatedLayer("Idle", 0, true, 1.0, 0.0);
SimpleAnimationComponentRequestBus.Event.StartAnimation(self.entityId, animInfo)
-- tell our flow graph HUD to transition the screen effect to "Normal"
local gameplayId = GameplayNotificationId(EntityId(), "TransitionScreenEffect")
GameplayNotificationBus.Event.OnEventBegin(gameplayId, "Normal") end
5. The following example implements the
OnDeactivate
function to disconnect from the gameplay bus.
function InLavaBehavior:
OnDeactivate
()
self.gameplayBus:Disconnect() end return InLavaBehavior
The Component Entity System is currently in preview and is undergoing active development. It will
replace the legacy Entity System (p. 551)
.
Version 1.10
488
Lumberyard Developer Guide
Anatomy of a Slice
A slice is a collection of configured
entities (p. 455) that is stored as a single unit in a reusable asset.
You can use slices to conveniently group entities and other slices for reuse. Slices are similar to prefabs but are part of the new Component Entity system. Slices can contain component entities, whereas prefabs cannot. Unlike prefabs, slices can be nested into a fully cascasding hierarchy. For example, a level, a house, a car, and an entire world are all slices that depend on (cascade) from a number of other slices.
You can generate a slice asset that contains any number of entities that you have placed and configured.
These entities can have arbitrary relationships. For example, they can exist in a parent/child transform hierarchy, although this is not required.
After you have created the slice asset, you can use the editor to instantiate the slice asset in your worlds, either by right-clicking in the viewport and choosing
Instantiate Slice
, or by dragging a slice asset into the viewport directly from the
File Browser
. Just as with standard prefab systems, you can then modify the entities in your slice instance. You can optionally push the changes back to the slice asset, which will affect all instances of that slice asset, as well as any other slices cascading from it.
A slice can contain instances of other slices. Modifications of a slice instance within another slice causes the changes to be stored in the instance as overrides (in the form of a data differential or delta). The modifications stored can be changes such as entity additions, entity removals, or component property changes.
The following diagram illustrates an example slice A, which contains references to two other slices B and
C. Slice A has two instances each of B and C:
Each instance contains a data patch, which may be empty if no changes or overrides are present. If the instantiation of slice B in slice A has been modified in comparison with the source asset B, the data patch contains the differences. When slice A is instantiated again, it contains instances of slice B, but with the modifications applied. Any nonoverridden fields propagate through the hierarchy. If you change a property value in the slice B asset on disk, the instance of B contained in slice A will reflect that change
— if the property for that instance has not already been overridden, as reflected in the instance's data patch.
In addition to references to other slices, slices can contain zero or more entities. These entities are original to this slice and are not acquired through referenced slice instances. A slice does not have to contain references to other slices. A slice that contains only original entities (as represented by the bottom box in the diagram) and no references to other slices is called a
leaf slice
.
Version 1.10
489
Lumberyard Developer Guide
Working with Dynamic Slices
Slices are a powerful tool for organizing entity data in your worlds. In the editor, you can choose to cascade slices and organize entity data in any desired granularity and still receive the benefits of data sharing and inheritance throughout the hierarchy. A level-based game, for example, implements each level as its own slice asset that contains instances of many other slices. These slices can potentially cascade many levels deep. You can even choose to create slices from other slices and inherit only the elements that you want.
Standard slice assets (
.slice
files) rely on the editor and cannot be instantiated at run time. However,
Lumberyard provides a mechanism for designating any
.slice
asset that you've built as a
dynamic slice
.
When you designate a slice as a dynamic slice, the Asset Processor processes and optimizes the slice for you, producing a
.dynamicslice
file asset. A dynamic slice is simply the run-time version of its source slice, containing only run-time components; the editor-dependent components have been converted to their run-time counterparts. Furthermore, dynamic slices are flattened and no longer maintain a data hierarchy, as doing so would increase memory footprint and reduce instantiation performance.
In the level-based game example previously mentioned, you could designate your giant level slice as a dynamic slice. When your game loads the level, it does so by instantiating the resulting
.dynamicslice
file.
You can choose to generate dynamic slices at whatever granularity is appropriate for your game. Because slices are loaded entirely asynchronously, they are a good choice for streaming strategies. For example, a driving game might represent each city block as a separate slice and choose to load them predictively based on player driving behavior.
To generate a dynamic slice
Right-click any
.slice
asset in the
File Browser
, and click
Set Dynamic Flag
.
The Asset Processor processes the source
.slice
file and generates a
.dynamicslice
file. The new
.dynamicslice
file appears in the File Browser as its own asset:
To remove the dynamic slice
Right-click the source
.slice
file and choose
Unset Dynamic Flag
.
The Asset Processor deletes the
.dynamicslice
file from the asset cache for you.
You can instantiate dynamic slices from your own components. To do so,
DynamicSlice
asset reference. You can populate the reference in the editor in the usual way, such as dragging a
.dynamicslice
asset from the
File Browser
onto your component’s reflected asset property.
You can then use the following EBus call to instantiate the referenced dynamic slice at a desired location in the world.
// Asset reference member, which must be reflected.
AZ::Data::Asset<AZ::DynamicPrefabAsset> m_sliceAsset;
Version 1.10
490
Lumberyard Developer Guide
Using Gems to Add C++ Code to a Lumberyard Game
// Create an instance of the dynamic slice.
AZ::Transform location = ...;
EBUS_EVENT(AzFramework::GameEntityContextRequestBus, InstantiateDynamicSlice, m_sliceAsset,
location);
Lumberyard includes a spawner component that is a good example of this behavior. You can use the spawner component directly or as an example from which to build your own.
You can see the source code for the spawner component at the file location dev\Code\Engine
\LmbrCentral\source\Scripting\SpawnerComponent.cpp
in the folder in which you installed
Lumberyard.
For information on creating an
AZ::Module
, see Creating an AZ Module . For more information about working with slices, see Working with Slices .
To add C++ code or assets to your Lumberyard game, use a gem . This document shows you how to create a gem and the various techniques that you can use to add code to it.
Creating a gem is straightforward. To create or enable a gem for your game project, follow the steps in the Gems section of the Amazon Lumberyard User Guide . The gem that you create or enable is located in the
\dev\Gems\
<gem name>
directory. The gem's directory structure is similar to the following example.
Your gem might not have all the directories listed.
\3rdParty
\Assets
\Code
\Include
\Source
\Tests
\External
Version 1.10
491
Lumberyard Developer Guide
Creating and Configuring Gems
•
3rdParty
– Contains third-party definition files that are specific to the gem.
•
Assets
– Contains assets to include in the game project that are specific to the gem.
•
Code\Include
– An additional header include path to add to a game project that uses the gem.
•
Code\Source
– Contains the source code for the gem.
•
Code\Tests
– Contains unit testing source code for projects that are built in a test configuration.
•
External
– Contains external libraries on which the gem depends that are specific to the gem.
The
\dev\Gems\
<gem name>
\Code
subdirectory has the following items that Lumberyard creates by default:
Item
An empty
EBus (p. 576) include file that is
named after the gem.
The AZ module for the gem
The default systems component files
Location
\Include\
<gem name>
\
<gem name>
Bus.h
Standard precompiled header files
Skeleton unit test source file
\Source\
<gem name>
Module.cpp
\Source\
<gem name>
SystemComponent.h
\Source\
<gem name>
SystemComponent.cpp
\Source\StdAfx.h
\Source\StdAfx.cpp
\Tests\
<gem name>
Test.cpp
Lumberyard also creates certain Waf –related files in the
\dev\Gems\
<gem name>
\Code
subdirectory. These files specify the source code content and how the gem is defined and built.
Item
Manifest file for the Waf build of the gem
Manifest file that lists additional files to for test configuration builds (for example,
Tests/
<gem name>
Test.cpp
)
Waf build script file that defines the gem
Location
<gem name>
.waf_files
<gem name>
_tests.waf_files
wscript
The manifest file that manages the source code uses the Lumberyard Waf waf_files
schema to define the source files, their Microsoft Visual Studio filter, and uber file grouping. The default
<gem name>
.waf_files
that Project Configurator generates looks like the following:
{
"none": {
"Source": [
"Source/StdAfx.cpp",
"Source/StdAfx.h"
]
Version 1.10
492
Lumberyard Developer Guide
Updating Gem Code
},
"auto": {
"Include": [
"Include/
<gem name>
/
<gem name>
Bus.h"
],
"Source": [
"Source/
<gem name>
Module.cpp",
"Source/
<gem name>
SystemComponent.cpp",
"Source/
<gem name>
SystemComponent.h"
]
}
}
The
.waf_files
file contains the following three levels of indentation:
• The first level contains the uber file mapping for uber file–enabled builds.
• none
specifies files to be excluded from the uber file. Precompiled headers must be listed here.
• auto
specifies files that are automatically combined into modules that are optimized for compile time by Waf.
• You can also specify a fixed uber file name (for example, my_gem_uber_0.cpp
) at this level to specially group a set of files. All of the files in the grouping are combined into my_gem_uber_0.cpp
.
This technique is useful to restrict which files are combined, like platform-specific code.
• The second level represents the Visual Studio filters that determine how the files are organized in the
Visual Studio solution that Waf generates.
• A special value called
Root
represents the root node of the project explorer in Microsoft Visual
Studio (that is, the file is not placed in any subdirectory).
• The third level contains paths to the source files relative to the location of the waf_files
file itself.
To update code in your gem, add a third-party library, new source code files, system components, or dependencies on other gems or Lumberyard modules.
A gem can use any Lumberyard third-party library, including its own private third-party library. To register a private third-party library for a gem, create a third-party configuration file in the
\3rdParty directory of the gem.
When you set the configuration file to an external third-party library, the library can be added as a gem dependency through Waf's dependency mechanisms.
Waf uses two conventions to add dependencies to third-party libraries: uselib
and use
. The convention uselib
is a wscript keyword that configures a module to link to a library's include path, library path, and library. If a gem uses uselib
to consume its gem-specific library, then that library is available to the gem only for compiling and linking.
The convention use
is similar to the uselib
keyword, except that the library's dependencies are recursively propagated to the module that adds the dependency. If a gem uses use
to consume its gemspecific library, then the library can be used recursively. This means that if the gem is enabled, the gem– specific third-party library is also available to the game project or dependent gems.
To add source code (for example, C++ or Qt) to a gem, use the Lumberyard Waf build system . Place internal source files (that is, files not meant to be exposed outside of the gem) under the
\Code\Source
Version 1.10
493
Lumberyard Developer Guide
Updating Gem Code directory. Place header files that can be included in projects or other gems in the
\Code\Include\
<gem name>
\
directory. Place additional unit tests in the
\Code\Tests
directory.
To add code files to a gem
1. Add the files to the target location. For consistency, we recommend that you place the source files somewhere in the
\Code
directory.
2. Add the source files to the Waf manifest waf_files
file. Following the format described earlier, add the source file paths to either the
<gem name>
.waf_files
file and/or the
<gem name>
_test.waf_files
file.
3. From a command prompt window, run lmbr_waf configure
to configure Waf and regenerate the
Microsoft Visual Studio solution.
New gems come with a default system component called
<gem name>
SystemComponent
. You can modify this system component according to your requirements. To communicate with the system component, you can define as many EBuses as required. If you want to add additional components, you must add the component descriptor to the AZ module for the gem (
\Code\Source\
<gem name>
Module.cpp
). For more information, see
and
Creating System Components (p. 467)
.
In addition to adding dependencies to gem-specific third-party libraries, your gem can specify dependencies on Lumberyard Engine modules, other gems, or third-party libraries for Lumberyard.
Adding a Dependency on a Lumberyard Module
Any gem can be configured to depend on any of the following Lumberyard framework modules:
•
AzCore
•
AzFramework
•
AzGameFramework
•
AzQtComponents
•
AzToolsFramework
•
GridMate
•
GridMateForTools
To declare a dependency on one of these Lumberyard modules, use the Waf use
mechanism. The following example wscript
file specifies a dependency on
AzFramework
.
def build(bld):
bld.DefineGem(
# Add custom build options here
includes = [bld.Path('Code/CryEngine/CryAction'),
use
= ['
AzFramework
'],
)
Adding a Dependency on Another Gem
You can configure a gem to depend on another gem by modifying the gem.json
file that is in the gem's directory. The following example shows how the Camera Framework gem that is included with
Lumberyard declares a dependency on the Camera Gem. This gems.json
file is located in the
\dev\Gems
\CameraFramework\
directory.
Version 1.10
494
Lumberyard Developer Guide
Updating Gem Code
{
"
Dependencies
": [
{
"Uuid": "f910686b6725452fbfc4671f95f733c6",
"VersionConstraints": [
"~>0.1"
],
"_comment": "Camera"
}
],
"GemFormatVersion": 3,
"Uuid": "54f2763fe191432fa681ce4a354eedf5",
"Name": "CameraFramework",
"Version": "0.1.0",
"LinkType": "Dynamic",
"DisplayName": "Camera Framework [PREVIEW]",
"Tags": ["Camera", "Framework"],
"Summary": "The Camera Framework Gem includes the camera rig component which drives
an entity through camera behaviors. Behaviors are provided in the Starting Point Camera
Gem.",
"IconPath": "preview.png"
}
The Camera Framework Gem specifies the Camera Gem in the
Dependencies
section. The
Dependencies section also has a
VersionConstraints
section that you can use to specify versioning requirements.
Adding a Dependency on a Third-Party Library for Lumberyard
You can define a gem that uses a third-party library for Lumberyard that another module is also using.
To do so, use the Waf uselib
mechanism to add the dependency to the gem, as in the following example wscript
file.
def build(bld):
bld.DefineGem(
# Add custom build options here
includes = [bld.Path('Code/CryEngine/CryAction'),
use = ['AzFramework'],
uselib
= ['
AWS_CPP_SDK
']
)
Note
You can also specify use,
but use this technique with caution. The recursive nature of use
can lead to linker errors, especially duplicate symbol errors.
Version 1.10
495
Lumberyard Developer Guide
Input in Amazon Lumberyard
Use the information in this section to learn about game input devices and channels in Amazon
Lumberyard.
Note
For information on the
Input
component that replaces legacy action maps, see Input in the
Amazon Lumberyard User Guide.
Topics
•
Input in Amazon Lumberyard (p. 496)
•
The AZ framework input system is in preview release and is subject to change.
Input is what differentiates interactive experiences from all other entertainment media. Regardless of genre or platform, every game is driven by some form of player interaction with a physical input device. There are many different types of input devices, each of which can produce a wide range of input data. Furthermore, the way this data is delivered to an application is rarely consistent across devices or platforms. As a cross-platform game engine, Lumberyard's goal is to provide platform-independent access to input data from any supported device. The goal is to provide a common interface with these qualities:
• Platform and device agnostic
• Extensible
• Efficient
In addition, input data should have these attributes:
• Must be obtainable by subscribing to input device events
• Must be obtainable on demand by polling the state or value of an input device
• Can be a custom payload, but adds no overhead when not used
Version 1.10
496
Lumberyard Developer Guide
AZ Framework Input
Lumberyard has created an input system that satisfies all these requirements.
A new input interface and
IInput
implementation act as a bridge between the new input system and the existing
IInput
interface. If you depend on the existing
IInput
interface and
CryInput
implementation, this bridge gives you the least disruptive migration path to the new interface. For more information, see
The new Lumberyard input interface is called AZ framework input. AZ framework already provides abstracted interfaces for platform-specific features like file I/O and application lifecycle management, so the AZ framework code location is a natural fit.
The AZ framework input interface uses the
AZCore
EBus system and defines the following classes and
EBuses:
•
InputDevice
– A base class that represents a physical input device.
•
InputDeviceId
– A device name and device index that together uniquely identify an
InputDevice
.
•
InputDeviceNotificationBus
– An EBus interface that subscribes to events from input devices when they connect or disconnect.
•
InputDeviceRequestBus
– An EBus interface that queries input devices about their associated input channels or current connected state.
•
InputChannel
– A base class that represents a specific source of input data (for example, the left mouse button). Input devices typically have multiple input channels.
•
InputChannelId
– A name that uniquely identifies an
InputChannel
.
•
InputChannelNotificationBus
– An EBus interface that subscribes to events from input channels when the channels are active or when their state or value changes.
•
InputChannelRequestBus
– An EBus interface that obtains an input channel from the input channel's
ID. You can then query the input channel directly for its current state or value.
•
InputChannelEventListener
– An event monitor that inherits from
InputChannelNotificationBus
but provides additional features. Subscribers can use the additional features to receive events in priority order or filter events based on the source device or channel. Subscribers can also consume events so that the events aren’t passed on to lower priority monitors.
To process input, you can simply inherit from
AzFramework::InputChannelEventListener
. You can also create a filter to receive events only from specific input devices or channels, and then override
OnInputChannelEvent
to process the input data.
If you want to query the current input state directly, use
AzFramework
::
InputChannelRequestBus
to obtain an input channel's ID. Then query the input channel for its current state or value.
Text Input Interfaces
The following interfaces are designed to process text input. The input is delivered as a complete string of
UTF-8 code points. This eliminates the requirement to keep track of and interpret individual code units or convert from other encodings.
•
InputTextEventNotificationBus
– An EBus interface that subscribes to text events from input devices or input channels.
Version 1.10
497
Lumberyard Developer Guide
AZ Framework Input
•
InputTextEntryRequestBus
– An EBus interface that sends text entry requests. The requests inform input devices that the user is expecting to start or stop entering text.
•
InputTextEventListener
– An event monitor that inherits from
InputTextNotificationBus
but provides additional features. Subscribers can use the additional features to receive events in priority order or consume events so that the events aren’t passed on to lower priority monitors.
Auxiliary Input Interfaces
The following AZ framework input auxiliary interfaces are only implemented by certain input devices.
You can use these interfaces to query or post data related to device activity like vibration effects, motion sensors, or the mouse cursor.
•
InputHapticFeedbackBus
– An EBus interface that sends haptic feedback requests to connected input devices.
•
InputMotionSensorRequestBus
– An EBus interface that sends motion sensor requests to connected input devices.
•
InputSystemCursorRequestBus
– An EBus interface that queries or changes the state, position, or appearance of the system cursor.
All input device classes inherit from
AzFramework::InputDevice
. While multiple instances of the same class can exist, every input device is identified by a unique
InputDeviceId
.
Input Devices Included in Lumberyard
The base class is designed so that you can inherit from it to implement new types of input devices.
However, Lumberyard already includes implementations for the following devices:
Device Type
Mouse
Keyboard
Gamepad
Touch
Motion
Virtual keyboard
Virtual reality controller
Supported Platforms
Windows, macOS
Windows and macOS
Windows, macOS, iOS, Android, consoles iOS, Android iOS, Android iOS, Android, consoles
Oculus, OpenVR
This core set of input devices are managed by the
AzFramework::InputSystemComponent
. You can use this component to configure the type and number of input devices that your application creates at startup.
Creating New Input Devices
You can create and implement new types of input devices by inheriting from
AzFramework::InputDevice and creating or destroying instances of the new class as required. For examples, see the Oculus and OpenVR Gems , which define and create new types of input devices that inherit from
AzFramework::InputDevice
. Their code is located at the Lumberyard directory locations
\dev\Gems
\Oculus
and
\dev\Gems\OpenVR
, respectively.
Version 1.10
498
Lumberyard Developer Guide
AZ Framework Input
The implementation details of each input device differ depending on the device type and platform.
However, almost all devices follow a similar pattern. They use a platform-specific API to obtain raw input data for each frame and then update all the device’s associated input channels accordingly.
When you implement an input device, use only your device’s
TickInput
function to update the value of the input channels. This ensures that input events are delivered at the same time every frame.
Depending on how the input device gets the raw, platform-specific input, you might have to use one of the following techniques:
• Polling the underlying input API on each call to your input device’s
TickInput
function. For examples, see all
InputDeviceGamepad
implementations in the directory
\dev\Code\Framework\AzFramework
\AzFramework\Input\Devices\Gamepad
.
• Queuing or coalescing input data from the application’s main message loop until the next call to
TickInput
. For an example, see
InputDeviceMouse
in the directory
\dev\Code\Framework\AzFramework
\AzFramework\Input\Devices\Mouse
.
• Ensuring input channels are updated in a thread-safe manner if no raw input is received on the main thread. For an example, see
InputDeviceTouchAndroid
in the directory
\dev\Code\Framework
\AzFramework\AzFramework\Input\Devices\Touch
.
Input devices can have multiple input channels. Each channel represents a discrete source of input data that is uniquely identified by an
InputChannelId
.
Input channels use
AzFramework::InputChannelNotificationBus::OnInputChannelEvent
to broadcast events. A channel broadcasts events when the channel's state or value changes from one frame to the next or if the channel is still active or held. Input channels can also be accessed directly and polled at any time to query their current state and value.
Creating Input Channels
Like the
AzFramework::InputDevice
base class, you can inherit from
AzFramework::InputChannel
to implement new types of input data sources.
Input Channels Included in Lumberyard
Lumberyard provides the following input channel implementations that are used by the devices listed in
the Input Devices (p. 498) section. You can also use these implementations for new input devices.
Input Channel
InputChannelAnalog
Example Use
Gamepad trigger
InputChannelAnalogWithPosition2D
Touch with pressure at a position
InputChannelAxis1D
Gamepad thumbstick x or y
InputChannelAxis2D
Gamepad thumbstick x and y together
InputChannelAxis3D
InputChannelDelta
Motion sensor acceleration, rotation, or magnetic field
Mouse wheel
InputChannelDigital
Gamepad button or keyboard key
Version 1.10
499
Lumberyard Developer Guide
Migration Path
Input Channel Example Use
InputChannelDigitalWithPosition2D
Touch without pressure at a position
InputChannelQuaternion
Motion sensor orientation
The new AZ framework input system was enabled by default in Lumberyard version 1.10.
To disable the AZ framework input system, use the
AZ_FRAMEWORK_INPUT_ENABLED
compile time define
. For more information, see the header file at the location
\dev\Code\Framework\AzFramework
\AzFramework\Input\System\InputSystemComponent.h
.
When you disable AZ framework input, Lumberyard reverts to using the legacy
CryInput
implementation of the
IInput
interface. This is not recommended, as the
CryInput
implementation will no longer be maintained and the
IInput
interface will be discontinued in a future release.
All existing dependencies on
IInput
continue to function identically when you use the new
AzToLyInput implementation of this interface, but the
IInput
interface will be discontinued in a future release.
Therefore, if you have custom code that depends on the
IInput
interface, we recommend that you convert it to use the AZ framework input system. For an example, see the following source files:
/dev/Gems/StartingPointInput/Code/Source/Input.h
/dev/Gems/StartingPointInput/Code/Source/Input.cpp
These files use the new system but use
#if
and
#else
directives that show how the implementations differ depending on whether
AZ_FRAMEWORK_INPUT_ENABLED
is defined.
This section contains information on legacy game input in Amazon Lumberyard. For information on
Lumberyard's new input system, see Input in Amazon Lumberyard (p. 496) .
Topics
•
•
•
Setting Up Controls and Action Maps (p. 503)
Note
Lumberyard's
Input
component replaces legacy action maps. For more information, see Input in the Amazon Lumberyard User Guide.
Version 1.10
500
Lumberyard Developer Guide
CryInput
The Action Map Manager provides a high-level interface to handle input controls inside a game.
The Action Map system is implemented in Lumberyard, and can be used directly by any code inside
Lumberyard or the GameDLL.
The Action Map Manager is initialized when Lumberyard is initialized. Your game must specify the path for the file defaultProfile.xml
(by default, the path is
Game/Libs/Config/defaultProfile.xml
). You can do this by passing the path to the manager. For example:
IActionMapManager* pActionMapManager = m_pFramework->GetIActionMapManager(); if (pActionMapManager)
{
pActionMapManager->InitActionMaps(filename);
}
Upon initialization, the Action Map Manager clears all existing initialized maps, filters, and controller layouts.
You can enable the feature that allows action maps to receive actions during runtime. Use the following code to enable or disable an action map during runtime: pActionMapMan->EnableActionMap("default", true);
To receive actions, implement the
IActionListener
interface in a class.
The main purpose of CryInput is to provide an abstraction that obtains input and status from various input devices such as a keyboard, mouse, joystick, and so on.
It also supports sending feedback events back to input devices—for example, in the form of force feedback events.
The common interfaces for the input system can be found in
IInput.h
, in the CryCommon project.
IInput
is the main interface of the input system. An instance implementing this interface is created automatically during system initialization in the
InitInput
function (
InitSystem.cpp
in CrySystem, see also
CryInput.cpp
in CryInput).
Only one instance of this interface is created. CrySystem also manages the update and shutdown of the input system.
This
IInput
instance is stored in the
SSystemGlobalEnvironment
structure gEnv. You can access it through gEnv->pInput
or, alternatively, through the system interface by
GetISystem()->GetIInput()
.
Access through the gEnv
variable is the most commonly used method.
A common use case within the input system is to create listener classes in other modules (for example,
CryGame) by inheriting from
IInputEventListener
and registering/unregistering the listener class with the input system for notifications of input events.
Version 1.10
501
Lumberyard Developer Guide
CryInput
For example, the Action Map System registers itself as an input listener and forwards game events only for the keys defined in the profile configuration files to further abstract the player input from device to the game.
SInputEvent
encapsulates information that is created by any input device and received by all input event listeners.
Input devices normally relate directly to physical input devices such as a joypad, mouse, keyboard, and so on. To create a new input device, you must implement all functions in the
IInputDevice
interface and register an instance of it with the Input System using the
AddInputDevice
function.
The
Init
function is called when registering the
IInputDevice
with the Input System; it is not necessary to manually call it when creating the input devices.
The
Update
function is called at every update of the Input System—this is generally where the state of the device should be checked/updated and the Input Events generated and forwarded to the Input
System.
It is common for input devices to create and store a list in SInputSymbol of each symbol the input device is able to generate in the Init function. Then, in the update function, the symbols for the buttons/axes that changed are looked up and used (via their AssignTo function) to fill in most of the information needed for the events, which are then forwarded to the input system.
Example:
// function from CInputDevice (accessible only within CryInput)
MapSymbol(...)
{
SInputSymbol* pSymbol = new SInputSymbol( deviceSpecificId, keyId, name, type );
pSymbol->user = user;
pSymbol->deviceId = m_deviceId;
m_idToInfo[ keyId ] = pSymbol;
m_devSpecIdToSymbol[ deviceSpecificId ] = pSymbol;
m_nameToId[ name ] = deviceSpecificId;
m_nameToInfo[ name ] = pSymbol;
return pSymbol;
} bool CMyKeyboardInputDevice::Init()
{
...
//CreateDeviceEtc();
...
m_symbols[ DIK_1 ] = MapSymbol( DIK_1, eKI_1, "1" );
m_symbols[ DIK_2 ] = MapSymbol( DIK_2, eKI_2, "2" );
...
} void CMyKeyboardInputDevice::Update( ... )
{
// Acquire device if necessary
...
// Will probably want to check for all keys, so the following section might be part of
a loop
SInputSymbol* pSymbol = m_symbols[ deviceKeyId ];
...
// check if state changed
Version 1.10
502
Lumberyard Developer Guide
Setting Up Controls and Action Maps
...
// This is an example for, when pressed, see ChangeEvent function for axis type
symbols
pSymbol->PressEvent( true );
SInputEvent event;
pSymbol->AssignTo( event, modifiers );
gEnv->pInput->PostInputEvent( event );
}
To forward events to the input system so that event listeners can receive them, use the
PostInputEvent function from
IInput
.
If adding your input device to CryInput, it may be useful to inherit directly from
CInputDevice
, as it already provides a generic implementation for most functions in IInputDevice.
Note
This file is included with the full source of CryEngine and is not available in the FreeSDK or
GameCodeOnly solutions. For these licenses please derive from IInputDevice directly.
This section describes how to create and modify action maps to customize the controls to the needs of your game.
Action map profiles for all supported platforms are located in
Game\Libs\Config\Profile
\DefaultProfile.xml
. This default XML file organizes controls into the following sections, each of which is controlled by its own action map:
• multiplayer
• singleplayer
• debug
• flycam
• default
• player
• vehicle
• land vehicle
• sea vehicle
• helicopter
Each action map can be enabled or disabled during runtime from Flow Graph, in Lua scripts, or in C++ code.
An action map is a set of key/button mappings for a particular game mode. For example, there is an
<actionmap>
section for helicopter controls called "Helicopter", which means that everything inside that section consists of key and button bindings that apply only when flying a helicopter. To change your common in-game bindings, go to the section starting with
<actionmap name="default">
. There are also sections for multiplayer-specific bindings and, of course, any other vehicles or modes you need.
Version 1.10
503
Lumberyard Developer Guide
Setting Up Controls and Action Maps
The following is an overview of a standard action map, in this case the standard debug one:
<actionmap name="debug" version="22">
<!-- debug keys – move to debug when we can switch devmode-->
<action name="flymode" onPress="1" noModifiers="1" keyboard="f3" />
<action name="godmode" onPress="1" noModifiers="1" keyboard="f4" />
<action name="toggleaidebugdraw" onPress="1" noModifiers="1" keyboard="f11" />
<action name="togglepdrawhelpers" onPress="1" noModifiers="1" keyboard="f10" />
<action name="ulammo" onPress="1" noModifiers="1" keyboard="np_2" />
<action name="debug" onPress="1" keyboard="7" />
<action name="thirdperson" onPress="1" noModifiers="1" keyboard="f1" />
<!-- debug keys – end -->
</actionmap>
Versioning
<actionmap name="debug" version="22">
When the version value is incremented, Lumberyard ensures that the user profile receives the newly updated action map. This is quite useful when deploying new actions in a patch of a game that is already released. If the version stays the same, changes or additions to the action maps are not propagated to the user profile.
Activation Modes
The following activation modes are available:
• onPress – The action key is pressed
• onRelease – The action key is released
• onHold – The action key is held
• always – Permanently activated
The activation mode is passed to action listeners and identified by the corresponding Lua constant:
• eAAM_OnPress
• eAAM_OnRelease
• eAAM_OnHold
• eAAM_Always
Modifiers available:
• retriggerable
• holdTriggerDelay
• holdRepeatDelay
• noModifiers – Action takes place only if no
Ctrl
,
Shift
,
Alt
, or
Win
keys are pressed
• consoleCmd – Action corresponds to a console command
• pressDelayPriority
• pressTriggerDelay
• pressTriggerDelayRepeatOverride
• inputsToBlock – Specify the input actions to block here
Version 1.10
504
Lumberyard Developer Guide
Setting Up Controls and Action Maps
• inputBlockTime – Time to block the specified input action
You can also define action filters directly in your defaultProfile.xml
file. The following attributes are available:
•
name
– How the filter will be identified.
•
type
– Specify actionFail
to cause an action to fail. Specify actionPass
to allow the action to succeed.
A sample action filter follows:
<actionfilter name="no_move" type="actionFail">
<!-- actions that should be filtered -->
<action name="crouch"/>
<action name="jump"/>
<action name="moveleft"/>
<action name="moveright"/>
<action name="moveforward"/>
<action name="moveback"/>
<action name="sprint"/>
<action name="xi_movey"/>
<action name="xi_movex"/>
<!-- actions end -->
</actionfilter>
Links to the different controller layouts can also be stored in this file:
<controllerlayouts>
<layout name="Layout 1" file="buttonlayout_alt.xml"/>
<layout name="Layout 2" file="buttonlayout_alt2.xml"/>
<layout name="Layout 3" file="buttonlayout_lefty.xml"/>
<layout name="Layout 4" file="buttonlayout_lefty2.xml"/>
</controllerlayouts>
Note
The "file" attribute links to a file stored in "libs/config/controller/" by default.
In Lumberyard, you can use the console command i_reloadActionMaps
to re-initialize the defined values. The ActionMapManager sends an event to all its listeners to synchronize the values throughout the engine. If you're using a separate GameActions file like GameSDK, make sure this class will receive the update to re-initialize the actions/filters in place. Keep in mind that it's not possible to define action maps, filters, or controller layouts with the same name in multiple places (for example, action filter no_move
defined in defaultProfile.xml
and the
GameActions
file).
To handle actions during runtime, you can use flow graphs or Lua scripts.
• Flow Graph – Input nodes can be used to handle actions. Only digital inputs can be handled from a flow graph. For more information, see Flow Graph System in the Amazon Lumberyard User Guide .
• Lua script – While actions are usually not intended to be received directly by scripts, it is possible to interact with the Action Map Manager from Lua.
Version 1.10
505
Lumberyard Developer Guide
Setting Up Controls and Action Maps
The default mapping for input on the PC is shown in the following table. To reconfigure the controls
for your game, follow the instructions in Setting Up Controls and Action Maps (p. 503) and
Player Action
Player Movement
Player Aim
Jump
Sprint
Crouch
Slide
(when sprinting)
Fire
Zoom
Melee
Fire Mode
Reload
Use
Toggle Weapon
Toggle Explosive
Toggle Binoculars
Toggle Light
(attachment)
Third Person Camera
F1
1
3
B
L
PC
W, A, S, D
Mouse XY
C
C
Spacebar
Shift
2
R
F
Mouse 1
Mouse 2
V
Vehicle Action
Accelerate
Boost
Brake/Reverse
Handbrake
Steer
Look
Horn
Fire
Version 1.10
506
PC
W
Shift
S
Spacebar
A/D
Mouse XY
H
Mouse 1
Vehicle Action
Change Seat
Headlights
Helicopter Action
Ascend
Descend
Roll Left
Roll Right
Yaw Left
Yaw Right
Pitch Up
Pitch Down
Lumberyard Developer Guide
Setting Up Controls and Action Maps
PC
C
L
PC
W
S
A
D
Mouse X (left)
Mouse X (right)
Mouse Y (up)
Mouse Y (down)
Multiplayer Action
Show Scoreboard
PC
TAB
This page lists some of the name conventions used for action maps.
Key Gestures
Letters
Numbers
Arrows
Function keys
Numpad
Esc
~
Tab
CapsLock
Shift
Ctrl
"a" - "z"
"1" - "0"
"up", "down", "left", "right"
"f1" - "f15"
"np_1" - "np_0", "numlock", "np_divide", "np_multiply", "np_subtract",
"np_add", "np_enter", "np_period"
"escape"
"tilde"
"tab"
"capslock"
"lshift", "rshift"
"lctrl", "rctrl"
Version 1.10
507
Lumberyard Developer Guide
Setting Up Controls and Action Maps
.
/
Home
End
Delete
PageUp
PageDown
Insert
ScrollLock
PrintScreen
Pause/Break
;
[ ]
"\"
,
'
Enter
Alt spacebar
-
=
Backspace
"period"
"slash"
"home"
"end"
"delete"
"pgup"
"pgdn"
"insert"
"scrolllock"
"print"
"pause"
"lalt", "ralt"
"space"
"minus"
"equals"
"backspace"
"lbracket", "rbracket"
"backslash"
"semicolon"
"apostrophe"
"enter"
"comma"
Mouse Gestures
Left/primary mouse button
Right/secondary mouse button
Mouse wheel up
Mouse wheel down
New position along xaxis
New position along yaxis
"mouse1"
"mouse2"
"mwheel_up"
"mwheel_down"
"maxis_x"
"maxis_y"
Version 1.10
508
Lumberyard Developer Guide
CryExtension
The
Code\CryCommon
directory is the central directory for all the engine interfaces (as well as some commonly used code stored there to encourage reuse).
This section includes the following topics:
•
•
•
•
Serialization Library (p. 533)
The complexity of Lumberyard can be challenging to both newcomers and experienced users who want to understand, configure, run, and extend it. Refactoring Lumberyard into extensions makes it easier to manage. Existing features can be unplugged (at least to some degree), replaced, or customized, and new features added. Extensions can consolidate code for a single feature in one location. This avoids having to implement a feature piecemeal across a number of the engine's base modules. Refactoring into extensions can also make the system more understandable at a high level.
Lumberyard's extension framework is loosely based on some fundamental concepts found in Microsoft's
Component Object Model (COM). The framework defines two base interfaces that each extension needs to implement, namely
ICryUnknown
and
ICryFactory
. These are similar to COM's
IUnknown
and
IClassFactory
. The interfaces serve as a base to instantiate extensions, allow interface type casting, and enable query and exposure functionality.
The framework utilizes the concept of shared pointers and is implemented in a way to enforce their consistent usage to help reduce the chance of resource leaks. A set of C++ templates wrapped in a few
macros is provided as Glue Code Macros (p. 515) that encourage engine refactoring into extensions.
The glue code efficiently implements all base services and registers extensions within the engine.
Additionally, a few helper functions implement type-safe casting of interface pointers, querying the IDs of extension interfaces, and convenient instantiation of extension classes. Hence, repetitive writing of tedious boilerplate code is unnecessary, and the potential for introducing bugs is reduced. An example is provided in the section
. If the provided glue code is not applicable, then you must implement the interfaces and base services manually, as described in the section
Version 1.10
509
Lumberyard Developer Guide
Composites
Clients access extensions through a system wide factory registry. The registry allows specific extension classes to be searched by either name or ID, and extensions to be iterated by using an interface ID.
The framework allows extensions to expose certain internal objects that they aggregate or are composed of. These so called
composites
are extensions themselves because they inherit from
ICryUnknown
.
Composites allow you to reuse desired properties like type information at runtime for safe casting and loose coupling.
Although the framework was designed and implemented to utilize shared pointers and enforce their usage in order to reduce the possibility of resource leaks, raw interface pointers can still be acquired.
Therefore, care needs to be taken to prevent re-wrapping those raw interface pointers in shared pointer objects. If the original shared pointer object is not passed during construction so that its internal reference counter can be referred to, the consistency of reference counting will be broken and crashes can occur. A best practice is to use raw interface pointers only to operate on interfaces temporarily, and not store them for later use.
You must use globally unique identifiers (GUIDs) to uniquely identify extensions and their interfaces.
GUIDs are essentially 128-bit numbers generated by an algorithm to ensure they only exist once within a system such as Lumberyard. The use of GUIDs is key to implementing the type-safe casting of extension interfaces, which is particularly important in large scale development projects. To create GUIDs, you can use readily available tools like the
Create GUID
feature in Visual Studio or the macro below.
GUIDs are defined as follows.
struct CryGUID
{
uint64 hipart;
uint64 lopart;
...
}; typedef CryGUID CryInterfaceID; typedef CryGUID CryClassID;
Declared in the following framework header files:
•
CryCommon/CryExtension/CryGUID.h
•
CryCommon/CryExtension/CryTypeID.h
The following Visual Studio macro can be used to generate GUIDs conveniently within the IDE. The macro writes GUIDs to the current cursor location in the source code editor window. Once added to
Macro Explorer
, the macro can be bound to a keyboard shortcut or (custom) toolbar.
Public Module CryGUIDGenModule
Sub GenerateCryGUID()
Dim newGuid As System.Guid
newGuid = System.Guid.NewGuid()
Dim guidStr As String
Version 1.10
510
Lumberyard Developer Guide
ICryUnknown
guidStr = newGuid.ToString("N")
guidStr = guidStr.Insert(16, ", 0x")
guidStr = guidStr.Insert(0, "0x")
REM guidStr = guidStr + vbNewLine
REM guidStr = guidStr + newGuid.ToString("D")
DTE.ActiveDocument.Selection.Text = guidStr
End Sub
End Module
ICryUnknown
provides the base interface for all extensions. If making it the top of the class hierarchy is not possible or desired (for example, in third party code), you can apply an additional level of indirection to expose the code by using the extension framework. For an example, see
If ICryUnknown Cannot Be the Base of the Extension Class (p. 530) .
ICryUnknown is declared as follows.
struct ICryUnknown
{
CRYINTERFACE_DECLARE(ICryUnknown, 0x1000000010001000, 0x1000100000000000)
virtual ICryFactory* GetFactory() const = 0; protected:
virtual void* QueryInterface(const CryInterfaceID& iid) const = 0;
virtual void* QueryComposite(const char* name) const = 0;
}; typedef boost::shared_ptr<ICryUnknown> ICryUnknownPtr;
•
GetFactory()
returns the factory with which the specified extension object was instantiated. Using the provided glue code this function has constant runtime.
•
QueryInterface()
returns a void pointer to the requested interface if the extension implements it, or NULL otherwise. This function was deliberately declared as protected to enforce usage of
that is linear in the number of supported interfaces. Due to glue code implementation details, no additional internal function calls are needed. A generic code generator produces a series of instructions that compares interface IDs and returns a properly cast pointer.
•
QueryComposite()
returns a void pointer to the queried composite if the extension exposes it; otherwise, NULL. As with
QueryInterface()
, this function was deliberately declared as protected to enforce type querying. For information on type querying, see
. The function has a (worst case) run time linear in the number of exposed composites.
• Unlike in COM,
ICryUnknown
does not have
AddRef()
and
Release()
. Reference counting is implemented in an non-intrusive way by using shared pointers that are returned by the framework when extension classes are instantiated.
Declared in the following framework header file:
Version 1.10
511
Lumberyard Developer Guide
ICryFactory
•
CryCommon/CryExtension/ICryUnknown.h
ICryFactory
provides the base interface to instantiate extensions. It is declared as follows.
struct ICryFactory
{
virtual const char* GetClassName() const = 0;
virtual const CryClassID& GetClassID() const = 0;
virtual bool ClassSupports(const CryInterfaceID& iid) const = 0;
virtual void ClassSupports(const CryInterfaceID*& pIIDs, size_t& numIIDs) const = 0;
virtual ICryUnknownPtr CreateClassInstance() const = 0; protected:
virtual ~ICryFactory() {}
};
•
GetClassName()
returns the name of the extension class. This function has constant run time when the provided glue code is used.
•
GetClassID()
returns the ID of the extension class. This function has constant run time when the provided glue code is used.
•
ClassSupports(iid)
returns true if the interface with the specified ID is supported by the extension class; otherwise, false. This function has a (worst case) run time linear in the number of supported interfaces when the provided glue code is used.
•
ClassSupports(pIIDs, numIIDs)
returns the pointer to an internal array of IDs enumerating all of the interfaces that this extension class supports as well as the length of the array. This function has constant run time when the provided glue code is used.
•
CreateClassInstance()
dynamically creates an instance of the extension class and returns a shared pointer to it. If the extension class is implemented as a singleton, it will return a (static) shared pointer that wraps the single instance of that extension class. This function has constant run time when the provided glue code is used, except for the cost of the constructor call for non-singleton extensions.
• The destructor is declared protected to prevent explicit destruction from the client side by using delete
, boost::shared_ptr<T>
, etc.
ICryFactory
instances exist (as singletons) throughout the entire lifetime of any Lumberyard process and
must not
be destroyed.
Declared in the following framework header file:
•
CryCommon/CryExtension/ICryFactory.h
ICryFactoryRegistry is a system-implemented interface that enables clients to query extensions. It is declared as follows.
struct ICryFactoryRegistry
Version 1.10
512
Lumberyard Developer Guide
Additional Extensions
{
virtual ICryFactory* GetFactory(const char* cname) const = 0;
virtual ICryFactory* GetFactory(const CryClassID& cid) const = 0;
virtual void IterateFactories(const CryInterfaceID& iid, ICryFactory** pFactories, size_t&
numFactories) const = 0; protected:
virtual ~ICryFactoryRegistry() {}
};
•
GetFactory(cname)
returns the factory of the extension class with the specified name; otherwise,
NULL.
•
GetFactory(cid)
returns the factory of the extension class with the specified ID; otherwise, NULL.
•
IterateFactory()
if pFactories
is not NULL,
IterateFactory
copies up to numFactories
entries of pointers to extension factories that support iid
. numFactories
returns the number of pointers copied.
If pFactories
is NULL, numFactories
returns the total amount of extension factories that support iid
.
• The destructor was declared protected to prevent explicit destruction from the client side by using delete
, boost::shared_ptr<T>
, etc.
ICryFactoryRegistry
is a system interface and that exists throughout the entire lifetime of any CryEngine process and
must not
be destroyed.
Declared in the following framework header file:
•
CryCommon/CryExtension/ICryFactoryRegistry.h
Use the methods defined in
ICryUnknown
for additional functionality.
Interface casting semantics have been implemented to provide syntactically convenient and type-safe casting of interfaces. The syntax was designed to conform with traditional C++ type casts and respects const
rules.
ICryFactory* pFactory = ...; assert(pFactory);
ICryUnknownPtr pUnk = pFactory->CreateClassInstance();
IMyExtensionPtr pMyExtension = cryinterface_cast<IMyExtension>(pUnk); if (pMyExtension)
{
// it's safe to work with pMyExtension
}
Interface casting also works on raw interface pointers. However, please consider the guidelines described in the section
Shared and raw interface pointers (p. 510)
.
Declared in the following framework header file:
•
CryCommon/CryExtension/ICryUnknown.h
Version 1.10
513
Lumberyard Developer Guide
Additional Extensions
Occasionally, it is necessary to know the ID of an interface, e.g. to pass it to
ICryFactoryRegistry::IterateFactories()
. This can be done as follows.
CryInterfaceID iid = cryiidof<IMyExtension>();
Declared in the following framework header file:
•
CryCommon/CryExtension/ICryUnknown.h
Use this extension to check whether pointers to different interfaces belong to the same class instance.
IMyExtensionAPtr pA = ...;
IMyExtensionBPtr pB = ...; if (CryIsSameClassInstance(pA, pB))
{
...
}
This works on both shared and raw interface pointers.
Declared in the following framework header file:
•
CryCommon/CryExtension/ICryUnknown.h
Extensions can be queried for composites as follows.
IMyExtensionPtr pMyExtension = ...;
ICryUnknownPtr pCompUnk = crycomposite_query(pMyExtension, "foo");
IFooPtr pComposite = cryinterface_cast<IFoo>(pCompUnk); if (pComposite)
{
// it's safe to work with pComposite, a composite of pMyExtention exposed as "foo"
implementing IFoo
}
A call to crycomposite_query()
might return NULL if the specified composite has not yet been created.
To gather more information, the query can be rewritten as follows.
IMyExtensionPtr pMyExtension = ...; bool exposed = false;
ICryUnknownPtr pCompUnk = crycomposite_query(pMyExtension, "foo", &exposed); if (exposed)
{
if (pCompUnk)
Version 1.10
514
Lumberyard Developer Guide
Glue Code Macros
{
// "foo" exposed and created
IFooPtr pComposite = cryinterface_cast<IFoo>(pCompUnk);
if (pComposite)
{
// it's safe to work with pComposite, a composite of pMyExtention exposed as "foo"
implementing IFoo
}
}
else
{
// "foo" exposed but not yet created
}
} else
{
// "foo" not exposed by pMyExtension
}
As with interface casting composite, queries work on raw interface pointers. However, please consider
the guidelines described in the section Shared and raw interface pointers (p. 510) .
Declared in the following framework header file:
•
CryCommon/CryExtension/ICryUnknown.h
The following macros provide glue code to implement the base interfaces and services to support the framework in a thread-safe manner. You are strongly encouraged to use them when you implement an extension.
For examples of how these macros work together, see
Declared in the following framework header files:
•
CryCommon/CryExtension/Impl/ClassWeaver.h
•
CryCommon/CryExtension/CryGUID.h
Declares an interface and associated ID. Protects the interfaces from accidentally being deleted on client side. That is, it allows destruction only by using boost::shared_ptr<T>
. This macro is required once per interface declaration.
Parameters
iname
The (C++) name of the interface as declared.
iidHigh
The higher 64-bit part of the interface ID (GUID).
iidLow
The lower 64-bit part of the interface ID (GUID).
Version 1.10
515
Lumberyard Developer Guide
Glue Code Macros
Start marker of the interface list inside the extension class implementation. Required once per extension class declaration.
Marker to add interfaces inside the extension class declaration. It has to be declared in between
CRYINTERFACE_BEGIN()
and any of the
CRYINTERFACE_END*()
markers. Only declare the interfaces that the class directly inherits. If deriving from an existing extension class or classes, the inherited interfaces get added automatically. If an interface is declared multiple times, duplicates will be removed. It is not necessary to add
ICryUnknown
.
Warning
Other interfaces that are not declared will not be castable by using cryinterface_cast<T>()
.
Parameters
iname
The (C++) name of the interface to be added.
End marker of the interface list inside the extension class declaration. Use this if not inheriting from any already existing extension class. Required once per extension class declaration. Mutually exclusive with any of the other
CRYINTERFACE_END*()
markers.
End marker of the interface list inside the extension class declaration. Use this if inheriting from an already existing extension class. Required once per extension class declaration. Mutually exclusive with any of the other
CRYINTERFACE_END*()
markers.
Parameters
base
The (C++) name of the extension class from which derived.
End marker of the interface list inside the extension class declaration. Use this if inheriting from two already existing extension classes. Required once per extension class declaration. Mutually exclusive with any of the other
CRYINTERFACE_END*()
markers.
Parameters
base0
The (C++) name of the first extension class from which derived.
base1
The (C++) name of the second extension class from which derived.
Version 1.10
516
Lumberyard Developer Guide
Glue Code Macros
End marker of the interface list inside the extension class declaration. Use this if inheriting from three already existing extension classes. Required once per extension class declaration. Mutually exclusive with any of the other
CRYINTERFACE_END*()
markers.
Parameters
base0
The (C++) name of the first extension class from which derived.
base1
The (C++) name of the second extension class from which derived.
base2
The (C++) name of the 3rd extension class from which derived.
Convenience macro for the following code sequence (probably the most common extension case):
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(iname)
CRYINTERFACE_END()
Parameters
iname
The (C++) name of the interface to be added.
Start marker of the list of exposed composites.
Marker to add a member of the extension class to the list of exposed composites.
Parameters
member
The (C++) name of the extension class member variable to be exposed. It has to be of type boost::shared_ptr<T>
, where
T
inherits from
ICryUnknown
. This condition is enforced at compile time.
membername
The name (as C-style string) of the composite by which the composite can later be queried at runtime.
Version 1.10
517
Lumberyard Developer Guide
Glue Code Macros
End marker of the list of exposed composites. Use this if not inheriting from any extension class that also exposes composites. Mutually exclusive with any of the other
CRYCOMPOSITE_END*()
markers.
Parameters
implclassname
The (C++) name of the extension class to be implemented.
End marker of the list of exposed composites. Use this if inheriting from one extension class that also exposes composites. Queries will first search in the current class and then look into the base class to find a composite that matches the requested name specified in crycomposite_query()
. Mutually exclusive with any of the other
CRYCOMPOSITE_END*()
markers.
Parameters
implclassname base
The (C++) name of the extension class to be implemented.
The (C++) name of the extension class derived from.
End marker of the list of exposed composites. Use this if inheriting from two extension classes that also expose composites. Queries will first search in the current class and then look into the base classes to find a composite matching the requested name specified in crycomposite_query()
. Mutually exclusive with any of the other
CRYCOMPOSITE_END*()
markers.
Parameters
implclassname
The (C++) name of the extension class to be implemented.
base0
The (C++) name of the first extension class from which derived.
base1
The (C++) name of the second extension class which derived.
End marker of the list of exposed composites. Use this if inheriting from three extension classes that also expose composites. Queries will first search in the current class and then look into the base classes to
Version 1.10
518
Lumberyard Developer Guide
Glue Code Macros find a composite matching the requested name specified in crycomposite_query()
. Mutually exclusive with any of the other
CRYCOMPOSITE_END*()
markers.
Parameters
implclassname
The (C++) name of the extension class to be implemented.
base0
The (C++) name of the first extension class from which derived.
base1
The (C++) name of the second extension class from which derived.
base2
The (C++) name of the third extension class from which derived.
Generates code to support base interfaces and services for an extension class that can be instantiated an arbitrary number of times. Required once per extension class declaration. Mutually exclusive to
CRYGENERATE_SINGLETONCLASS().
Parameters
implclassname
The C++ class name of the extension.
cname
The extension class name with which it is registered in the registry.
cidHigh
The higher 64-bit part of the extension's class ID (GUID) with which it is registered in the registry.
cidLow
The lower 64-bit part of the extension's class ID (GUID) with which it is registered in the registry.
Generates code to support base interfaces and services for an extension class that can be instantiated only once (singleton). Required once per extension class declaration. Mutually exclusive with
CRYGENERATE_CLASS()
.
Parameters
implclassname
The C++ class name of the extension.
cname
The extension class name with which it is registered in the registry.
Version 1.10
519
Lumberyard Developer Guide
CryExtension Samples
cidHigh
The higher 64-bit part of the extension's class ID (GUID) with which it is registered in the registry.
cidLow
The lower 64-bit part of the extension's class ID (GUID) with which it is registered in the registry.
Registers the extension class in the system. Required once per extension class at file scope.
Parameters
implclassname
The C++ class name of the extension.
Parameters
Constructs a CryGUID. Useful when searching the registry for extensions by class ID.
high low
The higher 64-bit part of the GUID.
The lower 64-bit part of the GUID.
//////////////////////////////////////////////////////////////////////////
// source control interface struct ISourceControl : public ICryUnknown
{
CRYINTERFACE_DECLARE(ISourceControl, 0x399d8fc1d94044cc, 0xa70d2b4e58921453)
virtual void GetLatest(const char* filename) = 0;
virtual void Submit() = 0;
}; typedef cryshared_ptr<ISourceControl> ISourceControlPtr;
//////////////////////////////////////////////////////////////////////////
// concrete implementations of source control interface class CSourceControl_Perforce : public ISourceControl
{
Version 1.10
520
Lumberyard Developer Guide
Using Extensions
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(ISourceControl)
CRYINTERFACE_END()
CRYGENERATE_SINGLETONCLASS(CSourceControl_Perforce, "CSourceControl_Perforce",
0x7305bff20ee543e3, 0x820792c56e74ecda)
virtual void GetLatest(const char* filename) { ... };
virtual void Submit() { ... };
};
CRYREGISTER_CLASS(CSourceControl_Perforce) class CSourceControl_SourceSafe : public ISourceControl
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(ISourceControl)
CRYINTERFACE_END()
CRYGENERATE_SINGLETONCLASS(CSourceControl_SourceSafe, "CSourceControl_SourceSafe",
0x1df62628db9d4bb2, 0x8164e418dd5b6691)
virtual void GetLatest(const char* filename) { ... };
virtual void Submit() { ... };
};
CRYREGISTER_CLASS(CSourceControl_SourceSafe)
//////////////////////////////////////////////////////////////////////////
// using the interface (submitting changes) void Submit()
{
ICryFactoryRegistry* pReg = gEnv->pSystem->GetFactoryRegistry();
ICryFactory* pFactory = 0;
size_t numFactories = 1;
pReg->IterateFactories(cryiidof<ISourceControl>(), &pFactory, numFactories);
if (pFactory)
{
ISourceControlPtr pSrcCtrl = cryinterface_cast<ISourceControl>(pFactory-
>CreateClassInstance());
if (pSrcCtrl)
{
pSrcCtrl->Submit();
}
}
}
To work with a specific extension class, a client needs to know the extension's class name or class id and the interface(s) that the class supports. With this information, the class factory can be queried from the registry, an instance created and worked with as in the following example.
// IMyExtension.h
#include <CryExtension/ICryUnknown.h>
Version 1.10
521
Lumberyard Developer Guide
Using Extensions struct IMyExtension : public ICryUnknown
{
...
}; typedef boost::shared_ptr<IMyExtension> IMyExtensionPtr;
// in client code
#include <IMyExtension.h>
#include <CryExtension/CryCreateClassInstance.h>
IMyExtensionPtr pMyExtension;
#if 0
// create extension by class name if (CryCreateClassInstance("MyExtension", pMyExtension))
#else
// create extension by class id, guaranteed to create instance of same kind if (CryCreateClassInstance(MAKE_CRYGUID(0x68c7f0e0c36446fe, 0x82a3bc01b54dc7bf),
pMyExtension))
#endif
{
// it's safe to work with pMyExtension
}
// verbose version of client code above
#include <IMyExtension.h>
#include <CryExtension/ICryFactory.h>
#include <CryExtension/ICryFactoryRegistry.h>
ICryFactoryRegistry* pReg = ...;
#if 0
// search extension by class name
ICryFactory* pFactory = pReg->GetFactory("MyExtension");
#else
// search extension by class id, guaranteed to yield same factory as in search by class
name
ICryFactory* pFactory = pReg->GetFactory(MAKE_CRYGUID(0x68c7f0e0c36446fe,
0x82a3bc01b54dc7bf));
#endif if (pFactory) // see comment below
{
ICryUnknownPtr pUnk = pFactory->CreateClassInstance();
IMyExtensionPtr pMyExtension = cryinterface_cast<IMyExtension>(pUnk);
if (pMyExtension)
{
// it's safe to work with pMyExtension
}
}
As an optimization, you can enhance the if
check as follows.
if (pFactory && pFactory->ClassSupports(cryiidof<IMyExtension>()))
{
...
This version of the if
statement will check interface support before the extension class is instantiated.
This check prevents the unnecessary (and potentially expensive) construction and destruction of extensions that are incompatible with a given interface.
Version 1.10
522
Lumberyard Developer Guide
Implementing Extensions Using the Framework
To determine how many extension classes in the registry support a given interface, and to list them, clients can submit queries similar to the following.
// IMyExtension.h
#include <CryExtension/ICryUnknown.h> struct IMyExtension : public ICryUnknown
{
...
};
// in client code
#include <IMyExtension.h>
#include <CryExtension/ICryFactory.h>
#include <CryExtension/ICryFactoryRegistry.h>
ICryFactoryRegistry* pReg = ...; size_t numFactories = 0; pReg->IterateFactories(cryiidof<IMyExtension>(), 0, numFactories);
ICryFactory** pFactories = new ICryFactory*[numFactories]; pReg->IterateFactories(cryiidof<IMyExtension>(), pFactories, numFactories);
...
delete [] pFactories;
The following section explains in detail how to implement extensions in Lumberyard. It provides examples that use glue code and do not use glue code. The section also shows you how to utilize the framework in cases where
ICryUnknown
cannot be the base of the extension interface.
The public interface header that will be included by the client should look like the following.
// IMyExtension.h
#include <CryExtension/ICryUnknown.h> struct IMyExtension : public ICryUnknown
{
...
};
If you are using glue code, declare the implementation class of the extension in the header file as follows.
// MyExtension.h
#include <IMyExtension.h>
#include <CryExtension/Impl/ClassWeaver.h> class CMyExtension : public IMyExtension
{
...
Version 1.10
523
Lumberyard Developer Guide
Implementing Extensions Using the Framework
};
The first example shows a possible implementation of the
IMyExtension
class in the previous examples.
///////////////////////////////////////////
// public section
// IMyExtension.h
#include <CryExtension/ICryUnknown.h> struct IMyExtension : public ICryUnknown
{
CRYINTERFACE_DECLARE(IMyExtension, 0x4fb87a5f83f74323, 0xa7e42ca947c549d8)
virtual void CallMe() = 0;
}; typedef boost::shared_ptr<IMyExtension> IMyExtensionPtr;
///////////////////////////////////////////
// private section not visible to client
// MyExtension.h
#include <IMyExtension.h>
#include <CryExtension/Impl/ClassWeaver.h> class CMyExtension : public IMyExtension
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(IMyExtension)
CRYINTERFACE_END()
CRYGENERATE_CLASS(CMyExtension, "MyExtension", 0x68c7f0e0c36446fe, 0x82a3bc01b54dc7bf) public:
virtual void CallMe();
};
// MyExtension.cpp
#include "MyExtension.h"
CRYREGISTER_CLASS(CMyExtension)
CMyExtension::CMyExtension()
{
}
CMyExtension::~CMyExtension()
{
} void CMyExtension::CallMe()
{
printf("Inside CMyExtension::CallMe()...");
}
The following example shows how the extension class
MyExtension
can be customized and expanded to implement two more interfaces,
IFoo
and
IBar
.
///////////////////////////////////////////
// public section
Version 1.10
524
Lumberyard Developer Guide
Implementing Extensions Using the Framework
// IFoo.h
#include <CryExtension/ICryUnknown.h> struct IFoo : public ICryUnknown
{
CRYINTERFACE_DECLARE(IFoo, 0x7f073239d1e6433f, 0xb59c1b6ff5f68d79)
virtual void Foo() = 0;
};
// IBar.h
#include <CryExtension/ICryUnknown.h> struct IBar : public ICryUnknown
{
CRYINTERFACE_DECLARE(IBar, 0xa9361937f60d4054, 0xb716cb711970b5d1)
virtual void Bar() = 0;
};
///////////////////////////////////////////
// private section not visible to client
// MyExtensionCustomized.h
#include "MyExtension.h"
#include <IFoo.h>
#include <IBar.h>
#include <CryExtension/Impl/ClassWeaver.h> class CMyExtensionCustomized : public CMyExtension, public IFoo, public IBar
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(IFoo)
CRYINTERFACE_ADD(IBar)
CRYINTERFACE_ENDWITHBASE(CMyExtension)
CRYGENERATE_CLASS(CMyExtensionCustomized, "MyExtensionCustomized", 0x07bfa7c543a64f0c,
0x861e9fa3f7d7d264) public:
virtual void CallMe(); // chose to override MyExtension's impl
virtual void Foo();
virtual void Bar();
};
// MyExtensionCustomized.cpp
#include "MyExtensionCustomized.h"
CRYREGISTER_CLASS(CMyExtensionCustomized)
CMyExtensionCustomized::CMyExtensionCustomized()
{
}
CMyExtensionCustomized::~CMyExtensionCustomized()
{
} void CMyExtensionCustomized::CallMe()
{
printf("Inside CMyExtensionCustomized::CallMe()...");
} void CMyExtensionCustomized::Foo()
{
Version 1.10
525
Lumberyard Developer Guide
Implementing Extensions Using the Framework
printf("Inside CMyExtensionCustomized::Foo()...");
} void CMyExtensionCustomized::Bar()
{
printf("Inside CMyExtensionCustomized::Bar()...");
}
If for any reason using the glue code is neither desired nor applicable, extensions can be implemented as follows. It is recommended to implement
ICryUnknown
and
ICryFactory
such that their runtime cost
is equal to the one provided by the glue code. For more information, see ICryUnknown (p. 511) and
.
///////////////////////////////////////////
// public section
// INoMacros.h
#include <CryExtension/ICryUnknown.h> struct INoMacros : public ICryUnknown
{
// befriend cryiidof and boost::checked_delete
template <class T> friend const CryInterfaceID& InterfaceCastSemantics::cryiidof();
template <class T> friend void boost::checked_delete(T* x); protected:
virtual ~INoMacros() {} private:
// It's very important that this static function is implemented for each interface!
// Otherwise the consistency of cryinterface_cast<T>() is compromised because
// cryiidof<T>() = cryiidof<baseof<T>>() {baseof<T> = ICryUnknown in most cases}
static const CryInterfaceID& IID()
{
static const CryInterfaceID iid = {0xd0fda1427dee4cceull, 0x88ff91b6b7be2a1full};
return iid;
} public:
virtual void TellMeWhyIDontLikeMacros() = 0;
}; typedef boost::shared_ptr<INoMacros> INoMacrosPtr;
///////////////////////////////////////////
// private section not visible to client
// NoMacros.cpp
//
// This is just an exemplary implementation!
// For brevity the whole implementation is packed into this cpp file.
#include <INoMacros.h>
#include <CryExtension/ICryFactory.h>
#include <CryExtension/Impl/RegFactoryNode.h>
// implement factory first class CNoMacrosFactory : public ICryFactory
{
// ICryFactory public:
virtual const char* GetClassName() const
Version 1.10
526
Lumberyard Developer Guide
Implementing Extensions Using the Framework
{
return "NoMacros";
}
virtual const CryClassID& GetClassID() const
{
static const CryClassID cid = {0xa4550317690145c1ull, 0xa7eb5d85403dfad4ull};
return cid;
}
virtual bool ClassSupports(const CryInterfaceID& iid) const
{
return iid == cryiidof<ICryUnknown>() || iid == cryiidof<INoMacros>();
}
virtual void ClassSupports(const CryInterfaceID*& pIIDs, size_t& numIIDs) const
{
static const CryInterfaceID iids[2] = {cryiidof<ICryUnknown>(), cryiidof<INoMacros>()};
pIIDs = iids;
numIIDs = 2;
}
virtual ICryUnknownPtr CreateClassInstance() const; public:
static CNoMacrosFactory& Access()
{
return s_factory;
} private:
CNoMacrosFactory() {}
~CNoMacrosFactory() {} private:
static CNoMacrosFactory s_factory;
};
CNoMacrosFactory CNoMacrosFactory::s_factory;
// implement extension class class CNoMacros : public INoMacros
{
// ICryUnknown public:
virtual ICryFactory* GetFactory() const
{
return &CNoMacrosFactory::Access();
};
// befriend boost::checked_delete
// only needed to be able to create initial shared_ptr<CNoMacros>
// so we don't lose type info for debugging (i.e. inspecting shared_ptr)
template <class T> friend void boost::checked_delete(T* x); protected:
virtual void* QueryInterface(const CryInterfaceID& iid) const
{
if (iid == cryiidof<ICryUnknown>())
return (void*) (ICryUnknown*) this;
else if (iid == cryiidof<INoMacros>())
return (void*) (INoMacros*) this;
else
return 0;
}
virtual void* QueryComposite(const char* name) const
{
return 0;
}
Version 1.10
527
Lumberyard Developer Guide
Implementing Extensions Using the Framework
// INoMacros public:
virtual void TellMeWhyIDontLikeMacros()
{
printf("Woohoo, no macros...\n");
}
CNoMacros() {} protected:
virtual ~CNoMacros() {}
};
// implement factory's CreateClassInstance method now that extension class is fully visible
to compiler
ICryUnknownPtr CNoMacrosFactory::CreateClassInstance() const
{
boost::shared_ptr<CNoMacros> p(new CDontLikeMacros);
return
ICryUnknownPtr(*static_cast<boost::shared_ptr<ICryUnknown>*>(static_cast<void*>(&p)));
}
// register extension static SRegFactoryNode g_noMacrosFactory(&CNoMacrosFactory::Access());
The following example shows how to expose (inherited) composites. For brevity, the sample is not separated into files.
//////////////////////////////////////////////////////////////////////////
struct ITestExt1 : public ICryUnknown
{
CRYINTERFACE_DECLARE(ITestExt1, 0x9d9e0dcfa5764cb0, 0xa73701595f75bd32)
virtual void Call1() = 0;
};
typedef boost::shared_ptr<ITestExt1> ITestExt1Ptr;
class CTestExt1 : public ITestExt1
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(ITestExt1)
CRYINTERFACE_END()
CRYGENERATE_CLASS(CTestExt1, "TestExt1", 0x43b04e7cc1be45ca, 0x9df6ccb1c0dc1ad8)
public:
virtual void Call1();
};
CRYREGISTER_CLASS(CTestExt1)
CTestExt1::CTestExt1()
{
}
CTestExt1::~CTestExt1()
{
}
void CTestExt1::Call1()
Version 1.10
528
Lumberyard Developer Guide
Implementing Extensions Using the Framework
{
}
//////////////////////////////////////////////////////////////////////////
class CComposed : public ICryUnknown
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_END()
CRYCOMPOSITE_BEGIN()
CRYCOMPOSITE_ADD(m_pTestExt1, "Ext1")
CRYCOMPOSITE_END(CComposed)
CRYGENERATE_CLASS(CComposed, "Composed", 0x0439d74b8dcd4b7f, 0x9287dcdf7e26a3a5)
private:
ITestExt1Ptr m_pTestExt1;
};
CRYREGISTER_CLASS(CComposed)
CComposed::CComposed()
: m_pTestExt1()
{
CryCreateClassInstance("TestExt1", m_pTestExt1);
}
CComposed::~CComposed()
{
}
//////////////////////////////////////////////////////////////////////////
struct ITestExt2 : public ICryUnknown
{
CRYINTERFACE_DECLARE(ITestExt2, 0x8eb7a4b399874b9c, 0xb96bd6da7a8c72f9)
virtual void Call2() = 0;
};
DECLARE_BOOST_POINTERS(ITestExt2);
class CTestExt2 : public ITestExt2
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(ITestExt2)
CRYINTERFACE_END()
CRYGENERATE_CLASS(CTestExt2, "TestExt2", 0x25b3ebf8f1754b9a, 0xb5494e3da7cdd80f)
public:
virtual void Call2();
};
CRYREGISTER_CLASS(CTestExt2)
CTestExt2::CTestExt2()
{
}
CTestExt2::~CTestExt2()
{
}
void CTestExt2::Call2()
{
}
Version 1.10
529
Lumberyard Developer Guide
Implementing Extensions Using the Framework
//////////////////////////////////////////////////////////////////////////
class CMultiComposed : public CComposed
{
CRYCOMPOSITE_BEGIN()
CRYCOMPOSITE_ADD(m_pTestExt2, "Ext2")
CRYCOMPOSITE_ENDWITHBASE(CMultiComposed, CComposed)
CRYGENERATE_CLASS(CMultiComposed, "MultiComposed", 0x0419d74b8dcd4b7e,
0x9287dcdf7e26a3a6)
private:
ITestExt2Ptr m_pTestExt2;
};
CRYREGISTER_CLASS(CMultiComposed)
CMultiComposed::CMultiComposed()
: m_pTestExt2()
{
CryCreateClassInstance("TestExt2", m_pTestExt2);
}
CMultiComposed::~CMultiComposed()
{
}
...
//////////////////////////////////////////////////////////////////////////
// let's use it
ICryUnknownPtr p;
if (CryCreateClassInstance("MultiComposed", p))
{
ITestExt1Ptr p1 = cryinterface_cast<ITestExt1>(crycomposite_query(p, "Ext1"));
if (p1)
p1->Call1(); // calls CTestExt1::Call1()
ITestExt2Ptr p2 = cryinterface_cast<ITestExt2>(crycomposite_query(p, "Ext2"));
if (p2)
p2->Call2(); // calls CTestExt2::Call2()
}
There are cases where making
ICryUnknown
the base of your extension class is not possible. Some examples are legacy code bases that cannot be modified, third party code for which you do not have full source code access, or code whose modification is not practical. However, these code bases can provide useful functionality (for example, for video playback or flash playback) if you expose them as engine extensions. The following sample illustrates how an additional level of indirection can expose a third party API.
///////////////////////////////////////////
// public section
// IExposeThirdPartyAPI.h
#include <CryExtension/ICryUnknown.h>
#include <IThirdPartyAPI.h> struct IExposeThirdPartyAPI : public ICryUnknown
{
CRYINTERFACE_DECLARE(IExposeThirdPartyAPI, 0x804250bbaacf4a5f, 0x90ef0327bb7a0a7f)
Version 1.10
530
Lumberyard Developer Guide
Implementing Extensions Using the Framework
virtual IThirdPartyAPI* Create() = 0;
}; typedef boost::shared_ptr<IExposeThirdPartyAPI> IExposeThirdPartyAPIPtr;
///////////////////////////////////////////
// private section not visible to client
// Expose3rdPartyAPI.h
#include <IExposeThirdPartyAPI.h>
#include <CryExtension/Impl/ClassWeaver.h> class CExposeThirdPartyAPI : public IExposeThirdPartyAPI
{
CRYINTERFACE_BEGIN()
CRYINTERFACE_ADD(IExposeThirdPartyAPI)
CRYINTERFACE_END()
CRYGENERATE_CLASS(CExposeThirdPartyAPI, "ExposeThirdPartyAPI", 0xa93b970b2c434a21,
0x86acfe94d8dae547) public:
virtual IThirdPartyAPI* Create();
};
// ExposeThirdPartyAPI.cpp
#include "ExposeThirdPartyAPI.h"
#include "ThirdPartyAPI.h"
CRYREGISTER_CLASS(CExposeThirdPartyAPI)
CExposeThirdPartyAPI::CExposeThirdPartyAPI()
{
}
CExposeThirdPartyAPI::~CExposeThirdPartyAPI()
{
}
IThirdPartyAPI* CExposeThirdPartyAPI::Create()
{
return new CThirdPartyAPI; // CThirdPartyAPI implements IThirdPartyAPI
}
To enable easy inclusion and exclusion of extensions, Lumberyard provides a global "extension definition" header much like
CryCommon/ProjectDefines.h
that is automatically included in all modules by means of the platform.h
file. To wrap your extension implementation code, you include a
#define statement in the extension definition header. To exclude unused extension code from your build, you can also comment out extensions that you are not interested in. Interface headers are not affected by the
#if defined
statements, so the client code compiles as is with or without them.
///////////////////////////////////////////
// public section
// IMyExtension.h
#include <CryExtension/ICryUnknown.h> struct IMyExtension : public ICryUnknown
{
...
Version 1.10
531
Lumberyard Developer Guide
CryString
}; typedef boost::shared_ptr<IMyExtension> IMyExtensionPtr;
// ExtensionDefines.h
...
#define INCLUDE_MYEXTENSION
...
///////////////////////////////////////////
// private section not visible to client
// MyExtension.h
#if defined(INCLUDE_MYEXTENSION)
#include <IMyExtension.h>
#include <CryExtension/Impl/ClassWeaver.h> class CMyExtension : public IMyExtension
{
...
};
#endif // #if defined(INCLUDE_MYEXTENSION)
// MyExtension.cpp
#if defined(INCLUDE_MYEXTENSION)
#include "MyExtension.h"
CRYREGISTER_CLASS(CMyExtension)
...
#endif // #if defined(INCLUDE_MYEXTENSION)
Because extensions can be removed from a build, clients must write their code in a way that does not assume the availability of an extension. For more information, see
.
Lumberyard has a custom reference-counted string class
CryString
(declared in
CryString.h
) which is a replacement for
STL std::string
.
CryString
should always be preferred over std::string
. For convenience, string
is used as a typedef for
CryString
.
The following code shows good (efficient) and bad usage: const char *szKey= "Test"; map< string, int >::const_iterator iter = m_values.find( CONST_TEMP_STRING( szKey ) ); //
Good map< string, int >::const_iterator iter = m_values.find( szKey ); // Bad
By using the suggested method, you avoid the allocation, deallocation, and copying of a temporary string object, which is a common problem for most string classes. By using the macro
CONST_TEMP_STRING
, the string class uses the pointer directly without having to free data afterwards.
Version 1.10
532
Lumberyard Developer Guide
Further Usage Tips
• Do not use std::string
or std::wstring
. Instead, use only string
and wstring
, and never include the standard string header
<string>
.
• Use the c_str()
method to access the contents of the string.
• Because strings are reference-counted, never modify memory returned by the c_str()
method. Doing so could affect the wrong string instance.
• Do not pass strings via abstract interfaces; all interfaces should use const char*
in interface methods.
•
CryString
has a combined interface of std::string
and the MFC
CString
, so you can use both interface types for string operations.
• Avoid doing many string operations at runtime as they often cause memory reallocations.
• For fixed size strings (e.g. 256 chars), use
CryFixedStringT
, which should be preferred over static char arrays.
The
ICrySizer
interface can be implemented to record detailed information about the memory usage of a class.
Note
This information is also available in the Editor under
Engine Memory info
.
The following example shows how to use the
ICrySizer
interface.
void GetMemoryUsage( ICrySizer *pSizer )
{
{
SIZER_COMPONENT_NAME( pSizer, "Renderer (Aux Geometries)" );
pSizer->Add(*this);
}
pSizer->AddObject(<element_prow>,<element_count>);
pSizer->AddObject(<container>);
m_SubObject.GetMemoryUsage(pSizer);
}
The
CryCommon
serialization library has the following features:
• Separation of user serialization code from the actual storage format. This makes it possible to switch between XML, JSON, and binary formats without changing user code.
• Re-usage of the same serialization code for editing in the PropertyTree. You can write the serialization code once and use it to expose your structure in the editor as a parameters tree.
• Enables you to write serialization code in non-intrusive way (as global overloaded functions) without modifying serialized types.
• Makes it easy to change formats. For example, you can add, remove, or rename fields and still be able to load existing data.
Version 1.10
533
Lumberyard Developer Guide
Tutorial
The example starts with a data layout that uses standard types, enumerations, and containers. The example adds the
Serialize
method to structures with fixed signatures.
#include "Serialization/IArchive.h"
#include "Serialization/STL.h" enum AttachmentType
{
ATTACHMENT_SKIN,
ATTACHMENT_BONE
}; struct Attachment
{
string name;
AttachmentType type;
string model;
void Serialize(Serialization::IArchive& ar)
{
ar(name, "name", "Name");
ar(type, "type", "Type");
ar(model, "model", "Model");
}
}; struct Actor
{
string character;
float speed;
bool alive;
std::vector<Attachment> attachments;
Actor()
: speed(1.0f)
, alive(true)
{
}
void Serialize(Serialization::IArchive& ar)
{
ar(character, "character", "Character");
ar(speed, "speed", "Speed");
ar(alive, "alive", "Alive");
ar(attachments, "attachments", "Attachment");
}
};
// Implementation file:
#include "Serialization/Enum.h"
SERIALIZATION_ENUM_BEGIN(AttachmentType, "Attachment Type")
SERIALIZATION_ENUM(ATTACHMENT_BONE, "bone", "Bone")
SERIALIZATION_ENUM(ATTACHMENT_SKIN, "skin", "Skin")
SERIALIZATION_ENUM_END()
Why are two names needed?
The ar()
call takes two string arguments: one is called name
, and the second label
. The name
argument is used to store parameters persistently; for example, for JSON and XML. The label
parameter is used for the PropertyTree. The label
parameter is typically longer, more descriptive, contains white space, and may be easily changed without breaking compatibility with existing data. In contrast, name
is a C-style
Version 1.10
534
Lumberyard Developer Guide
Tutorial identifier. It is also convenient to have name
match the variable name so that developers can easily find the variable by looking at the data file.
Omitting the label
parameter (the equivalent of passing nullptr
) will hide the parameter in the
PropertyTree, but it will be still serialized and can be copied together with its parent by using copy-paste.
Note
The
SERIALIZATION_ENUM
macros should reside in the .cpp implementation file because they contain symbol definitions.
Serializing into or from a file
Now that the data has been defined, it is ready for serialization. To implement the serialization, you can use
Serialization::SaveJsonFile
, as in the following example.
#include <Serialization/IArchiveHost.h>
Actor actor;
Serialization::SaveJsonFile("filename.json", actor);
This will output content in the following format:
{
"character": "nanosuit.cdf",
"speed": 2.5,
"alive": true,
"attachments": [
{ "name": "attachment 1", "type": "bone", "model": "model1.cgf" },
{ "name": "attachment 2", "type": "skin", "model": "model2.cgf" }
]
}
The code for reading data is similar to that for serialization, except that it uses
Serialization::LoadJsonFile
.
#include <Serialization/IArchiveHost.h>
Actor actor;
Serialization::LoadJsonFile(actor, "filename.json");
The save and load functions used are wrappers around the
IArchiveHost
interface, an instance of which is located in gEnv->pSystem->GetArchiveHost()
. However, if you have direct access to the archive code
(for example, in
CrySystem
or
EditorCommon
), you can use the archive classes directly, as in the following example.
#include <Serialization/JSONOArchive.h>
#include <Serialization/JSONIArchive.h>
Serialization::JSONOArchive oa;
Actor actor; oa(actor); oa.save("filename.json");
// to get access to the data without saving: const char* jsonString = oa.c_str();
// and to load
Serialization::JSONIArchive ia;
Version 1.10
535
Lumberyard Developer Guide
Use Cases if (ia.load("filename.json"))
{
Actor loadedActor;
ia(loadedActor);
}
If you have the
Serialize
method implemented for your types, it is easy to get it exposed to the
QPropertyTree
, as the following example shows.
#include <QPropertyTree/QPropertyTree.h>
QPropertyTree* tree = new QPropertyTree(parent);
static Actor actor; tree->attach(Serialization::SStruct(actor));
You can select enumeration values from the list and add or remove vector elements by using the [ 2 ] button or the context menu.
In the moment of attachment, the
Serialize
method will be called to extract properties from your object. As soon as the user changes a property in the UI, the
Serialize
method is called to write properties back to the object.
Note
It is important to remember that
QPropertyTree
holds a reference to an attached object. If the object's lifetime is shorter than the tree, an explicit call to
QPropertyTree::detach()
should be performed.
Normally when struct
or a class instance is passed to the archive, the
Serialize
method of the instance is called. However, it is possible to override this behavior by declaring the following global function: bool Serialize(Serialization::IArchive&, Type& value, const char* name, const char* label);
The return value here has the same behavior as
IArchive::operator().
For input archives, the function returns false when a field is missing or wasn't read. For output archives, it always returns true.
Version 1.10
536
Lumberyard Developer Guide
Use Cases
Note
The return value does not propagate up. If one of the nested fields is missing, the top level block will still return true.
The global function approach is useful when you want to:
• Add serialization in non-intrusive way
• Transform data during serialization
• Add support for unsupported types like plain pointers
The following example adds support for std::pair<>
type to the
Serialize
function: template<class T1, class T2> struct pair_serializable : std::pair<T1, T2>
{
void Serialize(Serialization::IArchive& ar)
{
ar(first, "first", "First");
ar(second, "second", "Second");
}
} template<class T1, class T2> bool Serialize(Serialization::IArchive& ar, std::pair<T1, T2>& value, const char* name,
const char* label)
{
return ar(static_cast<pair_serializable<T1, T2>&>(value), name, label);
}
The benefit of using inheritance is that you can get access to protected fields. In cases when access policy is not important and inheritance is undesirable, you can replace the previous code with following pattern.
template<class T1, class T2> struct pair_serializable
{
std::pair<T1, T2>& instance;
pair_serializable(std::pair<T1, T2>& instance) : instance(instance) {}
void Serialize(Serialization::IArchive& ar)
{
ar(instance.first, "first", "First");
ar(instance.second, "second", "Second");
}
} template<class T1, class T2> bool Serialize(Serialization::IArchive& ar, std::pair<T1, T2>& value, const char* name,
const char* label)
{
pair_serializable<T1, T2> serializer(value);
return ar(serializer, name, label);
}
Normally,
SERIALIZATION_ENUM_BEGIN()
will not compile if you specify enumeration within a class
(a "nested enum
"). To overcome this shortcoming, use
SERIALIZATION_ENUM_BEGIN_NESTED
, as in the following example.
Version 1.10
537
Lumberyard Developer Guide
Use Cases
SERIALIZATION_ENUM_BEGIN_NESTED(Class, Enum, "Label")
SERIALIZATION_ENUM(Class::ENUM_VALUE1, "value1", "Value 1")
SERIALIZATION_ENUM(Class::ENUM_VALUE2, "value2", "Value 2")
SERIALIZATION_ENUM_END()
The Serialization library supports the loading and saving of polymorphic types. This is implemented through serialization of a smart pointer to the base type.
For example, if you have following hierarchy:
IBase
• ImplementationA
• ImplementationB
You would need to register derived types with a macro, as in the following example.
SERIALIZATION_CLASS_NAME(IBase, ImplementationA, "impl_a", "Implementation A");
SERIALIZATION_CLASS_NAME(IBase, ImplementationA, "impl_b", "Implementation B");
Now you can serialize a pointer to the base type:
#include <Serialization/SmartPtr.h>
_smart_ptr<IInterfface> pointer; ar(pointer, "pointer", "Pointer");
The first string is used to name the type for persistent storage, and the second string is a humanreadable name for display in the PropertyTree.
There are two aspects that can be customized within the PropertyTree:
1. The layout of the property fields. These are controlled by control sequences in the label (the third argument in
IArchive::operator()
).
2. Decorators. These are defined in the same way that specific properties are edited or represented.
Control characters
Control sequences are added as a prefix to the third argument for
IArchive::operator()
. These characters control the layout of the property field in the PropertyTree.
Layout Control Characters
!
Prefix Role
Read-only field
Description
Prevents the user from changing the value of the property.
The effect is non-recursive.
Version 1.10
538
Lumberyard Developer Guide
Use Cases
^^
<
>
>
N
>
+
Prefix
^
[
S
]
Role
Apply
S
control characters to children.
Description
Inline Places the property on the same line as the name of the structure root. Can be used to put fields in one line in a horizontal layout, rather than in the default vertical list.
Inline in front of a name
Places the property name before the name of the parent structure. Useful to add check boxes before a name.
Expand value field Expand the value part of the property to occupy all available space.
Contract value field
Limit field width to
N
pixels
Expand row by default.
Reduces the width of the value field to the minimum. Useful to restrict the width of inline fields.
Useful for finer control over the UI. Not recommended for use outside of the editor.
Can be used to control which structures or containers are expanded by default. Use this only when you need per-item control. Otherwise,
QPropertyTree::setExpandLevels
is a better option.
Applies control characters to child properties. Especially useful with containers.
Combining control characters
Multiple control characters can be put together to combine their effects, as in the following example.
ar(name, "name", "^!<Name"); // inline, read-only, expanded value field
Decorators
There are two kinds of decorators:
1. Wrappers that implement a custom serialization function that performs a transformation on the original value. For example,
Serialization/Math.h
contains
Serialization::RadiansAsDeg(float&) that allows to store and edit angles in radians.
2. Wrappers that do no transformation but whose type is used to select a custom property implementation in the PropertyTree. Resource Selectors are examples of this kind of wrapper.
Decorator
AnimationPath
Purpose
Selection UI for full animation path.
Version 1.10
539
Defined for types
Any string-like type, like: std::string
, string (CryStringT)
,
SCRCRef
CCryName
Context needed
Lumberyard Developer Guide
Use Cases
Decorator
CharacterPath
CharacterPhysicsPath
CharacterRigPath
SkeletonPath
JointName
AttachmentName
SoundName
ParticleName
Purpose
UI: browse for character path (cdf)
UI: browse for character .phys-file.
UI: browse for .rig files.
UI: browse for .chr
or .skel files.
Defined for types
UI: list of character joints
UI: list of character attachments
UI: list of sounds
UI: particle effect selection
ICharacterInstance*
ICharacterInstance*
Serialization/
Decorators/Math.h
RadiansAsDeg
Edit or store radians as degrees float, Vec3
Serialization/
Decorators/Range.h
Range
Sets soft or hard limits for numeric values and provides a slider UI.
Numeric types
Serialization/
Callback.h
Callback
Provides per-property callback function. See
All types apart from compound ones (structs and containers)
Context needed
Decorator example
The following example uses the
Range
and
CharacterPath
decorators.
float scalar; ar(Serialization::Range(scalar), 0.0f, 1.0f); // provides slider-UI string filename; ar(Serialization::CharacterPath(filename), "character", "Character"); // provides UI for
file selection with character filter
Version 1.10
540
Lumberyard Developer Guide
Use Cases
The signature of the
Serialize
method is fixed. This can prevent the passing of additional arguments into nested
Serialize
methods. To resolve this issue, you can use a serialization context to pass a pointer of a specific type to nested
Serialize
calls, as in the following example.
void Scene::Serialize(Serialization::IArchive& ar)
{
Serialization::SContext sceneContext(ar, this);
ar(rootNode, "rootNode")
} void Node::Serialize(Serialization::IArchive& ar)
{
if (Scene* scene = ar.FindContext<Scene>())
{
// use scene
}
}
Contexts are organized into linked lists. Nodes are stored on the stack within the
SContext
instance.
You can have multiple contexts. If you provide multiple instances of the same type, the innermost context will be retrieved.
You may also use contexts with the PropertyTree without modifying existing serialization code. The easiest way to do this is to use
CContextList
(
QPropertyTree/ContextList.h
), as in the following example.
// CContextList m_contextList; tree = new QPropertyTree(); m_contextList.Update<Scene>(m_scenePointer); tree->setArchiveContext(m_contextList.Tail()); tree->attach(Serialization::SStruct(node));
It is possible to treat a block of data in the archive in an opaque way. This capability enables the Editor to work with data formats it has no knowledge of.
These data blocks can be stored within
Serialization::SBlackBox
.
SBlackBox
can be serialized or deserialized as any other value. However, when you deserialize
SBlackBox
from a particular kind of archive, you must serialize by using a corresponding archive. For example, if you obtained your
SBlackBox from
JSONIArchive
, you must save it by using
JSONOArchive
.
When you change a single property within the property tree, the whole attached object gets deserialized. This means that all properties are updated even if only one was changed. This approach may seem wasteful, but has the following advantages:
• It removes the need to track the lifetime of nested properties, and the requirement that nested types be referenced from outside in safe manner.
• The content of the property tree is not static data, but rather the result of the function invocation. This allows the content to be completely dynamic. Because you do not have to track property lifetimes, you can serialize and de-serialize variables constructed on the stack.
• The removal of the tracking requirement results in a smaller amount of code.
Version 1.10
541
Lumberyard Developer Guide
Use Cases
Nevertheless, there are situations when it is desirable to know exactly which property changes. You can achieve this in two ways: 1) by using the
Serialize
method, or 2) by using
Serialization::Callback
.
1. Using the
Serialize
method, compare the new value with the previous value, as in the following example.
void Type::Serialize(IArchive& ar)
{
float oldValue = value;
ar(value, "value", "Value");
if (ar.IsInput() && oldValue != value)
{
// handle change
}
}
2. The second option is to use the
Serialization::Callback
decorator to add a callback function for one or more properties, as the following example illustrates.
#include <Serialization/Callback.h> using Serialization::Callback;
ar(Callback(value,
[](float newValue) { /* handle change */ }),
"value", "Value");
Note
Callback
works only with the PropertyTree, and should be used only in Editor code.
Callback
can also be used together with other decorators, but in rather clumsy way, as the following example shows.
ar(Callback(value,
[](float newValue) { /* handle change*/ },
[](float& v) { return Range(v, 0.0f, 1.0f); }),
"value", "Value");
Of the two approaches, the callback approach is more flexible, but it requires you to carefully track the lifetime of the objects that are used by the callback lambda or function.
If your code base still uses MFC, you can use the PropertyTree with it by using a wrapper that makes this possible, as the following example shows.
#include <IPropertyTree.h> // located in Editor/Include
int CMyWindow::OnCreate(LPCREATESTRUCT pCreateStruct)
{
...
CRect clientRect;
GetClientRect(clientRect);
IPropertyTree* pPropertyTree = CreatePropertyTree(this, clientRect);
...
}
The
IPropertyTree
interface exposes the methods of
QPropertyTree
like
Attach
,
Detach
and
SetExpandLevels
.
Version 1.10
542
Lumberyard Developer Guide
Use Cases
QPropertyTree
provides a way to add short documentation in the form of tool tips and basic validation.
The
Doc
method allows you to add tool tips to
QPropertyTree
, as in the following examples.
void IArchive::Doc(const char*) void SProjectileParameter::Serialize(IArchive& ar)
{
ar.Doc("Defines projectile physics.");
ar(m_velocity, "velocity", "Velocity");
ar.Doc("Defines initial velocity of the projectile.");
}
The
Doc
method adds a tool tip to last serialized element. When used at the beginning of the function, it adds the tool tip to the whole block.
The
Warning
and
Error
calls allow you to display warnings and error messages associated with specific property within the property tree, as in the following examples.
template<class T> void IArchive::Warning(T& instance, const char* format, ...) template<class T> void IArchive::Error(T& instance, const char* format, ...) void BlendSpace::Serialize(IArchive& ar)
{
ar(m_dimensions, "dimensions, "Dimensions");
if (m_dimensions.empty())
ar.Error(m_dimensions, "At least one dimension is required for BlendSpace");
}
The error message appears as follows.
Warning messages look like this:
If you want to specify an enumeration value, you can use the enum
registration macro as described in the
section.
There are two ways to define a drop-down menu: 1) transform your data into
Serialization::StringListValue
, or 2) implement a custom PropertyRow in the UI.
A short example of the first approach follows. The example uses a custom reference.
Version 1.10
543
Lumberyard Developer Guide
Use Cases
// a little decorator that would annotate string as a special reference struct MyReference
{
string& str;
MyReference(string& str) : str(str) {}
}; inline bool Serialize(Serialization::IArchive& ar, MyReference& wrapper, const char* name,
const char* label)
{
if (ar.IsEdit())
{
Serialization::StringList items;
items.push_back("");
items.push_back("Item 1");
items.push_back("Item 2");
items.push_back("Item 3");
Serialization::StringListValue dropDown(items, wrapper.str.c_str());
if (!ar(dropDown, name, label))
return false;
if (ar.IsInput())
wrapper.str = dropDown.c_str();
return true;
}
else
{
// when loading from disk we are interested only in the string
return ar(wrapper.str, name, label);
}
}
Now you can construct
MyReference
on the stack within the
Serialize
method to serialize a string as a dropdown item, as in the following example.
struct SType
{
string m_reference;
void SType::Serialize(Serialization::IArchive& ar)
{
ar(MyReference(m_reference), "reference", "Reference");
}
};
The second way to define a drop-down menu requires that you implement a custom PropertyRow in the
UI. This takes more effort, but makes it possible to create the list of possible items entirely within editor code.
Version 1.10
544
Lumberyard Developer Guide
Capturing Video and Audio
This section contains information on recording videos for benchmarking. Capturing audio and video is also discussed, using either the Perspective view of the Lumberyard Editor or in pure-game mode via the
Launcher.
Topics
•
Capturing Video and Audio (p. 545)
•
This tutorial explains how to set up Lumberyard editor (or game) to capture video. Lumberyard outputs video as single frames. If required, it can also output stereo or 5.1 surround sound audio in
.wav
file format. You can edit the output with commonly available video editing software.
Before you can start video and audio streams in preparation for capture, you must configure some settings that determine how the video will be captured. You configure these settings by using console commands. To save time, you can create configuration files that execute the necessary commands for you instead of typing the commands directly into the console. Example configuration files are presented later in this topic.
The next sections describe the settings and the console commands that configure them.
The height and width of the captured frames in the editor is normally set to the exact view size of your rendered perspective window. To resize the view size, re-scale the perspective window, or right click in the top right of the perspective viewport where the frame size is displayed.
You can also capture higher than rendered images from Lumberyard Editor and Launcher.
The console variables that are now used in conjunction with Capture Frames are:
• r_CustomResHeight=
N
- Specifies the desired frame height in
N
pixels.
• r_CustomResWidth=
M
- Specifies the desired frame width in
M
pixels.
Version 1.10
545
Lumberyard Developer Guide
Video Settings
• r_CustomResMaxSize=
P
- Specifies the maximum resolution at which the engine will render the frames in
P
pixels.
• r_CustomResPreview=
R
- Specifies whether or how the preview is displayed in the viewport. Possible values for
R
are:
1
2
r_CustomResPreview
0
Preview status
No preview
Scaled to match the size of the viewport
Cropped to the size of the viewport
When deciding the number of frames per second to specify, keep in mind the following:
• NTSC standard video is approximately 30 frames per second, which is a good compromise between quality and file size.
• High quality video can have up to 60 frames per second, but the difference in quality of the increased number of frames is barely noticeable and can take up a lot of file space.
• Video at less than 24 FPS (a cinema standard) will not look smooth.
To specify a fixed frame rate, use the command: t_fixedstep
N
N
specifies the time step. Time step is calculated by using the formula step = 1 second/
<number of frames>
A table of common time step values follows.
FPS
25 (PAL)
30
60
Time Step
0.04
0.033333333
0.0166666667
You can capture pictures in several different file formats. A good choice for average quality is the
.jpeg
file format. The
.tga
or
.bmp
file formats are better for higher quality, and
.hdr
for pictures that use high-dynamic-range imaging .
To specify the capture file format, use the console command capture_file_format
N
N
is jpg
, bmp
, tga
or hdr
.
Version 1.10
546
Lumberyard Developer Guide
Starting and Ending the Video Recording
By default, recorded frames are stored in the directory
<root>
\CaptureOutput
. To specify a custom directory, use the command: capture_folder
N
N
is the name of the custom directory.
Warning
When you start a recording, the captured frames are placed in the currently specified directory and will overwrite existing files with the same name. To avoid losing work, create a directory for each recording, or move the existing files to another directory before you start.
After you have specified the values mentioned in the previous sections, you can start the recording by using the command:
capture_frames
N
Setting
N
to
1
starts the recording, and setting
N
to
0
stops it.
Before you begin, decide if you require audio in stereo or in 5.1 surround format, and then change your audio settings accordingly in the Windows control panel.
After loading the level of your game that you want to capture, you must deactivate the sound system so that you can redirect the sound output to a file. To deactivate the sound system, use the command:
#Sound.DeactivateAudioDevice()
This redirects the sound output to a
.wav
file in the root directory of the game. The sound will not run in realtime, but be linked precisely to the time step that you set previously.
To write the sound capture, use the command: s_OutputConfig
N
Setting
N
to
3
activates the non-realtime writing of sound to the
.wav
file. Setting
N
to
0
specifies autodetection (the default).
To reset the sound system use the command:
#Sound.ActivateAudioDevice()
This creates a
.wav
file in the root directory of the game. The file will continue to be written to until you run the following combination of commands to deactivate the audio device:
Version 1.10
547
Lumberyard Developer Guide
Configuration Files
#Sound.DeactivateAudioDevice() s_OutputConfig 0
#Sound.ActivateAudioDevice()
Tip
Although these commands reset the sound system, some sounds won't start until they are correctly triggered again. This applies particularly to looped sounds. To get looped sounds to play, start the recording of video and sound first, and then enter any area that triggers the looped sounds that you want to record.
• To ensure that multiple recordings use exactly the same settings, create a configuration file that you can use for each of them. This will ensure that all of your captured files have the same format.
An example configuration file: sys_spec = 4
Fixed_time_step 0.0333333333
Capture_file_format jpg
Capture_folder myrecording r_width 1280 r_height 800
The command sys_spec = 4
sets the game graphic settings to "very high" to generate the best appearance.
• To speed up the process of starting and stopping the recording, you can create two configuration files: one to start the video, and one to stop it.
• To start recording, use a config file like the following:
#Sound.DeactivateAudioDevice() s_OutputConfig 3
#Sound.ActivateAudioDevice()
Capture_frames 1
• To stop recording, use a config file like the following:
Capture_frames 0
#Sound.DeactivateAudioDevice() s_OutputConfig 0
#Sound.ActivateAudioDevice()
Executing the Config Files
To run the config file, open the console and type the following command:
Exec
N
N
is the name of the config file.
Version 1.10
548
Lumberyard Developer Guide
Recording Time Demos
Lumberyard Editor can record and play back player input and camera movement.
Note
Recording of some player actions such as vehicle movement are not supported.
To use the feature, you must start game mode in Lumberyard Editor and then record in it. To start game mode, press
Ctrl+G
after a level has fully loaded, or load the level in pure-game mode.
Output like the following appears both in the console and in the timedemo.log
file in the directory corresponding to the level used:
TimeDemo Run 131 Finished.
Play Time: 3.96s, Average FPS: 50.48
Min FPS: 0.63 at frame 117, Max FPS: 69.84 at frame 189
Average Tri/Sec: 14037316, Tri/Frame: 278071
Recorded/Played Tris ratio: 0.99
Optional Title
Command
Start Recording
End Recording
Start Playback
Stop Playback
Keystroke
Ctrl + PrintScreen
Ctrl + Break
Shift + PrintScreen
Ctrl + Break
Console Commands
record stoprecording demo stopdemo
• stopdemo
– Stops playing a time demo.
• demo
demoname
– Plays the time demo from the specified file.
• demo_fixed_timestep
– Specifies the number of updates per second.
• demo_panoramic
– Uses a panoramic view when playing back the demo.
• demo_restart_level
N
– Restarts the level after each loop. Possible values for
N
: 0 = Off; 1 = use quicksave on first playback; 2 = load level start.
• demo_ai
– Enables or disables AI during the demo.
• demo_savestats
– Saves level stats at the end of the loop.
• demo_max_frames
– Specifies the maximum number of frames to save.
• demo_screenshot_frame
N
– Makes a screenshot of the specified frame during demo playback. If a negative value for
N
is supplied, takes a screenshot every
N
frame.
• demo_quit
– Quits the game after the demo run is finished.
• demo_noinfo
– Disables the information display during the demo playback.
• demo_scroll_pause
– Enables the use of the
ScrollLock
key to pause demo play and record.
Version 1.10
549
Lumberyard Developer Guide
Related Console Variables
• demo_num_runs
– Specifies the number of times to loop the demo.
• demo_profile
– Enables demo profiling.
• demo_file
– Specifies the time demo file name.
Version 1.10
550
Lumberyard Developer Guide
Entity Property Prefixes
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
This section covers topics related to the Entity system. Entities are objects, placed inside a level, that players can interact with.
This section includes the following topics:
•
Entity Property Prefixes (p. 551)
•
Creating a New Entity Class (p. 552)
•
•
•
Adding Usable Support on an Entity (p. 564)
•
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
The Lumberyard Editor supports typed properties where the type is derived from special prefixes in the property name. For a complete list of supported prefixes, refer to the s_paramTypes
array, defined in
Objects/EntityScript.cpp
. This array maps prefixes to variable types.
The following prefixes are supported by Lumberyard:
{ "n", IVariable::INT, IVariable::DT_SIMPLE, SCRIPTPARAM_POSITIVE },
{ "i", IVariable::INT, IVariable::DT_SIMPLE,0 },
{ "b", IVariable::BOOL, IVariable::DT_SIMPLE,0 },
{ "f", IVariable::FLOAT, IVariable::DT_SIMPLE,0 },
{ "s", IVariable::STRING, IVariable::DT_SIMPLE,0 },
{ "ei", IVariable::INT, IVariable::DT_UIENUM,0 },
{ "es", IVariable::STRING, IVariable::DT_UIENUM,0 },
{ "shader", IVariable::STRING, IVariable::DT_SHADER,0 },
Version 1.10
551
Lumberyard Developer Guide
Creating a New Entity Class
{ "clr", IVariable::VECTOR, IVariable::DT_COLOR,0 },
{ "color", IVariable::VECTOR, IVariable::DT_COLOR,0 },
{ "vector", IVariable::VECTOR, IVariable::DT_SIMPLE,0 },
{ "snd", IVariable::STRING, IVariable::DT_SOUND,0 },
{ "sound", IVariable::STRING, IVariable::DT_SOUND,0 },
{ "dialog", IVariable::STRING, IVariable::DT_DIALOG,0 },
{ "tex", IVariable::STRING, IVariable::DT_TEXTURE,0 },
{ "texture", IVariable::STRING, IVariable::DT_TEXTURE,0 },
{ "obj", IVariable::STRING, IVariable::DT_OBJECT,0 },
{ "object", IVariable::STRING, IVariable::DT_OBJECT,0 },
{ "file", IVariable::STRING, IVariable::DT_FILE,0 },
{ "aibehavior", IVariable::STRING, IVariable::DT_AI_BEHAVIOR,0 },
{ "aicharacter", IVariable::STRING, IVariable::DT_AI_CHARACTER,0 },
{ "aipfpropertieslist", IVariable::STRING, IVariable::DT_AI_PFPROPERTIESLIST,0 },
{ "aiterritory", IVariable::STRING, IVariable::DT_AITERRITORY,0 },
{ "aiwave", IVariable::STRING, IVariable::DT_AIWAVE,0 },
{ "text", IVariable::STRING, IVariable::DT_LOCAL_STRING,0 },
{ "equip", IVariable::STRING, IVariable::DT_EQUIP,0 },
{ "reverbpreset", IVariable::STRING, IVariable::DT_REVERBPRESET,0 },
{ "eaxpreset", IVariable::STRING, IVariable::DT_REVERBPRESET,0 },
{ "aianchor", IVariable::STRING, IVariable::DT_AI_ANCHOR,0 },
{ "soclass", IVariable::STRING, IVariable::DT_SOCLASS,0 },
{ "soclasses", IVariable::STRING, IVariable::DT_SOCLASSES,0 },
{ "sostate", IVariable::STRING, IVariable::DT_SOSTATE,0 },
{ "sostates", IVariable::STRING, IVariable::DT_SOSTATES,0 },
{ "sopattern", IVariable::STRING, IVariable::DT_SOSTATEPATTERN,0 },
{ "soaction", IVariable::STRING, IVariable::DT_SOACTION,0 },
{ "sohelper", IVariable::STRING, IVariable::DT_SOHELPER,0 },
{ "sonavhelper", IVariable::STRING, IVariable::DT_SONAVHELPER,0 },
{ "soanimhelper", IVariable::STRING, IVariable::DT_SOANIMHELPER,0 },
{ "soevent", IVariable::STRING, IVariable::DT_SOEVENT,0 },
{ "sotemplate", IVariable::STRING, IVariable::DT_SOTEMPLATE,0 },
{ "gametoken", IVariable::STRING, IVariable::DT_GAMETOKEN, 0 },
{ "seq_", IVariable::STRING, IVariable::DT_SEQUENCE, 0 },
{ "mission_", IVariable::STRING, IVariable::DT_MISSIONOBJ, 0 },
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
The following example creates an entity class called
Fan
.
• Create a new entity definition file with the extension ".ent", for example "
GameSDK\Entities\Fan.ent
".
This file will expose the entity to the engine.
<Entity
Name="Fan"
Script="Scripts/Entities/Fan.lua"
/>
Version 1.10
552
Lumberyard Developer Guide
Creating a New Entity Class
• Create a new Lua script file, for example
GameSDK\Entities\Scripts\Fan.lua
. The Lua file will define the entity logic.
Fan = {
type = "Fan", -- can be useful for scripting
-- instance member variables
minrotspeed = 0,
maxrotspeed = 1300,
acceleration = 300,
currrotspeed = 0,
changespeed = 0,
currangle = 0,
-- following entries become automatically exposed to the editor and serialized (load/ save)
-- type is defined by the prefix (for more prefix types, search for s_paramTypes in /
Editor/Objects/EntityScript.cpp)
Properties = {
bName = 0, -- boolean example, 0/1
fName = 1.2, -- float example
soundName = "", -- sound example
fileModelName = "Objects/box.cgf", -- file model
},
-- optional editor information
Editor = {
Model = "Editor/Objects/Particles.cgf", -- optional 3d object that represents this
object in editor
Icon = "Clouds.bmp", -- optional 2d icon that represents this
object in editor
},
}
-- optional. Called only once on loading a level.
-- Consider calling self:OnReset(not System.IsEditor()); here function Fan:OnInit()
self:SetName( "Fan" );
self:LoadObject( "Objects/Indoor/Fan.cgf", 0, 0 );
self:DrawObject( 0, 1 ); end
-- OnReset() is usually called only from the Editor, so we also need OnInit()
-- Note the parameter function Fan:OnReset(bGameStarts) end
-- optional. To start having this callback called, activate the entity:
-- self:Activate(1); -- Turn on OnUpdate() callback function Fan:OnUpdate(dt)
if ( self.changespeed == 0 ) then
self.currrotspeed = self.currrotspeed - System.GetFrameTime() * self.acceleration;
if ( self.currrotspeed < self.minrotspeed ) then
self.currrotspeed = self.minrotspeed;
end
else
self.currrotspeed = self.currrotspeed + System.GetFrameTime() * self.acceleration;
if ( self.currrotspeed > self.maxrotspeed ) then
self.currrotspeed = self.maxrotspeed;
end
end
self.currangle = self.currangle + System.GetFrameTime() * self.currrotspeed;
local a = { x=0, y=0, z=-self.currangle };
self:SetAngles( a ); end
Version 1.10
553
Lumberyard Developer Guide
Entity Pool System
-- optional serialization function Fan:OnSave(tbl)
tbl.currangle = self.currangle; end
-- optional serialization function Fan:OnLoad(tbl)
self.currangle = tbl.currangle; end
-- optional function Fan:OnSpawn() end
-- optional function Fan:OnDestroy() end
-- optional function Fan:OnShutDown() end
-- optional function Fan:OnActivate()
self.changespeed = 1 - self.changespeed; end
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
The topics in this section describe the entity pool system, including how it is implemented, how to register a new entity class to be pooled, and how to debug it. For more information on using entity pools in the Lumberyard Editor, see the Lumberyard User Guide.
This section includes the following topics:
•
Entity Pool Definitions (p. 555)
•
•
Creating and Destroying Static Entities with Pools (p. 558)
•
Creating and Destroying Dynamic Entities with Pools (p. 560)
•
•
Listener/Event Registration (p. 562)
•
The following processes must take place when creating an entity pool and preparing it for use. Each of these processes is described in more detail.
1. An entity pool is created by using the information in an entity pool definition.
2. An entity pool is populated with entity containers.
3. An entity pool is validated by testing the entity pool signature of one of the entity containers against the entity pool signature of each
Entity
class mapped to the pool.
Version 1.10
554
Lumberyard Developer Guide
Editor Usage
4. All entities marked to be created through the pool have an entity pool bookmark created for them.
5. An entity pool bookmark is prepared from or returned to the entity pool, which is mapped to its
Entity
class on demand.
When running in the Lumberyard Editor, the entity pool system is not fully enabled. All entities are created outside the pools when playing in-game in the Editor. However, all flow node actions with entity pools will still work in the Lumberyard Editor, mimicking the final results that you will see in-game.
Note
The entity pool listeners
OnEntityPreparedFromPool
and
OnEntityReturnedToPool
are still called in the Editor, even though the entity itself is not removed/reused.
Entities can be either static or dynamic. A static entity is placed in the Editor and exported with the level.
This entity always exists. A property associated with the exported information determines whether it should be pooled (and not created during level load) or instead have an entity pool bookmark made for it. A dynamic entity is created at run-time, usually from game code. The information is constructed at run-time, usually just before it is created, and passed on to the Entity system for handling. This information also indicates whether or not it should go through an entity pool.
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
Entity pools must be defined in the file
\Game\Scripts\Entities\EntityPoolDefinitons.xml
. An entity pool definition is responsible for defining the following:
• the empty class that will be used by entity containers when they're not in use
• the entity classes mapped to the pool
• other properties that describe the pool and how it is used.
In general, a pool is initially filled with a defined number of entity containers; that is, empty
CEntity classes with all the required entity proxies and game object extensions that are normally created when an entity belonging to an entity class mapped to the definition is fully instantiated. For example, a normal AI entity will have the following entity proxies: sound extension, script extension, render extension, and the game object as its user extension; as its game object extension, it will have the
CPlayer
class. All of these classes are instantiated for each empty
CEntity
instance, and is reused by the entities as they are created from the pool.
The following illustrates an entity pool definition:
EntityPoolDefinitions.xml
<Definition name="AI" emptyClass="NullAI" maxSize="16" hasAI="1" defaultBookmarked="0"
forcedBookmarked="0">
<Contains>
<Class>Grunt</Class>
<Class>Flyer</Class>
</Contains>
Version 1.10
555
Lumberyard Developer Guide
Entity Pool Definitions
</Definition>
The empty class is defined using the emptyClass
attribute, which takes the name of a valid entity class.
The purpose of the empty class is to:
• satisfy the engine's requirement to have an entity class associated with an entity at all times; an empty container is initialized/reused to this entity class
• prepare all needed entity proxies and game object extensions needed for the entities
For example, building on the definition shown in the previous section, you would create an empty class called "NullAI" and register it the same way as the other AI classes above. Then:
1. Declare the entity class and map it to its Lua script via the game factory.
GameFactory.cpp
REGISTER_FACTORY(pFramework, "NullAI", CPlayer, true);
2. Create the Lua script for it. View sample code at
\Game\Scripts\Entities\AI\NullAI.lua
.
These steps will allow Lumberyard to see "NullAI" as a valid entity class. In addition, by mapping
CPlayer to it, you ensure that the correct game object extension is instantiated for the entity containers. The
Lua script needs to create all the entity proxies for the entity containers. In the sample code, a render proxy is created, even though we aren't loading an asset model for this entity. For more details, see the
discussion of entity pool signatures in Entity Pool Creation (p. 557)
.
In an entity pool definition file, the
<Contains>
section should include maps to all the entity classes that an entity must belong to when it is created through this pool. You can map as many as you want by adding a new
<Class>
node within this section. It is important that each entity have the same dynamic
class hierarchy as the empty class when fully instantiated. See Debugging Utilities (p. 563)
for useful debugging tools to verify that this is the case.
An entity pool definition can define the following additional properties.
name
Unique identity given to an entity pool, useful for debugging purposes. The name should be unique across all definitions.
maxSize
Largest pool size this pool can reach. By default, this is also the number of entity containers created to fill the pool when loading a level. This value can be overwritten for a level by including an
EntityPools.xml
file inside the level's root directory. This file can only be used to decrease the number of entity containers created per pool; it cannot exceed the maxSize
value defined here. This is useful when you need to reduce the memory footprint of the entity pools per level. The following example file adjusts the size of an AI entity pool to "2".
LevelEntityPools.xml
<EntityPools>
Version 1.10
556
Lumberyard Developer Guide
Entity Pool Creation
<AI count="2" />
</EntityPools>
hasAI
Boolean value that indicates whether or not the entity pool will contain entities that have AI associated with them. It is important to set this property to TRUE if you are pooling entities with AI.
defaultBookmarked
Boolean value that indicates whether or not an entity belonging to one of the entity classes mapped to this pool is flagged as "created through pool" (see
Creating and Destroying Static Entities with
created for the entity instead of being instantiated.
forcedBookmarked
Boolean value that indicates whether or not an entity belonging to one of the entity classes mapped to this pool must be created through the pool. This property overrides an entity's "created through pool" flag (see
Creating and Destroying Static Entities with Pools (p. 558)
).
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
When loading a level, an entity pool is created for each entity pool definition. On creation, the pool is filled with empty containers (instances of
CEntity
using the emptyClass
attribute value as the entity class. These empty containers come with some expectations that must be satisfied:
• Containers should be minimal in size. This means you should not load any assets or large amounts of data into them. For example, in the sample Lua script (
\Game\Scripts\Entities\AI\NullAI.lua
), the
NullAI entity does not define a character model, animation graph, body damage definition, etc.
• Containers should have the same entity proxies and game object extensions created for them as compared to a
CEntity
fully instantiated using each of the mapped entity classes.
Once the pool is created, an entity pool signature is generated using one of the empty containers. An entity pool's signature is a simple container that maps the dynamic class hierarchy of an entity.
One of the functions of the entity pool system is to avoid as much as possible dynamic allocation for delegate classes used by entities. Key examples of these are the entity proxies and game object extensions used by entities. When an entity pool's empty containers are first created, the delegate classes that will be used by the real entities contained in them are also supposed to be created. To ensure that this is the case, the entity pool signature is used. It works as follows:
1. A
TSerialize
writer is created. It is passed to each entity proxy and game object extension that exists in the entity.
2. Each proxy and extension is expected to write some info to the
TSerialize
writer. This information should be unique.
3. Two signatures can then be compared to see if they contain the same written information, verifying they contain the same dynamic class hierarchy.
All of the entity proxies have already been set up to write their information to the
TSerialize
writer.
However, if you create a new game object extension (or a new entity proxy), then you will need to set
Version 1.10
557
Lumberyard Developer Guide
Creating and Destroying Static Entities with Pools the class up to respond to the Signature helper when needed. To do this, implement the virtual method
(Entity Proxy:
GetSignature
; Game Object Extension:
GetEntityPoolSignature
) and write information about the class to the
TSerialize
writer. Generally, all that is needed is to just begin/end a group with the class name. The function should then return TRUE to mark that the signature is valid thus far.
CActor::GetEntityPoolSignature Example
bool CActor::GetEntityPoolSignature( TSerialize signature )
{
signature.BeginGroup("Actor");
signature.EndGroup();
return true;
}
The section Debugging Utilities (p. 563)
discusses how to view the results of entity pool signature tests in order to verify that everything is working as expected.
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
This topic covers issues related to handling static entities.
When an entity is marked to be created through the pool, it is not instantiated during the level load process. Instead, an entity pool bookmark is generated for it. The bookmark contains several items:
• Entity ID reserved for the entity, assigned when the level was exported. You will use this entity ID later to tell the system to create the entity.
• Static instanced data that makes the entity unique. This includes the
<EntityInfo>
section from the mission.xml
file, which contains area information, flow graph information, child/parent links,
PropertiesInstance table, etc.
• Serialized state of the entity if it has been returned to the pool in the past. See more details in
In each entity's
<EntityInfo>
section in the mission.xml
file (generated when the level is exported from the Editor), there's a
CreatedThroughPool
property. This property can be referenced from the
SEntitySpawnParams
struct. If set to TRUE, the
EntityLoadManager
module will
not
create a
CEntity instance for the entity. Instead, it will delegate the static instanced data and reserved entity ID to the
EntityPoolManager
to create a bookmark.
CEntityLoadManager::ParseEntities
SEntityLoadParams loadParams; if (ExtractEntityLoadParams(entityNode, loadParams))
{
if (bEnablePoolUse && loadParams.spawnParams.bCreatedThroughPool)
{
CEntityPoolManager *pPoolManager = m_pEntitySystem->GetEntityPoolManager();
bSuccess = (pPoolManager && pPoolManager->AddPoolBookmark(loadParams));
}
Version 1.10
558
Lumberyard Developer Guide
Creating and Destroying Static Entities with Pools
// Default to creating the entity
if (!bSuccess)
{
EntityId usingId = 0;
bSuccess = CreateEntity(loadParams, usingId);
}
}
To prepare a static entity, call
IEntityPoolManager::PrepareFromPool
, passing in the entity ID associated with the static entity you want to create. In response, the following execution flow takes place:
1. System determines if the request can be processed in this frame. It will attempt to queue up multiple requests per frame and spread them out. If the parameter bPrepareNow
is set to TRUE or if no prepare requests have been handled this frame, the request will be handled immediately. Otherwise, it will be added to the queue. Inside
CEntityPoolManager::LoadBookmarkedFromPool
, the EntityLoadManager is requested to create the entity.
Note
Note: If this activity is happening in the Editor, the entity will simply have its Enable event called. This will mimic enabling the entity via Flow Graph (unhide it). In this situation, the execution flow skips to the final step.
2. System searches for an entity container (either empty, or still in use) to hold the requested entity.
The function
CEntityPoolManager::GetPoolEntity
looks through the active entity pools to find one that contains the entity class of the given static entity. Once the correct pool is found, the container is retrieved from it. The actual order is as follows: a. If a forcedPoolId
(entity ID of one of the empty containers created to populate the pool) is requested, find that entity container and return it.
b. If no forcedPoolId
is requested, get an entity container from the inactive set (entity containers not currently in use).
c. If no inactive containers are available, get one from the active set (entity containers currently in use). This action uses a "weight" value to determine which container to return.
A special Lua function in the script is used to request weights for each empty container
(
CEntityPoolManager::GetReturnToPoolWeight
). A negative weight means it should not be used at all if possible. The system might pass in an urgent flag, which means the pool is at its maximum size.
d. If an empty container can still not be found, an urgent flag will be ignored and the system will try to grow the pool. This is only possible if the pool was not created at its maximum size (this happens when the maximum pool size is overridden for a level with a smaller maximum size). In this case, a new entity container is generated, added to the pool, and immediately used.
3. The retrieved entity container, along with the static instanced data and reserved entity ID gathered from its bookmark, is passed on through the function
CEntityLoadManager::CreateEntity
, which begins the Reload process.
CreateEntity
uses the provided entity container instead of creating a new
CEntity
instance. It will handle calling the Reload pipeline on the entity container, and then install all the static instanced data for the prepared static entity. The Reload pipeline is as follows: a. The function
CEntity::ReloadEntity
is called on the entity container. The
CEntity
instance will clean itself up internally and begin using the static instanced data of the entity being prepared. The
Lua script also performs cleanup using the function
OnBeingReused
.
b. The Entity system's salt buffer and other internal containers are updated to reflect that this entity container now holds the reserved entity ID and can be retrieved using it.
c. Entity proxies are prompted to reload using the static instanced data provided. This is done by calling
IEntityProxy::Reload
; each proxy is expected to correctly reset itself with the new data provided. The Script proxy is always the first to be reloaded so that the Lua script can be correctly associated before the other proxies attempt to use it.
Version 1.10
559
Lumberyard Developer Guide
Creating and Destroying Dynamic Entities with Pools
If the game object is being used as the User proxy, all the game object extensions for the container are also prompted to reload. This is done by calling
IGameObjectExtension::ReloadExtension on all extensions. If this function returns FALSE, the extension will be deleted. Once this is done,
IGameObjectExtension::PostReloadExtension
is called on all extensions. This behavior mimics the Init and PostInit logic. Each extension is expected to correctly reset itself with the new data provided.
4. If any serialized data exists within the bookmark, the entity container is loaded with that data. This ensures that the static entity resumes the state it was in last time it was returned to the pool. This process is skipped if this is the first time the static entity is being prepared.
At this point, calling
CEntity::GetEntity
or
CEntity::FindEntityByName
will return the entity container that is now housing the static entity and its information.
To return a static entity, call the function
IEntityPoolManager::ReturnToPool
. You must pass in the entity ID associated with the static entity. In response, the following execution flow takes place:
1. The function
CEntityPoolManager::ReturnToPool
finds the bookmark and the entity pool containing the current entity container housing the static entity.
2. Depending on the bSaveState
argument, the
CEntity
instance is (saved) and its serialized information is added to the bookmark. This ensures that if the static entity is prepared again later, it will resume its current state.
3. The entity container goes through the Reload process again. This time, however, the entity container is reloaded using its empty class, effectively removing all references to loaded assets/content and put it back into a minimal state.
At this point, calling
CEntity::GetEntity
or
CEntity::FindEntityByName
to find the static entity will return NULL.
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
The processes for creating and destroying dynamic entities are similar to those for static entities, which one key exception: dynamic entities have no entity pool bookmarks (at least initially). Because they are not exported in the level, they have no static instanced data associated with them and so no bookmark is made for them.
As with static entities, creating a dynamic entity with the pool starts with calling
IEntitySystem::SpawnEntity
. Construct an
SEntitySpawnParams
instance to describe its static instanced data. When filling in this struct, set the bCreatedThroughPool
property to TRUE if you wish to have the entity be created through the pool. In the following example, a vehicle part from the Vehicle system is being spawned through the pool:
SEntitySpawnParams spawnParams; spawnParams.sName = pPartName spawnParams.pClass = gEnv->pEntitySystem->GetClassRegistry()-
>FindClass("VehiclePartDetached");
Version 1.10
560
Lumberyard Developer Guide
Serialization spawnParams.nFlags = ENTITY_FLAG_CLIENT_ONLY; spawnParams.bCreatedThroughPool = true;
IEntity* pSpawnedDebris = gEnv->pEntitySystem->SpawnEntity(spawnParams);
Once
SpawnEntity
, the following execution flow takes place:
1.
CEntitySystem::SpawnEntity
will check for an entity pool associated with the provided entity class. If so, it will delegate the workload to the entity pool manager.
2. From within
CEntityPoolManager::PrepareDynamicFromPool
, an entity pool bookmark is created for the new entity. This is done primarily for serialization purposes.
3. The execution flow follows the same sequence as preparing a static entity (see Creating and
Destroying Static Entities with Pools (p. 558)
.
4. If the process is successful, the entity container now housing the information is returned. Otherwise,
SpawnEntity
creates a new
CEntity
instance to satisfy the request.
At this point, calling
CEntity::GetEntity
or
CEntity::FindEntityByName
will return the entity container now housing the dynamic entity and its information.
As with static entities, use
IEntitySystem::RemoveEntity
or any other method that can destroy an entity. The entity pool manager will return the entity container to the pool, freeing it for use elsewhere and removing the dynamic entity in the process. The resulting execution flow differ from destroying static entities in two ways:
• Dynamic entities are not serialized when they are returned.
• The entity pool bookmark associated with the dynamic entity is removed. It is no longer needed.
At this point, calling
CEntity::GetEntity
or
CEntity::FindEntityByName
will return NULL.
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
All entities created or prepared through the entity pool system are serialized by the system for game save/load. For this reason, do not serialize those entities marked as coming from the pool (
IEntity:IsFromPool
) in your normal serialization. This is handled in Lumberyard's default implementation for saving and loading the game state.
The entity pool system is serialized from the Entity system's implementation of the
Serialize
function.
The following process occurs when the game state is being saved:
1. All active entity containers in all entity pools are updated. This results in
CEntityPoolManager::UpdatePoolBookmark
being called for each active entity container. As long as the entity does not have the ENTITY_FLAG_NO_SAVE flag set on it, the bookmark is serialized as follows:
Version 1.10
561
Lumberyard Developer Guide
Listener/Event Registration a. Serialize Helper writes to the bookmark's pLastState
(an
ISerializedObject
), which contains the serialized state of the entity.
b. The callback
CEntityPoolManager::OnBookmarkEntitySerialize
runs through the serialization process on the entity. This ensures that the general information, properties and all entity proxies are serialized using their overloaded
Serialize()
implementation.
c. Any listeners subscribed to the
OnBookmarkEntitySerialize
callback are able to write data into the bookmark at this time. This is used to also bookmark AI objects along with the entity.
2. All entity pool bookmarks are saved, including the static entity and dynamic entity usage counts.
3. If any prepare requests are currently queued, the prepare request queue is saved.
The following process occurs when the game state is being loaded:
1. The saved entity pool bookmarks are read in. If the bookmark is marked as containing a dynamic entity, it is read to ensure it exists. Each bookmark's pLastState
is read in and updated.
2. If the entity pool bookmark contains an entity that was active at the time the game was saved, the entity is created/prepared from the pool once more.
a. While the entity is being created/prepared, it will load its internal state using the pLastState
at its final step, because the object contains information at this point.
b. This will also call the
OnBookmarkEntitySerialize
listener callback, allowing other systems to read data from the bookmark.
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
There are several listener and various event callbacks dealing with entity pool usage. These callbacks are important for sub-systems that rely on entity registration. They can notify you when an entity has been prepared or returned to the pool so that you can register and unregister it with your subsystems as needed.
This listener can be subscribed to via
IEntityPoolManager::AddListener
. It contains the following callbacks:
OnPoolBookmarkCreated
Called when an entity pool bookmark has been created. The reserved entity ID for the pooled entity is passed in, along with the static instanced data belonging to it.
OnEntityPreparedFromPool
Called when an entity (static or dynamic) has been prepared from the pool. You are given both the entity ID and the entity container that is now housing the entity. This is called at the end of the prepare entity process.
OnEntityReturnedToPool
Called when an entity (static or dynamic) has been returned to the pool. You are given both the entity ID and the entity container that is currently housing the entity. This is called at the start of the return entity process.
Version 1.10
562
Lumberyard Developer Guide
Debugging Utilities
OnPoolDefinitionsLoaded
Called at initialization, with information allowing listeners to set up their own resources for working with the pool. Currently passes the total number of pooled entities that have AI attached.
OnBookmarkEntitySerialize
Called during reads and writes from entity bookmarks, allowing listeners to store additional data in the bookmark.
This listener has a special callback, OnReused, that notifies you when an entity has been reloaded. This is the process an entity container goes through when a static entity is being prepared into it, or a dynamic entity is being created inside it. You are given the entity container that houses the entity as well as the static instanced data belonging to it.
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
There are several debugging utilities you can use to manage the entity pools and see how they are being used during gameplay.
To see the status of all entity pool bookmarks that currently exist during the game, use the following console command.
es_dump_bookmarks [filterName] [dumpToDisk]
This command causes text to be written to the console and game log file for every bookmark requested.
Arguments
filterName
(Optional) Allows you to filter your request to get bookmarks only for entities whose names contain the specified value as a substring. To display all bookmarks, set this argument to "all" or leave it empty.
dumpToDisk
(Optional) Allows you to output to disk all static instanced data associated with the displayed bookmarks. If supplied and its a non-zero numerical file, data will be stored at
\User\Bookmarks
\LevelName\EntityName.xml
.
Data displayed
The following information is displayed for each bookmark:
• Name of the bookmarked entity.
Version 1.10
563
Lumberyard Developer Guide
Entity ID Explained
• Layer the bookmarked entity belongs to.
• Entity class name the bookmarked entity uses.
• Reserved entity ID associated with the bookmarked entity.
• If the bookmarked entity has the No Save Entity Flag associated with it.
• If the bookmarked entity is static or dynamic.
• If the bookmarked entity contains any serialized data (and the memory footprint of the information if available).
• If the bookmarked entity contains any static instanced data (and the memory footprint of the information if available).
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
When referring to a dynamic C++ object, pointers and reference counting can be used, but a better method is to use a weak reference that allows you to remove an object and have all references become invalid. This option limits the need to iterate over all objects to invalidate objects being removed, which results in performance costs.
With each reference, Lumberyard stores a number called the "salt" (also called a "magic number"). This number, together with the
index
, gives the object a unique entity ID over the game lifetime. Whenever an object is destroyed and the index is reused, the salt is increased and all references with the same index become invalid. To get an entity position/pointer, the entity manager needs to resolve the entity ID; as the salt is different, the method fails.
The class
CSaltBufferArray
handles adding and removing objects and does the required adjustments to the salt. The object array is kept compact for more cache-friendly memory access. Storing
EntityId references to disc is possible and used for saved games and by the Editor game export. However, when loading a saved game of a level that has been patched and now has more entities, this can result in a severe conflict. To solve this problem, dynamic entities are created starting with a high index counting down, while static entities are created starting with a low index counting up.
Entity IDs have the following limitations:
• A 16-bit index allows up to approximately 65,000 living objects. This should be enough for any nonmassive multiplayer game. In a massive multiplayer game, the method described here should not be used by the server. However, it can be used between specific clients and the server.
• A 16-bit salt value allows a game to reuse an index up to approximately 65,000 times. If that happens, the index can no longer be used. This should be enough for any non-massive multiplayer game, when used with some care—don't create and destroy objects (such as bullets) too rapidly. A massive multiplayer game, or any game that supports multi-day game sessions, can run into this limit.
The Entity system is currently on a path to deprecation in favor of the Lumberyard Component Entity
Version 1.10
564
Lumberyard Developer Guide
Overview
Players may be able to interact with an entity using a key press ('F' by default). Entities that can be interacted with will be enabled with a special on-screen icon inside the game to inform the player that interaction is possible.
To use this feature, you need to create a script that implements two functions:
IsUsable()
and
OnUsed()
.
The script should look like this:
MakeUsable(NewEntity) function NewEntity:IsUsable(userId)
-- code implementation
return index; end function NewEntity:OnUsed(userId, index)
-- code implementation end
The
IsUsable()
function is called when a player is aiming the cross-hairs towards the entity. The function will determine if the entity can be interacted with by the player doing the aiming. The function only accepts a single parameter: the player's entity ID.
If the player cannot interact with the entity, the function should return 0. This value causes the UI to not render the "USE" icon over the entity.
If the player can interact with the entity, the function should return a positive value. This value will be stored and later used when calling the
OnUsed()
function.
The
OnUsed()
function is called when a player presses interacts with the entity (such as by pressing the
Use key when the USE icon is active. This function accepts two parameters: (1) the player's entity ID, and
(2) the value returned by
IsUsable()
.
CryLua is deprecated and will be removed in a future version of Lumberyard.
This section contains topics on using Lua scripting to work with the legacy Entity system. These Lua scripts use the legacy script context
of the behavior context no longer work in Lumberyard versions 1.8 and later. For information on updating Lua code from legacy script context to the new behavior context, see the migration notes for
Version 1.10
565
Lumberyard Developer Guide
Structure of a Script Entity
Lumberyard 1.8
. For information on using Lua with Lumberyard's new component entity system, see
Writing Lua Scripts for the Component Entity System (p. 620)
.
This section includes the following topics:
•
Structure of a Script Entity (p. 566)
•
•
•
•
Exposing an Entity to the Network (p. 573)
CryLua is deprecated and will be removed in a future version of Lumberyard.
Note
This page contains information on using Lua scripting to work with the legacy Entity system.
These Lua scripts use the legacy script context
. Starting with Lumberyard 1.8, Lua scripts use the new
that replaces the legacy script context. Scripts that were written before the integration of the behavior context no longer work in Lumberyard versions
1.8 and later. For information on updating Lua code from legacy script context to the new behavior context, see the migration notes for Lumberyard 1.8
. For information on using Lua
with Lumberyard's new component entity system, see Writing Lua Scripts for the Component
.
To implement a new entity using Lua, two files need to be created and stored in the game directory:
• The Ent file tells the Entity system the location of the Lua script file.
• The Lua script file implements the desired properties and functions.
With the SDK, both the
.ent
and
.lua
files are stored inside the
<Game_Folder>\Scripts.pak
file.
The Ent files are all stored inside the
<Game_Folder>\Entities
directory and need to have the
.ent
file extension. The content is XML as follows:
<Entity
Name="LivingEntity"
Script="Scripts/Entities/Physics/LivingEntity.lua"
/>
Entity properties set in the Ent file include:
Name
Name of the entity class.
Script
Path to the Lua script that implements the entity class.
Invisible
Flag indicating whether or not the entity class is visible in Lumberyard Editor.
Version 1.10
566
Lumberyard Developer Guide
Structure of a Script Entity
The Lua script, in addition to implementing the entity class, provides a set of information used by
Lumberyard Editor when working with entities on a level. The property values set inside the Lua script are default values assigned to new entity instances. Editor variables specify how entities are drawn in
Lumberyard Editor.
The following code excerpt is from the sample project files in your Lumberyard directory (
...\dev\Cache
\SamplesProject\pc\samplesproject\scripts\entities\physics\livingentity.lua
).
LivingEntity = {
Properties = {
soclasses_SmartObjectClass = "",
bMissionCritical = 0,
bCanTriggerAreas = 1,
DmgFactorWhenCollidingAI = 1,
object_Model = "objects/default/primitive_capsule.cgf",
Physics = {
bPhysicalize = 1, -- True if object should be physicalized at all.
bPushableByPlayers = 1,
},
Living = {
height = 0, -- vertical offset of collision geometry center
vector_size = {0.4, 0.4,0.9}, -- collision cylinder dimensions
height_eye = 1.8, -- vertical offset of camera
height_pivot = 0.1, -- offset from central ground position that is considered entity
center
head_radius = 0.3, -- radius of the 'head' geometry (used for camera offset)
height_head = 1.7, -- center.z of the head geometry
groundContactEps = 0.004, --the amount that the living needs to move upwards before
ground contact is lost. defaults to which ever is greater 0.004, or 0.01*geometryHeight
bUseCapsule = 1,--switches between capsule and cylinder collider geometry
inertia = 1, -- inertia koefficient, the more it is, the less inertia is, 0 means no
inertia
inertiaAccel = 1, -- inertia on acceleration
air_control = 1, -- air control koefficient 0..1, 1 - special value (total control of
movement)
air_resistance = 0.1, -- standard air resistance
gravity = 9.8, -- gravity vector
mass = 100, -- mass (in kg)
min_slide_angle = 60, -- if surface slope is more than this angle, player starts sliding
(angle is in radians)
max_climb_angle = 60, -- player cannot climb surface which slope is steeper than this
angle
max_jump_angle = 45, -- player is not allowed to jump towards ground if this angle is
exceeded
min_fall_angle = 65, -- player starts falling when slope is steeper than this
max_vel_ground = 10, -- player cannot stand of surfaces that are moving faster than this
timeImpulseRecover = 0.3, -- forcefully turns on inertia for that duration after
receiving an impulse
nod_speed = 1, -- vertical camera shake speed after landings
bActive = 1,-- 0 disables all simulation for the character, apart from moving along the
requested velocity
collision_types = 271, -- (271 = ent_static | ent_terrain | ent_living | ent_rigid |
ent_sleeping_rigid) entity types to check collisions against
},
MultiplayerOptions = {
bNetworked= 0,
},
Version 1.10
567
Lumberyard Developer Guide
Structure of a Script Entity
bExcludeCover=0,
},
Client = {},
Server = {},
-- Temp.
_Flags = {},
Editor={
Icon = "physicsobject.bmp",
IconOnTop=1,
},
}
This information is followed by functions that implement the entity class.
Properties
Entity properties are placed inside the entity class. These properties are assigned to all new instances of the entity class created, visible and editable in Lumberyard Editor as the instance's
Entity Properties
table. The property values set for individual entity instances placed on a level are saved in the level file. When a property of an entity instance is changed in Lumberyard Editor, the
OnPropertyChange() function called (if it is has been implemented for the script entity).
Lumberyard Editor provides the Archetype tool for assigning a common set of properties reused for multiple instance (even across multiple levels). For more information on Archetypes, see Archetype Entity in the Amazon Lumberyard User Guide .
When specifying entity class property names, use the following prefixes to signal the data type expected for a property value. This enables Lumberyard Editor to validate a property value when set.
Entity class property prefixes i n s f
Prefix b clr object_
Data Type
boolean float integer positive integer string color object compatible with Lumberyard (CFG, CGA, CHR or CDF file)
You can add special comments to property values that can be utilized by the engine. For example:
--[25,100,0.1,"Damage threshold"]
This comment tells the engine the following:
• Value is limited to between 25 and 100.
• The float value uses a step of 0.01 (this limits the fidelity of values).
Version 1.10
568
Lumberyard Developer Guide
Using Entity State
• The string "Damage threshold" will be displayed in the Lumberyard Editor as a tool tip.
Editor Table
The Editor table provides additional configuration information to Lumberyard Editor on how to handle instances of the entity.
Entity class editor variables
Variable
Model
ShowBounds
AbsoluteRadius
Icon
IconOnTop
DisplayArrow
Links
Description
CGF model to be rendered over an entity instance.
Flag indicating whether or not a bounding box is drawn around an entity instance when selected.
BMP icon to be drawn over an entity instance.
Flag indicating whether or not the icon is drawn over or under an entity instance.
Functions
A script entity can include several callback functions called by the engine or game system. See
System Script Callbacks (p. 773)
for more information.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Note
This page contains information on using Lua scripting to work with the legacy Entity system.
These Lua scripts use the legacy script context
. Starting with Lumberyard 1.8, Lua scripts use the new
that replaces the legacy script context. Scripts that were written before the integration of the behavior context no longer work in Lumberyard versions
1.8 and later. For information on updating Lua code from legacy script context to the new behavior context, see the migration notes for Lumberyard 1.8
. For information on using Lua
with Lumberyard's new component entity system, see Writing Lua Scripts for the Component
.
The Entity system provides a simple state-switching mechanism for script entities.
Each state consists of the following:
• Name (string)
• Lua table within the entity table, identified with the state name
•
OnEndState()
function (optional)
•
OnBeginState()
function (optional)
Version 1.10
569
Lumberyard Developer Guide
Using Entity State
• Additional callback functions (optional) (See Entity System Script Callbacks (p. 773)
)
To declare states for an entity:
All entity states must be declared in the entity's main table to make the Entity system aware of them.
The following examples show how to declare "Opened", "Closed", and "Destroyed" states.
AdvancedDoor =
{
Client = {},
Server = {},
PropertiesInstance = ...
Properties = ...
States = {"Opened","Closed","Destroyed"},
}
To define an entity state:
Entity states can be either on the server or client (or both). The definition for a server-side "Opened" state might look as follows:
AdvancedDoor.Server.Opened =
{
OnBeginState = function( self )
if(self.Properties.bUsePortal==1)then
System.ActivatePortal(self:GetWorldPos(),1,self.id);
end;
self.bUpdate=1;
self.lasttime=0;
AI.ModifySmartObjectStates( self.id, "Open-Closed" );
self:Play(1);
end,
OnUpdate = function(self, dt)
self:OnUpdate();
end,
}
To set an entity's initial state:
Initially, an entity has no state. To set an entity's state, use one of the entity's callback functions (not to be confused with an entity state's callback function) to call its
GotoState()
method, shown in the following example. Once the entity state is set, the entity resides in that state and events will also be directed to that state.
function AdvancedDoor:OnReset()
self:GotoState("Opened"); end
To change an entity's state:
Transitioning from the current state to any other state can also be done using the
GotoState()
method, as follows.
function AdvancedDoor.Server:OnHit(hit)
...
if(self:IsDead())then
self:GotoState("Destroyed");
Version 1.10
570
Lumberyard Developer Guide
Using Entity Slots
end end
To query an entity's state:
Querying the state the entity is currently in can be done using the
GetState()
method, as follows.
if (self:GetState()=="Opened") then ...
if (self:GetState()~="Opened") then ...
CryLua is deprecated and will be removed in a future version of Lumberyard.
Note
This page contains information on using Lua scripting to work with the legacy Entity system.
These Lua scripts use the legacy script context
. Starting with Lumberyard 1.8, Lua scripts use the new
that replaces the legacy script context. Scripts that were written before the integration of the behavior context no longer work in Lumberyard versions
1.8 and later. For information on updating Lua code from legacy script context to the new behavior context, see the migration notes for Lumberyard 1.8
. For information on using Lua
with Lumberyard's new component entity system, see Writing Lua Scripts for the Component
.
Each entity can have slots that are used to hold different resources available in Lumberyard. This topic describes how to work with entity slots.
The following table lists the resources that can be allocated in a slot, along with the ScriptBind function used to allocate it.
Lumberyard resource
static geometry animated character particle emitter light cloud fog volume
Function
LoadObject()
or
LoadSubObject()
LoadCharacter()
LoadParticleEffect()
LoadLight()
LoadCloud()
LoadFogVolume()
LoadVolumeObject()
Each of these resource may be moved, rotated, or scaled relative to the entity itself.
Version 1.10
571
Lumberyard Developer Guide
Linking Entities
•
SetSlotPos()
•
GetSlotPos()
•
SetSlotAngles()
•
GetSlotAngles()
•
SetSlotScale()
•
GetSlotScale()
You can add a parenting link between the slots, making it possible to have related positions.
•
SetParentSlot()
•
GetParentSlot()
To determine whether or not a specified slot is allocated, call the function
!IsSlotValid()
.
To free one slot, call
!FreeSlot()
To free all allocated slots within the entity, call
!FreeAllSlots()
.
The following example illustrates loading a slot in a script function.
local pos={x=0,y=0,z=0}; self:LoadObject(0,props.fileModel); self:SetSlotPos(0,pos); self:SetCurrentSlot(0);
CryLua is deprecated and will be removed in a future version of Lumberyard.
Note
This page contains information on using Lua scripting to work with the legacy Entity system.
These Lua scripts use the legacy script context
. Starting with Lumberyard 1.8, Lua scripts use the new
that replaces the legacy script context. Scripts that were written before the integration of the behavior context no longer work in Lumberyard versions
1.8 and later. For information on updating Lua code from legacy script context to the new behavior context, see the migration notes for Lumberyard 1.8
. For information on using Lua
with Lumberyard's new component entity system, see Writing Lua Scripts for the Component
.
In Lumberyard Editor, you can link an entity to other entities. These links are organized inside the Entity system. Each entity can link to multiple entities. Each link has a name associated to it. See the Amazon
Lumberyard User Guide for more information about grouping and linking objects.
The following example Lua script searches the Entity system for any links to other entities that are named "Generator".
function RadarBase:IsPowered()
Version 1.10
572
Lumberyard Developer Guide
Exposing an Entity to the Network
local i=0;
local link = self:GetLinkTarget("Generator", i);
while (link) do
Log("Generator %s", link:GetName());
if (link:GetState() == "PowerOn") then
if (link.PowerConnect) then
link:PowerConnect(self.id);
return true;
end
end
i=i+1;
link=self:GetLinkTarget("Generator", i);
end
return false; end
The legacy ScriptBind functions related to entity links are listed in
Lua ScriptBind Reference (p. 796) .
The following functions are used to read or create entity links:
•
CountLinks
•
CreateLink
•
GetLink
•
GetLinkName
•
GetLinkTarget
•
RemoveAllLinks
•
RemoveLink
•
SetLinkTarget
CryLua is deprecated and will be removed in a future version of Lumberyard.
Note
This page contains information on using Lua scripting to work with the legacy Entity system.
These Lua scripts use the legacy script context
. Starting with Lumberyard 1.8, Lua scripts use the new
that replaces the legacy script context. Scripts that were written before the integration of the behavior context no longer work in Lumberyard versions
1.8 and later. For information on updating Lua code from legacy script context to the new behavior context, see the migration notes for Lumberyard 1.8
. For information on using Lua
with Lumberyard's new component entity system, see Writing Lua Scripts for the Component
and the Network Binding (p. 626) section in particular.
A script entity can be a serialized value on the network. This approach is done by setting the values on the server and having them automatically synchronized on all the clients. It also makes it possible to invoke client/server RMI functions.
Keep in mind the following limitations:
• There is no notification when a serialized value has changed.
• Values are controlled on the server only, there is no way to set values on the client.
Version 1.10
573
Lumberyard Developer Guide
Exposing an Entity to the Network
To define the network features of an entity, call the ScriptBind function
Net.Expose()
, as illustrated in the following code. This code is written inside a Lua script within the global space, rather than in a function.
Net.Expose {
Class = DeathMatch,
ClientMethods = {
ClVictory = { RELIABLE_ORDERED, POST_ATTACH, ENTITYID, },
ClNoWinner = { RELIABLE_ORDERED, POST_ATTACH, },
ClClientConnect = { RELIABLE_UNORDERED, POST_ATTACH, STRING, BOOL },
ClClientDisconnect = { RELIABLE_UNORDERED, POST_ATTACH, STRING, },
ClClientEnteredGame = { RELIABLE_UNORDERED, POST_ATTACH, STRING, },
},
ServerMethods = {
RequestRevive = { RELIABLE_UNORDERED, POST_ATTACH, ENTITYID, },
RequestSpectatorTarget = { RELIABLE_UNORDERED, POST_ATTACH, ENTITYID, INT8 },
},
ServerProperties = {
busy = BOOL,
},
};
RMI functions
The RMI function is defined in either the ClientMethods and ServerMethods tables passed to the
Net.Expose()
function.
Order flags:
• UNRELIABLE_ORDERED
• RELIABLE_ORDERED
• RELIABLE_UNORDERED
The following descriptors control how the RMI is scheduled within the data serialization.
RMI attach flag
NO_ATTACH
PRE_ATTACH
POST_ATTACH
Description
No special control (preferred)
Call occurs before data serialized
Call occurs after the data serialized
The following example shows a function declaration: function DeathMatch.Client:ClClientConnect(name, reconnect)
The following examples illustrate a function call: self.allClients:ClVictory( winningPlayerId ); self.otherClients:ClClientConnect( channelId, player:GetName(), reconnect );
Version 1.10
574
Lumberyard Developer Guide
Exposing an Entity to the Network self.onClient:ClClientConnect( channelId, player:GetName(), reconnect );
for more details.
Note
Note: Script networking doesn't have an equivalent to the dependent object RMIs.
ServerProperties table
The entity table also contains a ServerProperties table that indicates which properties need to be synchronized. This is also the place to define the variable type of the value.
In addition, you must create a game object in CryAction and bind the new game object to the network game session. The following example shows the code placed in the
OnSpawn()
function:
CryAction.CreateGameObjectForEntity(self.id);
CryAction.BindGameObjectToNetwork(self.id);
You can also instruct the game object to receive a per-frame update callback, as in the following function call to CryAction:
CryAction.ForceGameObjectUpdate(self.id, true);
The script entity receive the
OnUpdate()
function callback of its Server table.
function Door.Server:OnUpdate(frameTime)
-- some code end
Note
Adding update callback code to your script entity can decrease the performance of a game.
Version 1.10
575
Lumberyard Developer Guide
How Components Use EBuses
Event buses (EBuses) are a general-purpose communication system that Lumberyard uses to dispatch notifications and receive requests. EBuses are configurable and support many different use cases. For examples of EBus usage, see
Usage and Examples (p. 578) . For in-depth information about EBuses, see
Event Buses in Depth (p. 582) . For C++ API reference documentation on the core EBus code, see the
EBus API Reference in the Amazon Lumberyard C++ API Reference .
Components commonly use EBuses in two ways: to dispatch events or to handle requests. A bus that dispatches events is a notification bus. A bus that receives requests is a request bus. Some components provide one type of bus, and some components provide both types. Some components do not provide an EBus at all. You use the EBus class for both EBus types, but you configure the EBuses differently. The following sections show how to set up and configure notification buses, event handlers, and request buses.
Notification buses dispatch events. The events are received by handlers, which implement a function to handle the event. Handlers first connect to the bus. When the bus dispatches an event, the handler's function executes. This section shows how to set up a notification bus to dispatch an event and a handler to receive the event.
To set up a bus to dispatch events
1. Define a class that inherits from
EBusTraits
. This class will be the interface for the EBus .
2. Override individual
EBusTraits
properties to define the behavior of your bus. Three
EBusTraits
that notification buses commonly override are
AddressPolicy
, which defines how many addresses the
EBus contains,
HandlerPolicy
, which describes how many handlers can connect to each address, and
BusIdType
, which is the type of ID that is used to address the EBus if addresses are used. For
Version 1.10
576
Lumberyard Developer Guide
Setting up a Handler example, notification buses often need to have multiple addresses, with the addresses identified by entity ID. To do so, they override the default
AddressPolicy
with
EBusAddressPolicy::ById
and set the
BusIdType
to
EntityId
.
3. Declare a function for each event that the EBus will dispatch. Handler classes will implement these functions to handle the events.
4. Declare an EBus that takes your class as a template parameter.
5. Send events. The function that you use to send the event depends on which addresses you want to send the event to, whether to return a value, the order in which to call the handlers, and whether to queue the event.
• To send an event to all handlers connected to the EBus, use
Broadcast()
. If an EBus has multiple addresses, you can use
Event()
to send the event only to handlers connected at the specified ID.
For performance-critical code, you can avoid an address lookup by using
Event()
variants that take a pointer instead of an ID.
• If an event returns a value, use
BroadcastResult()
or
EventResult()
to get the result.
• If you want handlers to receive the events in reverse order, use
BroadcastReverse()
or
EventReverse()
.
• To send events asynchronously, queue the event. Queued events are not executed until the queue is flushed. To support queuing, set the
EnableEventQueue
trait. To queue events, use
QueueBroadcast()
or
QueueEvent()
. To flush the event queue, use
ExecuteQueuedEvents()
.
To enable a handler class to handle the events dispatched by a notification bus
1. Derive your handler class from
<BusName>
::Handler
. For example, a class that needs to handle tick requests should derive from
TickRequestBus::Handler
.
2. Implement the EBus interface to define how the handler class should handle the events. In the tick bus example, a handler class would implement
OnTick()
.
3. Connect and disconnect from the bus at the appropriate places within your handler class's code. Use
<BusName>
:Handler::BusConnect()
to connect to the bus and
<BusName>
:Handler::BusDisconnect()
to disconnect from the bus. If the handler class is a component, connect to the bus in
Activate()
and disconnect from the bus in
Deactivate()
. Noncomponents typically connect in the constructor and disconnect in the destructor.
A request bus receives and handles requests. Typically, only one class handles requests for a request bus.
The first several steps for setting up a request bus are similar to setting up a notification bus. After that you also need to implement the handlers for handling the requests.
To set up a request bus
1. Define a class that inherits from
EBusTraits
. This class will be the interface for requests made to the
EBus.
2. Override individual
EBusTraits
properties to define the behavior of your bus. Two
EBusTraits
that request buses commonly override are
AddressPolicy
, which defines how many addresses the EBus contains, and
HandlerPolicy
, which describes how many handlers can connect to each address.
Version 1.10
577
Lumberyard Developer Guide
Usage and Examples
For example, because there is typically only one handler class for each request bus, request buses typically override the default handler policy with
EBusHandlerPolicy::Single
.
3. Declare a function for each event that the handler class will receive requests about. These are the functions that other classes will use to make requests of the handler class.
4. Declare an EBus that takes your class as a template parameter.
5. Implement a handler for the events as described in the previous section
.
This section provides examples of how to declare and configure an EBus, implement a handler, send messages, and receive return values.
Topics
•
•
EBus Configuration Options (p. 579)
•
Implementing a Handler (p. 580)
•
Sending Messages to an EBus (p. 581)
•
Retrieving Return Values (p. 581)
•
Return Values from Multiple Handlers (p. 581)
•
Asynchronous/Queued Buses (p. 582)
Declaring an EBus is much like declaring any virtual interface class in C++. However, you can specify various configuration options that control how the EBus is generated at compile time and how it behaves.
Here is a simple example of a basic interface and associated EBus.
class ExampleInterface : public AZ::EBusTraits
{ public:
// ------------------ EBus Configuration -------------------
// These override the defaults in EBusTraits.
// One handler per address is supported.
static const AZ::EBusHandlerPolicy
HandlerPolicy
= AZ::EBusHandlerPolicy::Single;
// The EBus contains a single address.
static const AZ::EBusAddressPolicy
AddressPolicy
= AZ::EBusAddressPolicy::Single;
// ------------------------ Other -------------------------
virtual ~ExampleInterface() { };
// ------------------ Handler Interface -------------------
// Handlers inherit from ExampleInterfaceBus::Handler
// Handlers are required to implement this because it's pure virtual.
virtual void DoSomething() = 0;
// Handlers can override this, but are not required to.
virtual void SomeMessage() { }
Version 1.10
578
Lumberyard Developer Guide
EBus Configuration Options
// Returns a value and has a parameter.
virtual bool ReturnsValue(int x) = 0;
}; using ExampleInterfaceBus = AZ::EBus<ExampleInterface>;
Tip
Use descriptive names in EBuses, and avoid overloaded functions. Explicit and descriptive function names prevent future API name collisions when classes inherit your EBus interfaces. Avoiding overloaded functions improves the experience of using your EBuses. This is especially true from scripting environments such as Lua, in which descriptive names improve readability and clarity. For more information, see
Components and EBuses: Best Practices (p. 478)
.
EBus configuration options are key to controlling how the EBus behaves. The configuration options used in the previous example are explained in the following sections.
The
HandlerPolicy
trait determines how many handlers connect to an address on the EBus and the
// One handler per address is supported.
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::
Single
;
The
HandlerPolicy
has two common uses:
• A singleton pattern in which various systems post messages or requests to a single system elsewhere in the codebase.
• A pattern where a specific component or an entity handles messages to the EBus. For example, you might have a mesh component that owns an entity. The mesh component handles all mesh-related queries addressed to the entity's ID.
The
AddressPolicy
trait defines how many addresses exist on the EBus. The following example specifes only a single address. An ID is not required.
// The EBus contains a single address.
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::
Single
;
Practical use cases for a single address policy include any global EBus that is not tied to a specific entity, application-specific ID, or object.
The
EBusAddressPolicy
has the following options:
•
Single
•
ById
– The EBus has multiple addresses. The order in which addresses are notified when broadcasting events without an ID is not specified.
Version 1.10
579
Lumberyard Developer Guide
Implementing a Handler
•
ByIdAndOrdered
– The EBus has multiple addresses. However, when broadcasting events without an
ID, we want to control the order in which individual addresses are notified. The
BusIdOrderCompare definition allows for arbitrary customization of ordering.
The
EBusHandlerPolicy
has the following options:
•
Single
– One handler per address is supported. Uses include an EBus with a
or an
EBus with addresses and a single handler (p. 584)
.
•
Multiple
– Any number of handlers are supported. Ordering is ignored. Uses include
or an
EBus with addresses and many handlers (p. 586)
.
•
MultipleAndOrdered
– Any number of handlers are supported, and handlers are notified in a particular order. The
BusHandlerOrderCompare
definition allows for arbitrary customization of ordering.
A handler of an EBus derives from
AZ::EBus<x>::Handler
. For convenience this was defined as
ExampleInterfaceBus
in the
previous example (p. 578) . This means that the handler can be derived
from
ExampleInterfaceBus::Handler
.
#include "ExampleInterface.h"
// note: derives from bus handler, rather than directly from ExampleInterface class MyHandler : protected ExampleInterfaceBus::Handler
{ public:
void Activate(); protected:
// Implement the handler interface:
void DoSomething() override; // note: Override specified.
void SomeMessage() override;
bool ReturnsValue(int x) override;
};
Note that handlers are not automatically connected to an EBus, but are disconnected automatically because the destructor of
Handler
calls
BusDisconnect
.
In order to actually connect to the EBus and start receiving events, your handler must call
BusConnect()
: void MyHandler::Activate()
{
// For a single EBus, this would be just BusConnect().
// For multiple EBuses, you must specify the EBus to connect to:
ExampleInterfaceBus::Handler::
BusConnect()
;
}
You can call
BusConnect()
at any time and from any thread.
If your EBus is addressed, connect to the EBus by passing the EBus ID to
BusConnect()
. To listen on all addresses, call
BusConnect()
without passing in an ID.
// connect to the EBus at address 5.
ExampleAddressBus::Handler::
BusConnect(5)
;
Version 1.10
580
Lumberyard Developer Guide
Sending Messages to an EBus
Anyone who can include the header can send messages to the EBus at any time. Using the previous example, a completely unrelated class can issue a
DoSomething
call on the EBus:
#include "ExampleInterface.h" // Note: You don't need to include MyHandler.h.
...
ExampleInterfaceBus::Broadcast(&ExampleInterfaceBus::Events::DoSomething);
EBuses also support a macro-based syntax. This syntax is being phased out, but uses of it can still be found in Lumberyard source code. The macro syntax for the previous example is as follows.
#include "ExampleInterface.h"
// Note: You don't need to include MyHandler.h.
...
EBUS_EVENT(ExampleInterfaceBus,
DoSomething
);
If your EBus is addressed, you can send events to a specific address ID. Events broadcast globally are received at all addresses.
// Broadcasts to ALL HANDLERS on this EBus regardless of address (even if the EBus has
addresses)
ExampleAddressBus::Broadcast(&ExampleAddressBus::Events::Test);
// Broadcasts only to handlers connected to address 5.
ExampleAddressBus::Event(5, &ExampleAddressBus::Events::Test);
If you make a synchronous call, you can also supply a variable in which to place the result:
// ALWAYS INITIALIZE YOUR RESULT!!!
// Since there may be nobody connected to the EBus, your result may not be populated.
bool
result
= false;
ExampleInterfaceBus::BroadcastResult(result, &ExampleInterfaceBus::Events::ReturnsValue,
2);
In this example, if there are no handlers connected to the EBus, the result
variable is not modified. If one or more handlers are connected to the EBus, operator=()
is called on the result
variable for each handler.
In certain cases you might have to aggregate the return value of a function when there are multiple handlers. For example, suppose you want to send a message to all handlers that asks whether any one handler objects to shutting down an application. If any one handler returns true, you should abort the shutdown. The following would not suffice:
// Counterexample: returnValue contains only the result of the final handler.
bool returnValue = false;
SomeInterfaceBus::BroadcastResult(returnValue,
&SomeInterfaceBus::Events::DoesAnyoneObject);
Because the EBus issues operator=
for each handler, returnValue
would contain only the result of the final handler.
Version 1.10
581
Lumberyard Developer Guide
Asynchronous/Queued Buses
Instead, you can create a class to collect your results that overrides operator=
. There are several built-in types for this, and you can make your own:
#include <AZCore/EBus/Results.h>
...
AZ::EBusAggregateResults<bool> results;
SomeInterfaceBus::BroadcastResult(
results
, &SomeInterfaceBus::Events::DoesAnyoneObject);
//
results
now contains a vector of all results from all handlers.
// alternative:
AZ::EBusLogicalResult<bool, AZStd::logical_or<bool>> response(false);
SomeInterfaceBus::BroadcastResult(
response
, &SomeInterfaceBus::Events::DoesAnyoneObject);
//
response
now contains each result, using a logical OR operation. So all responses are
OR'd with each other.
Note
Additional building blocks (for example, arithmetic results) are available inside the results.h
file.
To declare an EBus on which events can be queued and sent asynchronously, add the following to the
EBus declaration: static const bool EnableEventQueue = true;
You can use
QueueBroadcast
and
QueueEvent
to enqueue events on an EBus so that you can flush them later from a controlled location or thread.
To flush the queue at the appropriate location or thread, invoke the following:
ExampleInterfaceBus::ExecuteQueuedEvents();
Event buses (or EBus for short) are a general purpose system for dispatching messages. Ebuses have many advantages:
•
Abstraction
– Minimize hard dependencies between systems.
•
Event-driven programming
– Eliminate polling patterns for more scalable and high performing software.
•
Cleaner application code
– Safely dispatch messages without concern for what is handling them or whether they are being handled at all.
•
Concurrency
– Queue events from various threads for safe execution on another thread or for distributed system applications.
•
Predictability
– Provide support for ordering of handlers on a given bus.
•
Debugging
– Intercept messages for reporting, profiling, and introspection purposes.
You can use EBuses in many different ways. Following are some examples:
Version 1.10
582
Lumberyard Developer Guide
Bus Configurations
• As a direct global function call
• Dispatch processing to multiple handlers
• Queue all calls, acting like a command buffer
• As an addressable mailbox
• For imperative delivery
• For queued delivery
• Automatic marshalling of a function call into a network message or other command buffer
The EBus source code can found in the Lumberyard directory location
<root>
\dev\Code\Framework
\AZCore\AZCore\EBus\EBus.h
.
You can configure EBuses for various usage patterns. This section presents common configurations and their applications.
Topics
•
•
•
EBus with Addresses and a Single Handler (p. 584)
•
EBus with Addresses and Many Handlers (p. 586)
The simplest configuration is a many-to-one (or zero) communication bus, much like a singleton pattern.
There is at most one handler, to which any sender can dispatch events. Senders need not manually check and de-reference pointers. If no handler is connected to the bus, the event is simply ignored.
// One handler is supported.
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
// The EBus uses a single address.
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
Another common configuration is one in which many handlers can be present. You can use this configuration to implement observer patterns, subscriptions to system events, or general-purpose broadcasting.
Version 1.10
583
Lumberyard Developer Guide
Bus Configurations
Events to the handlers can be received in defined or undefined order. You specify which one in the
HandlerPolicy
trait.
Example Without Handler Ordering
To handle events in no particular order, simply use the
Multiple
keyword in the
HandlerPolicy
trait, as in the following example:
// Multiple handlers. Events received in undefined order.
static const AZ::EBusHandlerPolicy
HandlerPolicy
= AZ::EBusHandlerPolicy::
Multiple
;
// The EBus uses a single address.
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
Example with Handler Ordering
To handle events in a particular order, use the
MultipleAndOrdered
keyword in the
HandlerPolicy
trait, and then implement a custom handler-ordering function, as in the following example:
// Multiple handlers. Events received in defined order.
static const AZ::EBusHandlerPolicy
HandlerPolicy
=
AZ::EBusHandlerPolicy::
MultipleAndOrdered
;
// The EBus uses a single address.
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::Single;
//
Implement a custom handler-ordering function
struct BusHandlerOrderCompare : public AZStd::binary_function<MyBusInterface*,
MyBusInterface*, bool>
{
AZ_FORCE_INLINE bool operator()(const MyBusInterface* left, const MyBusInterface*
right) const { return left->GetOrder() < right->GetOrder(); }
};
EBuses also support addressing based on a custom ID. Events addressed to an ID are received by handlers connected to that ID. If an event is broadcast without an ID, it is received by handlers at all addresses.
A common use for this approach is for communication among the components of a single entity, or between components of a separate but related entity. In this case the entity ID is the address.
Version 1.10
584
Lumberyard Developer Guide
Bus Configurations
Example Without Address Ordering
In the following example, messages broadcast with an ID arrive at each address in no particular order.
// One handler per address is supported.
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
// The EBus has multiple addresses. Addresses are not ordered.
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::
ById
;
// Messages are addressed by EntityId.
using BusIdType = AZ::EntityId;
Example With Address Ordering
In the following example, messages broadcast with an ID arrive at each address in a specified order.
Version 1.10
585
Lumberyard Developer Guide
Bus Configurations
// One handler per address is supported.
static const AZ::EBusHandlerPolicy HandlerPolicy = AZ::EBusHandlerPolicy::Single;
// The EBus has multiple addresses. Addresses are ordered.
static const AZ::EBusAddressPolicy AddressPolicy = AZ::EBusAddressPolicy::
ByIdAndOrdered
;
// Messages are addressed by EntityId.
using BusIdType = AZ::EntityId;
// Addresses are ordered by EntityId.
using BusIdOrderCompare = AZStd::greater<BusIdType>;
In the previous configuration, only one handler is allowed per address. This is often desirable to enforce ownership of an EBus for a specific ID, as in the singleton case above. However, if you want more than one handler per address, you can configure the EBus accordingly:
Version 1.10
586
Lumberyard Developer Guide
Bus Configurations
Example: Without Address Ordering
In the following example, messages broadcast with an ID arrive at each address in no particular order. At each address, the order in which handlers receive the message is defined by
EBusHandlerPolicy
, which in this example is simply
ById
:
// Allow any number of handlers per address.
static const AZ::EBusHandlerPolicy
HandlerPolicy
= AZ::EBusHandlerPolicy::
Multiple
;
// The EBus has multiple addresses. Addresses are not ordered.
static const AZ::EBusAddressPolicy
AddressPolicy
= AZ::EBusAddressPolicy::
ById
;
// Messages are addressed by EntityId.
Version 1.10
587
Lumberyard Developer Guide
Synchronous vs. Asynchronous using BusIdType = AZ::EntityId;
Example: With Address Ordering
In the following example, messages broadcast with an ID arrive at each address in a specified order. At each address, the order in which handlers receive the message is defined by the
EBusHandlerPolicy
, which in this example is
ByIdAndOrdered
.
// Allow any number of handlers per address.
static const AZ::EBusHandlerPolicy
HandlerPolicy
= AZ::EBusHandlerPolicy::
Multiple
;
// The EBus has multiple addresses. Addresses are ordered.
static const AZ::EBusAddressPolicy
AddressPolicy
= AZ::EBusAddressPolicy::
ByIdAndOrdered
;
// We address the bus EntityId.
using BusIdType = AZ::EntityId;
// Addresses are ordered by EntityId.
using BusIdOrderCompare = AZStd::greater<BusIdType>;
EBus supports both synchronous and asynchronous (queued) messaging.
Synchronous Messaging
Synchronous messages are sent to any and all handlers when an EBus event is invoked. Synchronous messages limit opportunities for asynchronous programming, but they offer the following benefits:
• They don't require storing a closure. Arguments are forwarded directly to callers.
• They let you retrieve an immediate result from a handler (event return value).
• They have no latency.
Asynchronous Messaging
Asynchronous messages have the following advantages:
• They create many more opportunities for parallelism and are more future proof.
• They support queuing messages from any thread, dispatching them on a safe thread (like the main thread, or any thread that you choose).
• The code used to write them is inherently tolerant to latency and is easily migrated to actor models and other distributed platforms.
• The performance of the code that initiates events doesn't rely on the efficiency of the code that handles the events.
• In performance-critical code, asynchronous messages can improve i-cache and d-cache performance because they require fewer virtual function calls.
For information on declaring an EBus for queing and sending messages asynchronously, see
Asynchronous/Queued Buses (p. 582)
.
EBuses contain other features that address various patterns and use cases:
Version 1.10
588
Lumberyard Developer Guide
Common Tasks, EBuses, and Handlers
•
Cache a pointer to which messages can be dispatched
– This is handy for EBuses that have IDs.
Instead of looking up the EBus address by ID for each event, you can use the cached pointer for faster dispatching.
•
Queue any callable function on an EBus
– When you use queued messaging, you can queue a Lambda function or bound function against an EBus for execution on another thread. This is useful for general purpose thread-safe queuing.
The following are some common game programming tasks and the EBuses and handlers that you can use to implement them.
Bus
Events
File
AZ::InputEventNotificationBus
OnPressed
,
OnHeld
,
OnReleased
InputEventBus.h
Use these events to detect when mouse, keyboard, or other buttons are pressed, held, or released.
Bus
Events
File
LmbrCentral::MeshComponentNotificationBus
OnMeshCreated
,
OnMeshDestroyed
MeshComponentBus.h
Even after an entity has been created and its components have been activated, visual data might not be fully loaded. The
OnMeshCreated
event occurs when the mesh creation is complete. This is useful if you want to access the underlying
ICharacterInstance
and
ISkeletonAnim
members in order to play animations. More generally, it is useful to declare a component or entity as "alive" or game ready, whatever that might mean for your application.
Bus
Events
File
GridMate::SessionEventBus
OnMemberJoined
,
OnMemberLeaving
Session.h
You can use the
SessionEventBus
to detect when a member joins or leaves a network session. For documentation on this EBus, see
Reacting to Session Events (p. 1037)
in the Lumberyard networking documentation (p. 1004)
.
Version 1.10
589
Lumberyard Developer Guide
Get and Set Physics Characteristics
Bus
Methods
File
LmbrCentral::PhysicsComponentRequestBus
AddImpulse
,
GetMass
,
SetMass
,
GetVelocity
,
SetVelocity
, etc.
PhysicsComponentBus.h
The
PhysicsComponentRequestBus
contains useful methods for getting or setting the physical characteristics of objects like mass, density, velocity, and water damping. For an example of using a pointer directly to the underlying handler for better access to functions such as
GetVelocity
, see
Access to EBus Handlers (p. 592) .
Bus
Event
File
LmbrCentral::CharacterAnimationNotificationBus
OnAnimationEvent
CharacterAnimationBus.h
If you have set up animations in the
.animevents
file in Geppetto, an
OnAnimationEvent
event is called for each animation event during animation playback. You can monitor this to get notifications for animation events. The string configured for the animation event in Geppetto is held in the
LmbrCentral::AnimationEvent::m_animName
variable.
Bus
Methods
File
AZ::TransformBus
GetWorldX
,
SetWorldX
,
GetWorldY
,
SetWorldY
, etc.
TransformBus.h
The
TransformBus
contains many useful methods for getting or setting where in the world the entity is, such as xyz axis locations. For an example of using a pointer directly to the entity's transform for more optimal access to functions such as
GetBasisY
(the entity's forward vector), see Direct Access to EBus
.
Bus
Method
File
LmbrCentral::SkinnedMeshComponentRequestBus
GetCharacterInstance
SkinnedMeshComponent.h
To play animations manually, use the
ISkeletonAnim
in the character instance. To get the
ISkeletonAnim from the
ICharacterInstance
, use
ICharacterInstance::GetISkeletonAnim()
.
Version 1.10
590
Lumberyard Developer Guide
Use an EBus from Another Component
Bus
Events
File
AZ::EntityBus
OnEntityActivated
,
OnEntityDeactivated
EntityBus.h
The
OnEntityActivated
and
OnEntityDeactivated
events are called after all of an entity's components have had their
Activate()
or
Deactivate()
function called. These events can be useful if you want your component to use an EBus that another component has already set up in its
Activate()
function.
Bus
Event
File
AZ::TickBus
OnTick
TickBus.h
A tick is a unit of time generated by the component application. The
OnTick
event signals that the application has issued a tick and is called each frame.
Handlers receive events based on the order in which the components are initialized, unless a handler explicitly sets its
TickEvents::m_tickOrder
. The m_tickOrder
variable contains the order in which a handler receives tick events relative to other handlers.
The
AZ::ComponentTickBus
enum has presets that contain suggested values for the different kinds of components.
/**
* Values to help you set when a particular handler is notified of ticks.
*/
enum ComponentTickBus
{
TICK_FIRST = 0, ///< First position in the tick handler order.
TICK_PLACEMENT = 50, ///< Suggested tick handler position for components
that need to be early in the tick order.
TICK_ANIMATION = 100, ///< Suggested tick handler position for animation
components.
TICK_PHYSICS = 200, ///< Suggested tick handler position for physics
components.
TICK_DEFAULT = 1000, ///< Default tick handler position when the handler
is constructed.
TICK_UI = 2000, ///< Suggested tick handler position for UI
components.
TICK_LAST = 100000, ///< Last position in the tick handler order.
};
Version 1.10
591
Lumberyard Developer Guide
Direct Access to EBus Handlers
The default value of m_tickOrder
is
TICK_DEFAULT
, but you can set m_tickOrder
to a value based on the enum. For example, if you want your component to be ticked after physics is run, set m_tickOrder
to
AZ::ComponentTickBus::TICK_PHYSICS + 1.
For more information about
TickBus
, see
Tick Bus and Components (p. 472)
.
At run time, EBuses form a communication backbone between a component and other noncomponent subsystems. In a nontrivial application, EBus activity can consume a substantial amount of CPU and memory usage. On data-cache (D-Cache)–sensitive platforms such as consoles, the number of data lookups on each EBus call can potentially degrade performance. To reduce the number of data lookups, you can use a pointer to the EBus handler instead of calling the EBus.
The result of an EBus interaction is identical to a virtual function call on an EBus handler. As a result, you can implement this approach by getting a pointer directly to the handler at initialization time. Later, at run time, you make a direct call to the handler's function. Because you know in advance whether or not a handler pointer is null, you do not have to initialize a request bus return value every time.
The code examples in this document compare the two approaches.
The following example gets the velocity indirectly by using the physics component EBus.
class PlayerAnimationController : public AZ::Component, private AZ::TickBus::Handler
{ public:
// AZ::Component
void Activate() override
{
AZ::TickBus::Handler::m_tickOrder = AZ::ComponentTickBus::TICK_PHYSICS + 1; // To
be updated after the velocity is determined.
AZ::TickBus::Handler::BusConnect(); // for OnTick
}
void Deactivate() override;
{
AZ::TickBus::Handler::BusDisconnect();
} private:
// AZ::TickBus::Handler
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override
{
// Get the velocity indirectly by using the physics component EBus.
AZ::Vector3 velocity = AZ::Vector3::CreateZero();
EBUS_EVENT_ID_RESULT(velocity, GetEntityId(),
LmbrCentral::PhysicsComponentRequestBus, GetVelocity)
;
// Do something with velocity here.
}
};
The following example uses
FindFirstHandler()
to cache the handler and gets the velocity by calling the handler directly.
Version 1.10
592
Lumberyard Developer Guide
Using TransformBus to Get the
WorldTransform's Forward Vector Every Tick class PlayerAnimationController : public AZ::Component, private AZ::TickBus::Handler,
private AZ::EntityBus::Handler
{ public:
// AZ::Component
void Activate() override
{
AZ::EntityBus::Handler::BusConnect(GetEntityId()); // For OnEntityActivated/
OnEntityDeactivated.
}
void Deactivate() override;
{
AZ::EntityBus::Handler::BusDisconnect(GetEntityId());
} private:
// AZ::EntityBus::Handler
void OnEntityActivated(const AZ::EntityId &parentEntityId) override
{
// Do this after all the other entity's components have been activated so that the
// physics component has been already attached to the EBus.
m_physicsComponentRequests =
LmbrCentral::PhysicsComponentRequestBus::FindFirstHandler(GetEntityId())
;
AZ::TickBus::Handler::m_tickOrder = AZ::ComponentTickBus::TICK_PHYSICS + 1; // To
be updated after the velocity is determined.
AZ::TickBus::Handler::BusConnect(); // For OnTick.
}
void OnEntityDeactivated(const AZ::EntityId &parentEntityId) override
{
AZ::TickBus::Handler::BusDisconnect();
m_physicsComponentRequests = nullptr;
}
// AZ::TickBus::Handler
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override
{
// Get the velocity directly from the physics component handler.
AZ::Vector3 velocity = m_physicsComponentRequests != nullptr ?
m_physicsComponentRequests->GetVelocity() : AZ::Vector3::CreateZero()
;
// Do something with velocity here.
}
LmbrCentral::PhysicsComponentRequests *m_physicsComponentRequests = nullptr;
};
The following example gets the world transform's forward vector by indirectly by using the transform
EBus.
class PlayerAnimationController : public AZ::Component, private AZ::TickBus::Handler
{ public:
// AZ::Component
void Activate() override
{
AZ::TickBus::Handler::m_tickOrder = AZ::ComponentTickBus::TICK_PHYSICS + 1; // //
To be updated after the velocity is determined.
Version 1.10
593
Lumberyard Developer Guide
Using TransformBus to Get the
WorldTransform's Forward Vector Every Tick
AZ::TickBus::Handler::BusConnect(); // for OnTick
}
void Deactivate() override;
{
AZ::TickBus::Handler::BusDisconnect();
} private:
// AZ::TickBus::Handler
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override
{
// Get the forward vector indirectly by using the transform EBus.
AZ::Transform worldTransform = AZ::Transform::Identity();
EBUS_EVENT_ID_RESULT(worldTransform, GetEntityId(), AZ::TransformBus, GetWorldTM)
;
AZ::Vector3 forward = worldTransform.GetBasisY();
// Do something with "forward" here.
}
};
The following example caches the handler and calls it directly. Because every entity has a transform, the entity already has an API operation for accessing the transform. Using the EBus and the
FindFirstHandler
function is not necessary.
class PlayerAnimationController : public AZ::Component, private AZ::TickBus::Handler,
private AZ::EntityBus::Handler
{ public:
// AZ::Component
void Activate() override
{
AZ::EntityBus::Handler::BusConnect(GetEntityId()); // for OnEntityActivated/
OnEntityDeactivated
}
void Deactivate() override;
{
AZ::EntityBus::Handler::BusDisconnect(GetEntityId());
} private:
// AZ::EntityBus::Handler
void OnEntityActivated(const AZ::EntityId &parentEntityId) override
{
m_worldTransform = &GetEntity()->GetTransform()->GetWorldTM()
;
AZ::TickBus::Handler::m_tickOrder = AZ::ComponentTickBus::TICK_PHYSICS + 1; // To
be updated after the velocity is determined.
AZ::TickBus::Handler::BusConnect(); // for OnTick
}
void OnEntityDeactivated(const AZ::EntityId &parentEntityId) override
{
AZ::TickBus::Handler::BusDisconnect();
m_worldTransform = nullptr;
}
// AZ::TickBus::Handler
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override
{
// Get the forward vector directly from the AZ::Transform.
AZ::Vector3 forward = m_worldTransform->GetBasisY()
;
// Do something with "forward" here.
}
Version 1.10
594
Lumberyard Developer Guide
Using TransformBus to Get the
WorldTransform's Forward Vector Every Tick
const AZ::Transform *m_worldTransform = nullptr;
};
Version 1.10
595
Lumberyard Developer Guide
CryPak File Archives
This section covers tools available for tracking and accessing game files.
This section includes the following topics:
•
•
The CryPak module enables you to store game content files in a compressed or uncompressed archive.
• Compatible with the standard zip format.
• Supports storing files in an archive or in the standard file system.
• Data can be read in a synchronous and asynchronous way through
IStreamCallback
(max 4GB offset,
4GB files).
• Files can be stored in compressed or uncompressed form.
• Uncompressed files can be read partially if required.
• File name comparison is not case sensitive.
• Supports loading of
.zip
or
.pak
files up to 4GB in size.
Internally, all path-handling code is ASCII-based; as such, no Unicode (16-bit characters for different languages) functions can be used—this is to save memory and for simplicity. Because games can and should be developed with ASCII path names, no real need for Unicode exists. Game productions that don't follow these requirements have issues integrating other languages. For example, because a user might install a game to a directory with Unicode characters, absolute path names are explicitly avoided throughout the whole engine.
Usually the game content data is organized in several
.pak
files, which are located in the game directory.
When a file is requested for an opening operation, the CryPak system loops through all registered
.pak
Version 1.10
596
Lumberyard Developer Guide
Slashes files.
.pak
files are searched in order of creation. This allows patch
.pak
files, which have been added to the build later, to be in a preferred position. It is also possible to mix
.pak
files with loose files, which are stored directly in the file system (not in a
.pak
file). If a file exists as a loose file as well as in a
.pak
archive, the loose file is preferred when the game is in
devmode
. However, to discourage cheating in the shipped game, the file stored in the
.pak
is preferred over the loose file when the game is not run in devmode.
Usually forward slashes ( / ) are used for internal processing, but users may enter paths that contain backslashes.
You can use the path alias
@USER@
to specify a path relative to the user folder. This might be needed to store user-specific data. Windows can have restrictions on where the user can store files. For example, the program folder might not be writable at all. For that reason, screenshots, game data, and other files should be stored in the user folder. The following are examples of valid file names and paths:
@USER@/ProfilesSingle/Lisa.dat
game/Fred.dat
• A known implementation flaw exists where using more than approximately 1000 files per directory causes problems.
• Format properties:
• The
.zip
file format stores each file with a small header that includes its path and filename in uncompressed text form. For faster file access, a directory is listed at the end of the file. The directory also stores the path and filename in uncompressed text form (redundant).
To create a
.pak
file with 7-Zip's
7za.exe
command line tool, use the following syntax:
7za a -tzip -r -mx0
PakFileName
[file1 file2 file3 ...] [dir1 dir2 ...]
The zip RFC specifies two types of
.zip
files, indicated by
.zip
format version 45. Old
.zip
files can have a 4GB offset, but if legacy I/O functions are used, it is only possible to seek +- 2GB, which becomes the practical limit. The 4GB offsets have nothing to do with native machine types and do not change size across platforms and compilers, or configurations. The offsets for older versions of
.zip
files are in a machine independent uint32
; the offsets for the new version
.zip
files are in uint64
, appended to the old version struct s. The version a
.zip
file uses is located in the header of the
.zip
file. Applications are free to not support the newer version. For more information, see the .ZIP File Format Specification .
Manual splits are not necessary, as RC supports auto-splitting:
• zip_sizesplit
– Split
.zip
files automatically when the maximum configured or supported compressed size has been reached. The default limit is 2GB.
• zip_maxsize
– Maximum compressed size of the
.zip
file in kilobytes (this gives an explicit limit).
Version 1.10
597
Lumberyard Developer Guide
Accessing Files with CryPak
Splitting works in all cases and supports multi-threading and incremental updates. It expands and shrinks the chain of necessary zip-parts automatically. Sorting is honored as much as possible, even in face of incremental modifications, but individual files can be appended to the end of the parts to fill in the leftover space even if this violates the sort order.
For more information about zip files, see Zip File Format Reference by Phil Katz .
In this tutorial you will learn how file reading and writing works through
CryPak
. The tutorial teaches you how to add new files to your project, read files from the file system and from pak archives, and write files to the file system.
Topics
•
•
Reading Files with CryPak (p. 599)
•
Writing to File System Files With CryPak (p. 601)
•
Modifying Paks With CryArchive (p. 602)
•
This tutorial demonstrates two different methods of loading a file: from inside a
.pak
archive, and directly from the file system. Before you can start, you need a file in a
.pak
archive, and a file with the same name (but with different content) in the file system. To verify which file is loaded, the example makes use of the content inside each text file.
To prepare sample files
1. Create a text file named
ExampleText.txt
.
2. Using a text editor, open
ExampleText.txt
and type in the following text:
3.
This sample was read from the .pak archive
4. Save the file.
5. Inside the
GameSDK
directory, create a subfolder called
Examples
.
6. Add the
ExampleText.txt
file to the
Examples
folder so that the path looks like this:
<root>
\GameSDK\Examples\ExampleText.txt
7. Run the following command from the directory
root
\GameSDK
:
..\Tools\7za.exe a -tzip -r -mx0 Examples.pak Examples
This command uses the executable file
7za.exe
(located in the
Tools
folder) to create an archive of the
Examples
folder called
Examples.pak
. Because you ran the command from the
GameSDK folder, the archive was saved to the
GameSDK
folder. The
.pak
file contains only the file
Examples
\ExampleText.txt
.
8. Using a text editor, change the text inside the
<root>
\GameSDK\Examples\ExampleText.txt
file to something different, for example:
This sample was read from the file system
Version 1.10
598
Lumberyard Developer Guide
Accessing Files with CryPak
Now you have two different text files with the same destination path, except that one is stored directly in the file system, and the other is inside the
.pak
file.
Now you can write some code to read the information from the
ExampleText.txt
file that you created.
1. Type the following, which contains the if
else
statement that frames the code. The
ReadFromExampleFile()
function will read the contents of the file and return true
if it succeeds, and false
if not.
char* fileContent = NULL;
if (!
ReadFromExampleFile
(&
fileContent
))
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "ReadFromExampleFile()
failed");
}
else
{
CryLogAlways("ExampleText contains %s",
fileContent
);
[...] // this line will be added later on
}
If
ReadFromExampleFile()
is successful in reading
ExampleText.txt
, fileContent
will be the space in memory that contains the text that it read.
2. Type the following, which stubs out the
ReadFromExampleFile()
function.
bool
ReadFromExampleFile
(char** fileContent)
{
CCryFile
file
;
size_t
fileSize
= 0;
const char*
filename
= "examples/exampletext.txt";
[...]
}
• file
of type
CCryFile
can make use of
CryPak
to access files directly from the file system or from inside a
.pak
archive.
• fileSize
- Defines the end of the message. In this case, reading does not end by detecting the null character '
\0
'.
• filename
- Specifies the path of the file to be loaded and is case-insensitive.
3. Type the following, which uses
CryPak
to search the file.
char str[1024];
if (!file.
Open
(filename, "
r
"))
{
sprintf(str, "Can't open file, (%s)", filename);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "%s", str);
return false;
}
•
Open()
invokes
CryPak
to search the file specified by filename
.
• File access mode
"r"
specifies that a plain text file is going to be read. To read a binary file, use
"rb"
instead.
4. Type the following, which gets the length of the file. If the file is not empty, it the allocates the memory required as indicated by the file length. It then reads the file content. It aborts if the size of the content is not equal to the file length.
Version 1.10
599
Lumberyard Developer Guide
Accessing Files with CryPak
fileSize = file.
GetLength
();
if (fileSize <= 0)
{
sprintf(str, "File is empty, (%s)", filename);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "%s", str);
return false;
}
char*
content
= new
char
[fileSize + 1];
content[fileSize] = '\0';
if (file.
ReadRaw
(content, fileSize) != fileSize)
{
delete[]
content
;
sprintf(str, "Can't read file, (%s)", filename);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "%s", str);
return false;
}
• content
is the local pointer to a char
array in memory which gets initialized by the length returned by
GetLength()
and an extra null character.
•
ReadRaw fills content
with the information read from the text file. In case of a failure, the allocated memory of content
is freed.
5. Type the following, which closes the file handle and sets the fileContent
pointer so that the locally created data can be used outside the function. Finally, it returns true
since the reading was successful.
file.
Close
();
*
fileContent
=
content
;
return
true
;
Note
In the example, the caller of
ReadFromExampleFile()
is responsible for freeing the heap memory which has been allocated to store the data from the text file. Thus, after the data has been used, be sure to add the call delete[] fileContent;
.
6. To check if the reading was successful, run the game and check the
Game.log
file.
Complete example code (file reading)
Calling ReadFromExampleFile()
char* fileContent = NULL;
if (!ReadFromExampleFile(&fileContent))
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "ReadFromExampleFile()
failed");
}
else
{
CryLogAlways("ExampleText contains %s", fileContent);
delete[] fileContent;
}
ReadFromExampleFile() implementation bool ReadFromExampleFile(char** fileContent)
Version 1.10
600
Lumberyard Developer Guide
Accessing Files with CryPak
{
CCryFile file;
size_t fileSize = 0;
const char* filename = "examples/exampletext.txt";
char str[1024];
if (!file.Open(filename, "r"))
{
sprintf(str, "Can't open file, (%s)", filename);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "%s", str);
return false;
}
fileSize = file.GetLength();
if (fileSize <= 0)
{
sprintf(str, "File is empty, (%s)", filename);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "%s", str);
return false;
}
char* content = new char[fileSize + 1];
content[fileSize] = '\0';
if (file.ReadRaw(content, fileSize) != fileSize)
{
delete[] content;
sprintf(str, "Can't read file, (%s)", filename);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "%s", str);
return false;
}
file.Close();
*fileContent = content;
return true;
}
Writing a file is similar to the process for reading one. To write to files, you use
CCryFile::Write
, which always writes to the file system and never to
.pak
archives. For information on writing files to archive files, see
Modifying Paks With CryArchive (p. 602)
.
1. Type the following, which contains the if
else
statement that frames the code for writing to a file.
The
WriteToExampleFile()
function write will write the contents of the file and return true
if it succeeds, and false
if not.
char* newContent = "File has been modified";
bool appendToFile = false;
if (!
WriteToExampleFile
(
newContent
,
strlen(newContent)
,
appendToFile
))
{
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "WriteToExampleFile()
failed");
}
else
{
CryLogAlways("Text has been written to file, %s", newContent);
}
•
WriteToExampleFile()
takes the following three parameters:
• newContent
- The text which will be written to
ExampleText.txt
on the file system.
Version 1.10
601
Lumberyard Developer Guide
Accessing Files with CryPak
• strlen(newContent)
- Returns size of newContent
, which is the number of bytes to be written.
• appendToFile
- true
if newContent
will be added to the already existing content; false
if the file will be overwritten.
2. Type the following for the
WriteToExampleFile)
function.
bool
WriteToExampleFile
(char* text, int bytes, bool appendToFile)
{
CCryFile file;
const char* filename = "examples/exampletext.txt";
assert(bytes > 0);
char* mode = NULL;
if (appendToFile)
mode = "a";
else
mode = "w";
char str[1024];
if (!file.Open(filename, mode))
{
sprintf(str, "Can't open file, (%s)", filename);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "%s", str);
return false;
}
[...]
file.Close();
return true;
}
• mode
specifies if the text is to be appended to the existing file or if it will overwrite existing file contents.
"w"
means 'write' to a clean file, and
"a"
means 'append' to the existing file.
3. The final step writes the text to the file and returns the number of bytes written, or an error message if none were written.
int
bytesWritten
= file.
Write
(text, bytes);
assert(bytesWritten == bytes);
if (bytesWritten == 0)
{
sprintf(str, "Can't write to file, (%s)", filename);
CryWarning(VALIDATOR_MODULE_SYSTEM, VALIDATOR_WARNING, "%s", str);
return false;
}
• bytesWritten
tells how many bytes were written by calling the
Write()
function.
This section contains a short example that shows how files are added, updated and removed from an archive. The example intentionally uses the
USER
folder instead of the
GameSDK
folder because the .
pak files inside the
GameSDK
folder are loaded by default at startup and therefore are marked as
Read-Only
.
(Files in the
USER
folder are not loaded by default at startup.)
string pakFilename = PathUtil::AddSlash("
@USER@
") + "Examples.pak";
const char* filename = "Examples/ExampleText.txt";
char* text = "File has been modified by CryArchive";
Version 1.10
602
Lumberyard Developer Guide
Accessing Files with CryPak
unsigned length = strlen(text);
_smart_ptr<ICryArchive> pCryArchive = gEnv->pCryPak->
OpenArchive
(pakFilename.c_str(),
ICryArchive::FLAGS_RELATIVE_PATHS_ONLY |
ICryArchive::FLAGS_CREATE_NEW
);
if (pCryArchive)
{
pCryArchive->
UpdateFile
(filename, text, length, ICryArchive::METHOD_STORE, 0);
}
•
UpdateFile()
- Modifies an existing file inside the
.pak
archive or creates a new one if it does not exist.
•
ICryArchive::FLAGS_CREATE_NEW
- Forces a new
.pak
file to be created. If you want to add (append) files, remove this flag.
• To remove files or folders from an archive, use one of the following commands in place of
UpdateFile()
:
RemoveFile()
,
RemoveDir()
or
RemoveAll()
.
Initialization
To ensure that
.pak
files can be accessed from game code at anytime, the
CrySystem
module initializes
CryPak
in
CSystem::Init
by calling the following functions:
•
InitFileSystem(startupParams.pGameStartup);
•
InitFileSystem_LoadEngineFolders();
Tip
A good spot to test game initialization is in inside
Game.cpp
at the beginning of
CGame::Init
.
Pak file type priorities
Whether CryPak processes files in the file system first, or files in
.pak
files first, depends on the value of pakPriority
. The default value of pakPriority
depends on the configuration settings of your build, but it can also manually be changed by assigning the cvar sys_PakPriority
the values
0, 1, 2 or 3
. The meaning of these values is show in the enum
EPakPriority
:
PakVars.h
enum EPakPriority
{
ePakPriorityFileFirst = 0,
ePakPriorityPakFirst = 1,
ePakPriorityPakOnly = 2,
ePakPriorityFileFirstModsOnly = 3,
};
Pak loading and search priorities
The reason for adding the new pak file to the
GameSDK
folder in this example is because
.pak
files are loaded from the
GameSDK
path first. The loading order and search order of .pak file folders are as follows.
Note that the loading order and the search order are the reverse of each other.
.pak file load order
1.
GameSDK
:
<root>
\GameSDK\*.pak
2.
Engine:
<root>
\Engine\ a.
Engine.pak
Version 1.10
603
Lumberyard Developer Guide
Tracking File Access b.
ShaderCache.pak
c.
ShaderCacheStartup.pak
d.
Shaders.pak
e.
ShadersBin.pak
3. Mods: root\Mods\MyMod\GameSDK\*.pak
(this assumes that you run the game with the command argument
-mod "
MyMod
"
)
.pak file search order
1.
Mods
If more than one mod folder exists, they will be checked in the reverse order in which they were added.
2.
Engine
3.
GameSDK
It's possible to track invalid file reads that occur during game run time. The error message
Invalid File
Access
occurs when an attempt is made to read or open files from a thread that is not the streaming thread. These file access operations can cause stalls that can be quite severe.
Note
Only access attempts from the main thread and render thread are logged. This feature is disabled in RELEASE builds.
The following cvars enable different options for tracking file access.
sys_PakLogInvalidFileAccess
1
(default):
• Access is logged to game.log
.
• Generates a perfHUD
warning.
• The warning is displayed in red in the upper left corner of the screen.
• A 3 second-stall in non-release builds is induced.
sys_PakMessageInvalidFileAccess
• When a file is accessed, creates a popup dialog on the PC. At this point, you can choose to break into the debugger, or continue.
The points which define when a file access attempt is considered invalid are set by implementing
ICryPak::DisableRuntimeFileAccess
to return true or false. The points may need to be tweaked for single player and multiplayer games.
To add exceptions to file access tracking so that you can ignore files like game.log
, create an instance of
CDebugAllowFileAccess
in the scope which accesses the file.
Version 1.10
604
Lumberyard Developer Guide
Where invalid access is defined
The files that you collect with pak_LogInvalidFileAccess 2
must have their callstacks resolved. To do this requires the following tools from the
XenonStackParse
folder of the
Tools
directory.:
• The
.pdb
files from the build
• The
XenonStackParse
tool
• The
ProcessFileAccess.py
helper script
The directory structure for running
ProcessFileAccess.py
should resemble the following:
<Root>
--> XenonStackParse
--> FileAccessLogs (this folder should contain the .pdb files)
------> Processed (this folder contains the output from XenonStackParse)
Run
ProcessFileAccess.py
from the
FileAccessLogs
directory (
XenonStackParse
uses the working directory to search for the
.pdb
files). The script creates a folder called
Processed
and a file within it that contains the resolved callstack for each of the log files.
Version 1.10
605
Lumberyard Developer Guide
Render Nodes
Lumberyard's rendering technology starts with a modern, physically-based shading core that renders materials based on real world physical parameters (such as base color, metalicity, smoothness, and specularity), allowing you to achieve realistic results using the same physically based parameters used in the highest end film rendering pipelines.
The rendering core is supplemented by a rich set of the most frequently used real time lighting, shading, special effects, and post effects features, such as physical lights, global illumination, volumetric fog, procedural weathering, particle systems, dynamic real time shadows, motion blur, bokeh depth of field, post color correction, and more.
Lumberyard's rendering engine is tightly integrated with Lumberyard Editor, so the graphical fidelity and performance achieved in your game is what you see in the editor. Changes made in the editor are instantly reflected in the fully rendered scene, allowing for immediate feedback and rapid iteration.
The Lumberyard rendering technology is designed to take maximum advantage of today's high-end PC and console platforms, while maintaining compatibility with older hardware by scaling down graphical features and fidelity without compromising the core visual elements of your scene.
This section includes the following topics:
•
•
TrueType Font Rendering (p. 610)
•
Generating Stars DAT File (p. 611)
•
Temporal Antialiasing and Supersampling (p. 612)
•
Order-Independent Transparency (p. 616)
•
Building DirectX 12 Supported Applications (p. 618)
To visualize objects in a world, Lumberyard defines the concepts of the render node and render element.
Render nodes represent general objects in the 3D engine. Among other things, they are used to build a hierarchy for visibility culling, allow physics interactions (optional), and rendering.
For actual rendering, render nodes add themselves to the renderer, passing an appropriate render element that implements the actual drawing of the object. This process happens with the help of render objects, as shown in the sample code below
Version 1.10
606
Lumberyard Developer Guide
Creating a New Render Node
The following example creates a render node called
PrismObject
. It is derived from
IRenderNode
, defined in
Code/CryEngine/CryCommon/IEntityRenderState.h
.
1. Add the interface for
IPrismObjectRenderNode
to
CryEngine/CryCommon/IEntityRenderState.h
to make it publicly available.
struct IPrismRenderNode : public IRenderNode
{
...
};
2. Add a new enum to the list of already defined render nodes in
CryEngine/CryCommon/
IEntityRenderState.h
.
enum EERType
{
...
eERType_PrismObject,
...
};
3. Add PrismObjectRenderNode.h to Cry3DEngine.
#ifndef _PRISM_RENDERNODE_
#define _PRISM_RENDERNODE_
#pragma once class CPrismRenderNode : public IPrismRenderNode, public Cry3DEngineBase
{ public:
// interface IPrismRenderNode
...
// interface IRenderNode
virtual void SetMatrix(const Matrix34& mat);
virtual EERType GetRenderNodeType();
virtual const char* GetEntityClassName() const { return "PrismObject"; }
virtual const char* GetName() const;
virtual Vec3 GetPos(bool bWorldOnly = true) const;
virtual bool Render(const SRendParams &rParam);
virtual IPhysicalEntity* GetPhysics() const { return 0; }
virtual void SetPhysics(IPhysicalEntity*) {}
virtual void SetMaterial(IMaterial* pMat) { m_pMaterial = pMat; }
virtual IMaterial* GetMaterial(Vec3* pHitPos = 0) { return m_pMaterial; }
virtual float GetMaxViewDist();
virtual void GetMemoryUsage(ICrySizer* pSizer);
virtual const AABB GetBBox() const { return m_WSBBox; }
virtual void SetBBox( const AABB& WSBBox ) { m_WSBBox = WSBBox; } private:
CPrismRenderNode(); private:
~CPrismRenderNode();
AABB m_WSBBox;
Matrix34 m_mat;
_smart_ptr< IMaterial > m_pMaterial;
CREPrismObject* m_pRE;
Version 1.10
607
Lumberyard Developer Guide
Creating a New Render Node
};
#endif // #ifndef _PRISM_RENDERNODE_
4. Add PrismObjectRenderNode.cpp to Cry3DEngine.
#include "StdAfx.h"
#include "PrismRenderNode.h"
CPrismRenderNode::CPrismRenderNode() :m_pMaterial(0)
{
m_mat.SetIdentity();
m_WSBBox = AABB(Vec3(-1, -1, -1), Vec3(1, 1, 1));
m_pRE = (CREPrismObject*) GetRenderer()->EF_CreateRE(eDATA_PrismObject);
m_dwRndFlags |= ERF_CASTSHADOWMAPS | ERF_HAS_CASTSHADOWMAPS;
}
CPrismRenderNode::~CPrismRenderNode()
{
if (m_pRE)
m_pRE->Release(false);
Get3DEngine()->FreeRenderNodeState(this);
} void CPrismRenderNode::SetMatrix(const Matrix34& mat)
{
m_mat = mat;
m_WSBBox.SetTransformedAABB(mat, AABB(Vec3(-1, -1, -1), Vec3(1, 1, 1)));
Get3DEngine()->RegisterEntity(this);
} const char* CPrismRenderNode::GetName() const
{
return "PrismObject";
} void CPrismRenderNode::Render(const SRendParams& rParam, const SRenderingPassInfo
&passInfo)
{
FUNCTION_PROFILER_3DENGINE;
if(!m_pMaterial)
return;
// create temp render node to submit this prism object to the renderer
CRenderObject *pRO = GetRenderer()-
>EF_GetObject_Temp(passInfo.ThreadID()); // pointer could be cached
if(pRO)
{
// set basic render object properties
pRO->m_II.m_Matrix = m_mat;
pRO->m_ObjFlags |= FOB_TRANS_MASK;
pRO->m_fSort = 0;
pRO->m_fDistance = rParam.fDistance;
// transform camera into object space
const CCamera& cam(passInfo.GetCamera());
Vec3 viewerPosWS(cam.GetPosition());
// set render object properties
m_pRE->m_center = m_mat.GetTranslation();
Version 1.10
608
Lumberyard Developer Guide
Creating a New Render Node
SShaderItem& shaderItem(m_pMaterial->GetShaderItem(0));
GetRenderer()->EF_AddEf(m_pRE, shaderItem, pRO, passInfo,
EFSLIST_GENERAL, 0, SRendItemSorter(rParam.rendItemSorter));
}
} void CPrismRenderNode::GetMemoryUsage(ICrySizer* pSizer) const
{
SIZER_COMPONENT_NAME(pSizer, "PrismRenderNode");
pSizer->AddObject(this, sizeof(*this));
} void CPrismRenderNode::OffsetPosition(const Vec3& delta)
{
if (m_pRNTmpData) m_pRNTmpData->OffsetPosition(delta);
m_WSBBox.Move(delta);
m_mat.SetTranslation(m_mat.GetTranslation() + delta);
if (m_pRE) m_pRE->m_center += delta;
} void CPrismRenderNode::FillBBox(AABB & aabb)
{
aabb = CPrismRenderNode::GetBBox();
}
EERType CPrismRenderNode::GetRenderNodeType()
{
return eERType_PrismObject;
} float CPrismRenderNode::GetMaxViewDist()
{
return 1000.0f;
}
Vec3 CPrismRenderNode::GetPos(bool bWorldOnly) const
{
return m_mat.GetTranslation();
}
IMaterial* CPrismRenderNode::GetMaterial(Vec3* pHitPos)
{
return m_pMaterial;
}
5. To allow client code to create an instance of the new render node, extend the following function in
/
Code/CryEngine/Cry3DEngine/3DEngine.cpp
...
#include "PrismRenderNode.h"
...
IRenderNode * C3DEngine::CreateRenderNode(EERType type)
{
switch (type)
{
...
case eERType_PrismObject:
{
IPrismRenderNode* pRenderNode = new CPrismRenderNode();
return pRenderNode;
}
...
Version 1.10
609
Lumberyard Developer Guide
TrueType Font Rendering
CryFont is used to generate font textures that are required to render text on the screen. The various features of font rendering can be seen by using the r_DebugFontRendering
console variable.
The output is not only to test the functionality but also to document how the features can be used.
CryFont supports the following features:
• Font shaders – Used to configure the appearance of fonts. Multiple passes with configurable offset and color are supported to enable generation of shadows or outlines. A sample font shader is shown in the following XML example.
<fontshader>
<font path="VeraMono.ttf" w="288" h="416"/>
<effect name="default">
<pass>
<color r="0" g="0" b="0" a="1"/>
<pos x="1" y="1"/>
</pass>
</effect>
<effect name="console">
<pass>
<color r="0" g="0" b="0" a="0.5"/>
<pos x="2" y="2"/>
</pass>
</effect>
</fontshader>
The attributes
w
and
h
of the XML font element specify the width and height of the font texture.
The order of the passes in XML defines the order in which the passes are rendered. A
<pass>
element without child elements means that the pass is rendered with the default settings. The
<pos>
tag is used to offset the font, while the
<color>
tag is used to set font color and define the transparency
(with the alpha channel
a
).
• Unicode – The default font used does not support all Unicode characters (to save memory), but other fonts can be used.
• TrueType fonts as source – Cached in a small texture. Common characters are pre-cached, but runtime updates are possible and supported.
• Colored text rendering
• Adjustable transparency
• Color variations within a string – Use a value of
$0..9
to set one of the 10 available colors. Use
$$
to print the $ symbol, and
$o
to switch off the feature.
• Returns and tabs within a string
• Text alignment
• Computation of a string's width and height – Used internally to handle center and right alignment.
• Font size variations – Bilinear filtering allows some blurring, but no mipmaps are used so this feature has limitations in minification.
• Proportional and monospace fonts
• Pixel-perfect rendering with exact texel-to-pixel mapping for best quality.
Version 1.10
610
Lumberyard Developer Guide
Useful Console Commands
The following console commands provide information about font rendering.
r_DebugFontRendering
Provides information on various font rendering features, useful for verifying function and documenting usage.
• 0=off
• 1=display
r_DumpFontNames
Logs a list of fonts currently loaded.
r_DumpFontTexture
Dumps the texture of a specified font to a bitmap file. You can use r_DumpFontTexture
to get the loaded font names.
The Stars DAT file contains star data that is used in sky rendering. This topic provides information you'll need if you want to modify the data in this file. It assumes you have some familiarity with generating binary files.
Star data is located in
Build\Engine\EngineAssets\Sky\stars.dat
. This data is loaded in the function
CStars::LoadData
, implemented in the file
CRESky.cpp
.
The Stars DAT file uses a simple binary format; it can be easily modified using an editing tool. The file starts with a header, followed by entries for each star. The header specifies the number of entries in the file.
All types stored in little-endian format, float32 in IEEE-754 format.
Star data provided in the SDK is based on real-world information. Typically, you can also use existing star catalogs to populate this information for you.
The file elements are as follows:
Header (12 bytes)
Name
Tag
Version
NumStars
Offset
0
4
8
Type
uint32 uint32 uint32
Value
0x52415453 (ASCII: STAR)
0x00010001
Number of star entries in the file
Entry (12 bytes)
Name Offset
RightAscension
0
Type
float32
Version 1.10
611
Value
in radians
Name
Declination
Red
Green
Blue
Magnitude
Offset
4
8
9
10
11
Lumberyard Developer Guide
Temporal Antialiasing and Supersampling
Type
float32 uint8 uint8 uint8 uint8
Value
in radians star color, red channel star color, green channel star color, blue channel brightness, normalized range
Supersampling is a method of antialiasing that attempts to reduce jagged, pixelated edges (aliasing) in images. It works by sampling a higher resolution version of the image to get the average color of a pixel before reducing it to the intended size. The averaged color values create smoother transitions along an edge of colors, reducing the jagged look.
Because supersampling is memory intensive, Lumberyard uses temporal antialiasing (TAA) to approximate supersampling. While supersampling analyzes pixels spatially, TAA analyzes frames over time, even when the camera is static. The current frame is projected onto the previous frame and samples are blended into an accumulation buffer. This technique reduces ghosting artifacts in motion and gives you control over the amount of antialiasing needed for your graphics. You can create sharp images or softer, blurred images. You can also use supersampling for very high quality rendering.
TAA is useful for reducing aliasing from the following:
• Specular highlights and bright pixels, especially when combined with convolution filters such as
Depth of Field
or
Bloom
.
• Geometric and alpha-tested edges.
You can configure TAA by setting the r_AntialiasingMode
console variable, editing the platform configuration file, or creating a level configuration file with this setting.
The following table lists the antialiasing modes that are available in Lumberyard when you use the r_AntialiasingMode
console variable.
Mode
No antialiasing
FXAA
SMAA (1TX)
Console Variable
Value
0
1
2
Description
Disables postprocessing-based antialiasing. This is useful for debugging or when the technique is unnecessary. You may also use a higher resolution if you prefer not to spend system resources on antialiasing.
Enables fast approximate antialiasing (FXAA), which filters edges using a postprocessing edge detection technique.
Enables subpixel morphological antialiasing (SMAA), which uses an advanced postprocessing technique to detect edges
Version 1.10
612
Lumberyard Developer Guide
Controlling Antialiasing
Mode
TAA
Console Variable
Value
Description
3 in order to filter edges. This mode includes a basic temporal antialiasing component but does not address subpixel jitter.
Enables temporal antialiasing (TAA). This is the default mode.
The following table lists the additional console variables that you can configure for temporal antialiasing.
Console Variable
r_AntialiasingModeEditor r_AntialiasingTAAClampingFactor r_AntialiasingTAAJitterPattern r_AntialiasingTAALuminanceMax r_AntialiasingTAAMotionDifferenceMax r_AntialiasingTAAMotionDifferenceMaxWeight
Description
Specifies whether to use subpixel jitter in the editor. This can eliminate jittering artifacts on helper objects at the expense of losing antialiasing on static scenes.
Valid values: 0 = disables this mode | 1 = enables this mode
Controls the clamping factor in standard deviations. Set the value at which to limit the
TAA response. Higher values create a more stable scene with less flickering but more ghosting.
Lower values create a scene with less ghosting but more aliasing and flickering.
Valid values: 0.75 – 2.0
Specifies the sampling pattern for temporal antialiasing.
Valid values: 0 = no subsamples | 1 = 2x | 2 = 3x | 3
= 4x | 4 = 8x | 5 = sparse grid, 8x8 | 6 = random | 7
= Halton 8x (default) | 8 = Halton random
Clamps the input luminance before temporal filtering to help with image stability. Extra bright pixels can ghost and cause bloom artifacts.
Default value: 100.0
Specifies the maximum difference of speed between the current pixel and its history pixel at which the current pixel is considered fully disoccluded. Lower values create a scene with less ghosting but more aliasing on disoccluded pixels.
Specifies the blend weight for the current frame at the maximum speed difference (defined by the r_AntialiasingTAAMotionDifferenceMax
console variable).
Valid values: 0 = 100% of the history pixel | 1 =
100% of the current pixel
Version 1.10
613
Lumberyard Developer Guide
Controlling Antialiasing
Console Variable
r_AntialiasingTAANewFrameFalloff r_AntialiasingTAASharpening r_AntialiasingTAAUseAntiFlickerFilter r_AntialiasingTAAUseJitterMipBias r_AntialiasingTAAUseVarianceClamping
Description
Default value: 0.5
Represents the amount of time, in seconds, for the history signal to reach 63% of the source signal. Lower values create faster convergence, which can reduce ghosting but introduce some aliasing. Higher values create slower convergence.
Because higher values may not improve stability, you should adjust the color clamping factor before adjusting this value.
Default value: 0.15
Controls the sharpening filter to help retain sharpness. This is useful when temporal antialiasing introduces blur to a scene during motion.
Default value: 0.2
Reduces jitter-based flickering in certain scenarios.
Valid values: 0 = disables this mode | 1 = enables this mode
Enables mipmap biasing on textures when jitter is enabled. This creates a scene with decreased blur but more flickering.
Valid values: 0 = disables this mode | 1 = enables this mode
Default value: 1
Enables variance color clamping to help reduce ghosting. This may increase flickering in the scene.
The r_AntialiasingTAAClampingFactor
console variable affects only this mode.
Valid values: 0 = disables this mode | 1 = enables this mode
Default value: 0
The following images illustrate the range of graphics quality that you can achieve depending on which antialiasing setting you use.
Version 1.10
614
Lumberyard Developer Guide
Temporal Antialiasing Limitations
Temporal antialiasing (TAA) is an inexpensive solution that reduces aliasing from all sources and works well with most content. Because it relies on screen-space information from previous frames, TAA has limitations in the following scenarios:
• Objects occlude other objects while in motion. In this scenario, the newly visible areas in the current frame don't have a history value to blend with and can manifest as ghosting.
• Motion vectors are not present for objects in motion, which can result in subtle smearing artifacts.
Motion vectors are not generated for merged vegetation, non-CGF-based particles, or transparent materials. In certain high-frequency signal scenarios, the most apparent artifact is flickering caused by subpixel jittering that alternates between bright and dark pixels.
• The content has a lot of subpixel triangles and normals. In this scenario, the subpixel detail can cause flickering artifacts with temporal subpixel jittering. When a bright edge that is surrounded by dark pixels becomes smaller, the neighborhood clamping heuristic causes the pixels to flicker between light and dark.
• Transparency does not write depth. In this scenario, certain transparent content can exhibit subtle smearing artifacts.
In these cases, you may prefer to use subpixel morphological antialiasing (SMAA) or fast approximate antialiasing (FXAA).
We recommend following these best practices when using temporal antialiasing (TAA).
• Build content to alias as little as possible.
• Use level of detail (LOD) to reduce subpixel detail for objects that are far away.
• Use the antiflicker filter to help with flickering. The r_AntialiasingTAAUseAntiFlickerFilter
console variable is enabled by default.
Version 1.10
615
Lumberyard Developer Guide
Controlling Supersampling
In addition to antialiasing, Lumberyard supports supersampling for very high quality rendering.
Supersampling renders the scene at a higher resolution and downscales the image to obtain smooth and stable edges. Due to the high internal rendering resolution, supersampling is performance heavy and only suitable for games intended to be played on high-end computers.
Order-independent transparency (OIT) corrects the display of transparent objects that are drawn out of order.
OIT is useful when creating the following:
Version 1.10
616
Lumberyard Developer Guide
Configuring Order-Independent
Transparency for Lumberyard
• Concave geometry – When you create concave geometry, such as a glass, wine glass, or glass sculpture, some triangles may cover the same pixels and are drawn on top of each other. OIT solves the out-oforder issues that appear from certain angles.
• Intersecting geometry – When you create intersecting geometry, such as hair planes, some triangles may intersect in separate draws. OIT properly orders the triangles for each pixel.
• Transparent objects inside transparent objects – This includes liquids inside of glasses, holograms, or xray style effects.
To further demonstrate, see the following images.
OIT is not needed in the following example.
Drawing object 1, then object 2, and finally object 3 works.
OIT is needed in the following example.
Drawing object 1 and then object 2 will not work because certain pixels from object 1 must be in front of pixels from object 2
(and vice versa).
OIT is needed in the following example.
Object 2 is long and its center point is in front of object 1, but it must draw behind object 1.
OIT is needed in the following example.
Certain parts of object
1 draw behind other parts of the object, and you cannot control which draws first.
You can configure OIT by setting the r_AlphaBlendLayerCount
console variable or creating a level configuration file with this setting.
Version 1.10
617
Lumberyard Developer Guide
Building DirectX 12 Supported Applications
Note
OIT requires the following:
• Hardware requirements: DirectX 12_1 feature level compatible graphics card (Nvidia Maxwell
& Pascal, 4th generation Intel core processors)
• Software requirements: DirectX 11.3 and 12 runtime on Windows 10 SDK
To configure OIT using the console variable
1. In Lumberyard Editor, in the
Console
pane, click the icon in the left corner to open the
Console
Variables
window. For more information, see Using the Console Window in the
Amazon Lumberyard
User Guide
.
2. In the
Console Variables
window, search for r_AlphaBlendLayerCount
.
3. Specify the number of transparency layers that OIT can solve. A value of 1 is sufficient to solve most out-of-order transparency issues.
Valid values: 0 – 4
0 = disables OIT
4. Close the
Console Variables
window.
To configure OIT using a level configuration file
1. Go to the
\dev\
<project_name>
\Levels\
<level_name>
directory at the root of your Lumberyard installation.
2. Use a text editor to create a level.cfg
file or edit an existing level.cfg
file.
3. Specify the value for r_AlphaBlendLayerCount
to the number of transparency layers that OIT can solve. A value of 1 is sufficient to solve most out-of-order transparency issues.
Valid values: 0 – 4
0 = disables OIT
For example, to turn on one layer of OIT, add the following to the level.cfg
file: r_AlphaBlendLayerCount=1
4. Save the level.cfg
file.
Lumberyard includes a preview of DirectX 12, which provides the framework for you to build DirectX 12 supported applications and develop DirectX 12 features. DirectX 12 provides the following benefits for developing applications:
• Slightly faster overall GPU performance on Nvidia cards
• Slight increase in frame rate for scenes that are GPU-bound
• Supported features from DirectX 12 and DirectX 11.3 including the following:
• Rasterizer-ordered view with order independent transparency
• Tiled resources that allow you to develop textures virtually that you can then use on terrain
• Optimized texture streaming
Version 1.10
618
Lumberyard Developer Guide
Building DirectX 12 Supported Applications
• Conservative rasterization helps you develop and optimize ray tracing or voxel rendering, which you can use to develop certain rendering techniques such as global illumination (GI).
Based on your scene, you may discover faster or slower performance across DirectX 11 and DirectX 12.
For example, if you enable DirectX 12 you may see a slight performance degradation with CPU-bound scenes. Scenes with high draw calls may also see slower performance depending on the size of the scene and view distance.
For more information about DirectX 12, see Taking Advantage of DirectX 11.2 Tiled Resources and Don't
Be Conservative with Conservative Rasterization .
To enable DirectX 12 rendering in Lumberyard
1. On Windows 10, install the latest Windows 10 SDK in Visual Studio 2015.
2. (For monolithic builds only) Build your Lumberyard project by doing one of the following:
• Edit the user_settings.options
file (located in the
\lumberyard\dev\_WAF_
directory) to set win_build_renderer
lmbr_waf configure
.
to
DX12
under the
[Build Options]
section. In a command line window, type
• In a command line window, type
lmbr_waf configure --win-build-renderer=DX12
.
3. Edit the system_windows_pc.cfg
file to set r_Driver
to
DX12
.
4. Start your game using the launcher.
Version 1.10
619
Lumberyard Developer Guide
Learning Lua
You can use Lua in Lumberyard to facilitate quick iteration of your game project. Lua is a powerful, fast, lightweight, embeddable scripting language. When you construct new gameplay and game systems, you can run your changes immediately, without compiling your source code.
For learning the Lua language itself, the lua.org
website is a good place to start.
• Official Lua Documentation – Provides a central location for information about Lua, including a
Getting started page.
• Programming in Lua – This text is a resource for getting started with Lua programming.
• Lua 5.1 Reference Manual – Provides a reference of all the functions that are available by default in
Lua.
After you read through this tutorial on writing Lua scripts for the component entity system, learn more about using Lua in Lumberyard by consulting the following resources.
• For information on Lumberyard's built-in Lua editor, see
• For sample Lua scripts, see the Lumberyard
\dev\SamplesProject\Scripts
directory and its subdirectories.
• For information about Lua API operations in Lumberyard, see the Component Entity Lua API
Reference .
Version 1.10
620
Lumberyard Developer Guide
Adding Lua Scripts to Component Entities
• For information about the Lumberyard EBus, see Event Bus (EBus) (p. 576) .
Note
Starting with Lumberyard 1.8, Lua scripts use the new behavior context that replaces the legacy script context. Scripts that were written before the integration of the behavior context no longer work in Lumberyard versions 1.8 and later. For information on updating code from legacy script context to the new behavior context, see the migration notes for Lumberyard 1.8
. For
information on the behavior context, see Behavior Context (p. 480)
.
Lumberyard makes it easy for you to add script functionality to your game entities by using the
Lua
Script
component. The following steps show you how to do this in Lumberyard Editor.
To add a Lua script to a component entity in Lumberyard Editor
1. With the
Entity Inspector
view pane visible, select the entity in the viewport.
2. Click
Add Component
, and then open
Scripting
,
Lua Script
.
3. Scroll down to the
Scripting
section, and then click
Lua Script
.
Version 1.10
621
Lumberyard Developer Guide
Basic Structure of a Component Entity Lua Script
4. A
Lua Script
component appears in the inspector. Use the file selection button (
...
) to select the Lua script from the file hierarchy that you want to use.
You can select either a
.lua
file (a text copy of the original), or a
.luac
file (a precompiled version of the script). The functionality should be the same. The precompiled version is preferable because it loads faster and is usually smaller. However, you can use
.lua
files if you experience any issues.
5. After the script is loaded, click
Edit Script
(
{}
) to launch the Lua IDE and make changes to your script.
Scripts to be used as components contain a table (referred to as the script table), which provides the functionality for the script. In Lua, this table is treated like a class. The script table generally consists of the following:
• An optional
Properties
table within the script table. The
Properties
table provides an interface that you can use to customize the script behavior from the editor.
• An
OnActivate()
function that the engine calls when the entity that has the script is activated.
• An
OnDeactivate()
function called by the engine when the entity that has the script is deactivated.
The following example shows a skeleton script.
-- ScriptName.lua local ScriptName =
{
Properties =
{
-- Property definitions
}
}
Version 1.10
622
Lumberyard Developer Guide
Built-in Types and Methods function ScriptName:OnActivate()
-- Activation Code end function ScriptName:OnDeactivate()
-- Deactivation Code end return ScriptName
For each Lua script component, Lumberyard creates a table called the entity table. The script table in the referenced script is the metatable for the entity table. Because of this relationship, when any method in the script is called, the self parameter (implicit in most cases) refers to the entity table.
The entity table then has the following properties and methods available to it:
• A
Properties
table, copied from the script table's
Properties
table. Default values are provided where appropriate.
• An entityId
property, which contains an object of type
EntityId
that refers to the current entity.
• An
IsMaster
function, callable by the script, to check whether the currently executing script is on the master node or a proxy node. This function is available only if the script component is network enabled.
The Lumberyard engine provides a number of types and methods that are useful for making games.
Many of the types and methods available are listed in the class view available in Lumberyard's Lua IDE.
For more information on the class view, see Lua Editor .
The
Properties
table configures the editor interface for customizing the behavior of a script. With the properties table, users can modify numeric values, select states, and turn flags on and off. The table can even provide a reference to entities that your script can interact with.
The properties inside the
Properties
table are exposed to the editor. Properties outside the
Properties table are private and not displayed in the editor.
The following example is a properties table from the
Controllable Chicken
sample level.
-- Example Properties Table local ChickenMannequinControllerSM =
{
Properties =
{
MoveSpeed = { default = 3.0, description = "How fast the chicken moves.", suffix =
" m/s" },
RotationSpeed = { default = 360.0, description = "How fast (in degrees per second)
the chicken can turn.", suffix = " deg/sec"},
CameraFollowDistance = {default = 5.0, description = "Distance (in meters) from
which camera follows character."},
CameraFollowHeight = {default = 1.0, description = "Height (in meters) from which
camera follows character."},
CameraLerpSpeed = {default = 5.0, description = "Coefficient for how tightly camera
follows character."},
Camera = { default = EntityId() },
Version 1.10
623
Lumberyard Developer Guide
Supported Types
InitialState = "Idle",
DebugStateMachine = false,
},
...
The result is the following
Properties
user interface in Lumberyard Editor:
The type that you provide as the default value determines how the property is appears in the editor user interface. You can further customize the representation of the property in the editor by specifying additional attributes in a table format. All property types support a description field that appears when you pause your mouse on the property name in the editor.
Properties can have the types described in this section.
The following examples are Boolean values.
DebugMovement = false,
AllowMovement = { default = true, description = "Allow or restrict movement of the
object." },
In Lumberyard Editor, Boolean values are represented by a check box.
The following examples are numeric values.
Count = 5,
Velocity = { default = 1.0, suffix = "m/s", description = "Initial Velocity Of The
Object" },
Distance = { default = 5.0, min = 2.0, max = 10.0, step = 2.0, suffix = "m", description =
"The Distance An Object Can Travel In Meters" },
In Lumberyard Editor, numeric values are represented by an edit field with increase/decrease arrows.
Numeric values can do the following:
• Provide a custom suffix to indicate units.
Version 1.10
624
Lumberyard Developer Guide
Supported Types
• Set minimum and maximum values.
• Provide a step value (how much the value increases or decreases when the user clicks the arrows on the right side of the edit field).
The following examples are strings.
DebugPrefix = "d_",
Name = { default = "Default Name", description = "The name of the entity" },
StartingState = { "Idle", description = "Specify the starting state. Valid starting states
are Idle and Fidget" },
In Lumberyard Editor, string values are represented by a text edit box.
You can use any class that is reflected to both the
BehaviorContext
and the
EditContext
as a property. A good example of this is the
EntityId
type, which references other entities.
-- Entity Examples
ParentEntity = { default = EntityId(), description = "The Entity that this one will
follow"},
Target = EntityId()
The editor representation is the default editor for the type reflected. For example, for
EntityId
, it's the entity reference picker. For most reflected types, it is a tree of the type's properties.
Properties can contain resizable arrays of any of the types mentioned. To create the array, declare the default value as a keyless table of values. For example, the property definitions in the following code produce the properties shown in the image that follows.
local ExampleScript = {
Properties = {
Speed = 4,
ExampleArray = { default = { 1, 2, 3, 4 } },
}
} return ExampleScript
Version 1.10
625
Lumberyard Developer Guide
Attributes
You can add attributes to a property by placing them alongside the default value in a property table.
Attribute keys are not case sensitive. The following common attributes can be added to any property.
Common Attributes
AttributeDescription
UI
Specifies (overrides) the UI handler that the property uses.
For network binding features to function, you must have a Net Binding Component (p. 1054)
.
You can configure networking binding for properties by adding the netSynched
table to the description of the variable inside of the
Properties
table.
local ExampleScript = {
Properties = {
Speed = {
default = 0, -- Supports numbers, strings, booleans, and nils for net
bindings.
min = 0,
max = 100,
step = 1,
description = "Speed in m/s for the ...",
-- If this table is missing, it is assumed the value is not networked.
netSynched
=
{
-- Optional fields
OnNewValue = <function> -- OnNewValue is called whenever the property has a
-- new value. OnNewValue accepts one
parameter,which
-- is the entity table for the instance that
changed.
-- The following flags are mainly here for debugging and profiling
convenience.
Enabled = true -- Controls whether the field is network enabled.
If
-- missing, assumes true.
ForceIndex = [1..32] -- Profiling helper tool to force a property to use
a
-- specific DataSet to make understanding what data
is
-- being used where easier.
}``
}
}
} return ExampleScript
Version 1.10
626
Lumberyard Developer Guide
RPCs
After you add networking to a property, any changes to the property are reflected across the network.
Exposing RPCs to scripts involves creating a new table inside of the component table, but outside of the properties table, as shown in the following example.
local ExampleScript = {
Properties = {
-- ...
},
-- Table of remote procedure calls (RPCs) that the script wants to implement.
NetRPCs
=
{
RPCNoParam = {
OnMaster = <function> -- The function to be called on the Master Script.
-- The function should return a bool value that
-- indicates whether or not proxy components can
-- execute the RPC on themselves. Required.
OnProxy = <function> -- The function to be called on the Proxy Script.
-- This function is optional and can be excluded if
-- the master never allows proxies to execute the
function call.
}
}
} return ExampleScript
You can invoke the RPC just like any other function. There is no need to specify the
OnMaster/OnProxy from the calling script. For example, you can call RPCs as in the following example.
self.NetRPCs.RPCNoParam() self.NetRPCs.RPCParam(1.0)
Components provide interfaces that allow scripts to send them information and receive notifications when certain actions take place. Communication is established by creating two different objects in Lua: senders and handlers. A sender or a handler is an interface to an Event Bus (EBus) , a communication system used extensively in the Lumberyard Engine. When a sender is created, it can call functions, which in turn send information to a component. When a handler is created, the component calls certain functions that the Lua script defines. These senders and handlers are created with an entity ID. You can use the entity ID to communicate with components that are attached to entities other than the one the script itself is running on. The main script table always provides a field called entityId
that contains the
ID of the entity to which the script is attached. Other entity IDs can be passed to the script through the
Properties
interface.
Keep in mind the following points regarding the order of activation of Lua components:
• Lua components are activated after all C++ components have been activated.
• If an entity has multiple Lua components, there is no guarantee regarding which Lua component is activated first.
Version 1.10
627
Lumberyard Developer Guide
Registering with a Component to Receive Notifications
When a Lua script creates a handler object, it notifies a component attached to an entity that it should call the script handler functions when certain events occur. For example, in the first sample below, the script creates a Spawner Component notification bus handler when
OnActivate()
is called. This tells the spawner component attached to the entity that has the script to call the
OnSpawnBegin()
,
OnSpawnEnd()
, and
OnEntitySpawned()
functions when the spawner instantiates a new dynamic slice . Subsequently, the handler is explicitly disconnected and set back to nil in the
OnDeactivate
function. This ensures that processing time is not wasted when the entity attached to the script isn't active. As long as the entity is active, these functions are called by the spawner component at the appropriate time.
The following code example shows a spawner component handler.
local SpawnerScriptSample = { } function SpawnerScriptSample:OnActivate()
-- Register our handlers to receive notification from the spawner attached to this
entity.
if( self.spawnerNotiBusHandler == nil ) then
self.spawnerNotiBusHandler = SpawnerComponentNotificationBus.CreateHandler(self,
self.entityId)
end end
-- This handler is called when we start spawning a slice.
function SpawnerScriptSample:OnSpawnBegin(sliceTicket)
-- Do something so we know if/when this is being called
Debug.Log("Slice Spawn Begin") end
-- This handler is called when we're finished spawning a slice.
function SpawnerScriptSample:OnSpawnEnd(sliceTicket)
-- Do something so we know if/when this is being called
Debug.Log("Slice Spawn End") end
-- This handler is called whenever an entity is spawned.
function SpawnerScriptSample:OnEntitySpawned(sliceTicket, entityId)
-- Do something so we know if/when this is being called
Debug.Log("Entity Spawned: " .. tostring(entityId) ) end function SpawnerScriptSample:OnDeactivate()
-- Disconnect our spawner notificaton
if self.spawnerNotiBusHandler ~= nil then
self.spawnerNotiBusHandler:Disconnect()
self.spawnerNotiBusHandler = nil
end end return SpawnerScriptSample
There are event buses that are available to Lua that are not associated with components. For example, a script can create a handler to receive notifications from the system's tick bus whenever the engine ticks. It provides both the amount of time that has passed since the last tick and the current time point.
To gain access to this information, the script simply implements the
OnTick()
function and creates the handler.
Version 1.10
628
Lumberyard Developer Guide
Sending Events to a Component
The following example shows how to register an EBus.
local TestScript = { } function TestScript:OnActivate()
-- Inform the tick bus that you want to receive event notifications
self.tickBusHandler = TickBus.CreateHandler(self)
self.tickBusHandler:Connect() end
-- This callback is called every frame by the tick bus after this entity activates function TestScript:OnTick(deltaTime, timePoint)
-- Add script to be executed every frame here...
end function TestScript:OnDeactivate()
-- Inform the tick bus that you no longer want to receive notifications
self.tickBusHandler:Disconnect() end return TestScript
In addition to receiving notifications from components, a script must sometimes exercise control over components. Control is accomplished by sending events to components using the
Event
table and calling the functions implemented on it. In the example script that follows, the spawner component is sent an event that tells the component to spawn a dynamic slice by calling the
Spawn()
function. The first argument to an
Event
function is always the ID of the listener that you send the event to; the remaining arguments follow.
The following example shows how to send EBus events.
local SpawnerScript = { } function SpawnerScript:OnActivate()
SpawnerComponentRequestBus.Event.Spawn(self.entityId) end return SpawnerScript
You can request information from some event sending functions that return values. The next example script uses a
TransformBus
to get the current local transform of the entity and uses the
GetLocalTM() function, which returns a transform object. This object is stored in a variable in the main script table.
TransformBus
is used again to reset the transform of the object to the identity.
The following example shows how to use the transform bus.
function samplescript:OnActivate()
-- Retrieve the object's local transform and store it for later use
self.myOldTransform = TransformBus.Event.GetLocalTM(self.entityId)
-- Reset the object's local transform to the identity matrix
TransformBus.Event.SetLocalTM(self.entityId, Transform.CreateIdentity()) end
Version 1.10
629
Lumberyard Developer Guide
Communicating with Components
Attached to Other Entities
You can also send events and create handlers to communicate with components that are attached to other entities. The following example defines a parent entity in the properties table and requests its transform. This allows it to set its transform to that of another entity.
The following example code shows the use of a parent entity.
local ParentScriptSample=
{
Properties =
{
ParentEntity = { entity="" },
}
} function ParentScriptSample:OnActivate()
if self.Properties.ParentEntity.IsValid() then
local parentTransform = TransformBus.Event.GetLocalTM(self.Properties.ParentEntity)
TransformBus.Event.SetLocalTM(self.entityId, parentTransform)
end end return ParentScriptSample
Vectors and arrays in Lua behave very simarly to tables, with a few limitations. Both vector and array have the following features.
Length Operator
#
You can obtain the length of a collection by prefixing the name of the collection with the length operator
#
, as in the following example.
#myCollection
Indexing []
To obtain the elements in a collection, use indexing in square brackets as the following syntax shows.
Indexing is 1 based, just like Lua tables.
myCollection[index]
Vector
also has the following methods for mutating the collection.
push_back
Use the push_back
method to append elements to the vector, as in the following example.
myCollection:push_back(5)
pop_back
Use the pop_back
method to remove the last element of the vector, as in the following example.
Version 1.10
630
Lumberyard Developer Guide
Using AZStd::any myCollection:pop_back()
clear
Use the clear
method to remove all elements from the vector, as in the following example.
myCollection:clear()
You can pass any Lua primitive type excluding tables to any bus or function that takes
AZStd::any as a parameter (for example,
GameplayNotificationBus::OnEventBegin
). You can also pass any type reflected from C++ (for example, vectors or
EntityId
values). There is no syntax required to pass a value as an any
—just call the bus or function.
The following example shows the use of
AZStd::any
.
GameplayNotificationBus.Broadcast.OnEventBegin(self.eventId, "The value I'd like to pass to
the handler")
Lumberyard provides Lua scripts with several functions to make debugging easier.
To print text to the Lumberyard Editor and game console, use the
Debug.Log()
function.
The following example shows the use of the
Debug.Log()
function.
local LoggingTest = { } function LoggingTest:OnActivate()
componentName = "MyComponent"
Debug.Log
(ComponentName .. " has been activated.") end return LoggingTest
You can use the assert()
or
Debug.Assert()
functions to display an error message in the console when conditions are detected that might result in an execution fault. The assert functions take two arguments: a condition that evaluates to true or false, and a message to display if the condition is false.
The following example shows the use of the assert
and
Debug.Assert()
functions.
function SampleScript:DoStuff()
-- This value should never be negative
assert
( self.positiveValue >= 0, "Expected a positive value! Got: " ..
self.positiveValue ) end
-- Console output when the value of self.positiveValue is -5:
-- [Error] Lua error (2 - [string "q:/lyengine/branches/systems/dev/samplespro..."]:61:
Expected a positive value! Got: -5) during call samplescript:DoStuff
Version 1.10
631
Lumberyard Developer Guide
Communicating Errors
-- ALTERNATIVE SYNTAX: function SampleScript:DoStuff()
-- This value should never be negative
Debug.Assert
( self.positiveValue >= 0, "Expected a positive value! Got: " ..
self.positiveValue ) end
-- Console output when the value of self.positiveValue is -5:
-- [Error] Assert on argument 0: Expected a positive value! Got: -5
You can use the
Debug.Error()
function to display an error in the console and halt execution of the current script function. This does not halt all execution of the script. If you have active handlers, they can still be called when the engine posts notifications. The
Debug.Error()
function takes arguments similar to the
Debug.Assert
function: a condition and a message. The message is displayed in bright red and execution halts only if the condition is false.
The following example shows the use of the
Debug.Error()
function.
function SampleScript:CheckAndError()
-- This value should never be negative
Debug.Error
( self.positiveValue >= 0, "Detected a negative value: " ..
self.positiveValue ) end
-- Console output when the value of self.positiveValue is -5:
-- [Error] Error on argument 0: Detected a negative value: -5
A script condition can occur that does not adversely affect the execution of the script but might be useful for the user to know about. The
Debug.Warning()
function uses arguments similar to those of the
Error
and
Assert
functions but just displays an orange warning message in the console. It does not halt execution.
The following example shows the use of the
Debug.Warning()
function.
function SampleScript:CheckValue()
-- This value should probably never be negative
Debug.Warning
( self.positiveValue >= 0, "Detected a negative value: " ..
self.positiveValue ) end
-- Console output when the value of self.positiveValue is -5:
-- [Warning] Warning on argument 0: Detected a negative value: -5
By default, the Lumberyard component entity Lua environment is a single Lua environment
(or lua_State
). This environment is bound to the
BehaviorContext
that is owned by the
ComponentApplication
. Because of this, it has access to all API operations that are reflected on startup.
Version 1.10
632
Lumberyard Developer Guide
Adding Other VMs
You may add more
ScriptContext
instances using the
ScriptSystemBus
(either call
AddContextWithId
, or create your own and call
AddContext
). If you want your new context to be available for debugging, you must register it with
ScriptDebugAgentBus::RegisterContext
.
Lua provides the capability to load and execute scripts from other Lua files using the built-in Lua require function. It's important to note that this function requires a special path format. The file path is delimited by periods instead of slashes, has no
.lua
file name extension, and is relative to the Lumberyard assets directory. For example, if you want to use the require
function to give your scripts some common functionality from the project's
Scripts
directory, you can use code similar to the following example.
local library =
require
("Scripts.MyLibraryFile")
Lua Editor is in preview release and is subject to change.
Lumberyard Lua Editor (Lua IDE) offers an intuitive integrated development environment (IDE) that makes it easy to author, debug, and edit Lua scripts when you create or extend your game. Lua Editor is a standalone application, but can be opened directly from Lumberyard Editor.
This tutorial shows you how to use Lumberyard Editor to create a sample level with a component entity that contains a Lua script component. You open the script in Lua Editor from Lumberyard Editor and perform some sample debugging steps on the script.
To use Lua Editor for debugging
1. In Lumberyard Editor, create a new level by performing one of the following steps:
• In the
Welcome to Lumberyard Editor
window, click
New level
• Click
File
,
New
• Press
Ctrl+N
2. In the
New Level
dialog box, give the level a name, and then click
OK
.
3. In the
Generate Terrain Texture
dialog box, click
OK
to accept the defaults.
4. Right-click the Lumberyard Editor viewport and select
Create Entity
.
5. In
Entity Inspector
, click
Add Component
, and then choose
Rendering
,
Point Light
.
6. In
Entity Inspector
, click
Add Component
, and then choose
Scripting
,
Lua Script
.
7. Scroll down to the bottom of the
Entity Inspector
window and, in the
Lua Script
section, click
...
to open the
Pick Lua Script
window.
8. In the
Pick Lua Script
window, expand
Samples Project
,
Scripts
,and
Components
.
9. Click
lightflicker.lua
, and then click
OK
. (Note: additional sample scripts are located in the
Lumberyard directory
\dev\SamplesProject\Scripts
.)
Version 1.10
633
Lumberyard Developer Guide
Tutorial: Using Lua Editor for
Debugging with Lumberyard Editor
10. In
Entity Inspector
, in the
Lua Script
section, click the empty braces
{ }
to launch Lua Editor.
Because the debugging functionality is enabled through network sockets, you must connect Lua
Editor to the target that is running the script before you can debug. In this tutorial, you connect to
Lumberyard Editor.
Note
Connection is facilitated by
, which is Lumberyard's central connection hub for debugging. GridHub starts automatically when Lua Editor is started and must be running in the background for Lua Editor to find targets it can connect to. If for some reason you need to start it manually, you can launch it from
\dev\Bin64\LuaIDE.exe
.
11. In the Lua Editor toolbar, click
Target: None
, and then click
Editor(
ID
)
to connect to Lumberyard
Editor.
12. In the Lua Editor toolbar, leave
Context
setting at
Default
for the debugging context. The default setting is good for debugging component entity scripts such as the one in this tutorial. The
Cry
context option is for debugging legacy scripts such as those associated with Cry entities or the Game
SDK.
13. The
Debugging
icon turns green to show that Lua Editor and Lumberyard Editor are connected:
Click
Classes
in the
Class Reference
to show the available Lua libraries. You can do the same for
EBuses
and
Globals
.
Version 1.10
634
Lumberyard Developer Guide
Tutorial: Using Lua Editor for
Debugging with Lumberyard Editor
Note
The class reference feature is active only for the default context and component entity scripts. This feature is not active in the Cry context, which exists only for backward compatibility.
After you connect, you can pause the execution of a given script by setting breakpoints.
14.
In the Lua Editor toolbar, click the
Breakpoints
icon to show the
Breakpoints
window.
15. In Lua Editor, single-click or double-click one or more line numbers in the lightflicker.lua
script to set one or more breakpoints. As you add breakpoints, the line number and script path for each are added to the
Breakpoints
window.
16. In Lumberyard Editor, press
Ctrl+G
to run the game, or click
AI/Physics
at the bottom of the viewport to enable game simulation and run scripts. Lua Editor opens with a yellow marker stopped on the first breakpoint that it encounters.
Version 1.10
635
Lumberyard Developer Guide
Tutorial: Using Lua Editor for
Debugging with Lumberyard Editor
When execution is halted at a breakpoint, more information becomes available in the
Lua Locals
,
Stack
, and
Watched Variables
panes.
17.
Click the
Stack
icon to show the
Stack
window.
18.
Click the
Lua Locals
icon to show local Lua variables.
19.
Click
Watched Variables
icon variables to watch.
to open the
Watched Variables
window, where you can specify
20. Press
F11
a few times to step through the code. Note how the contents of the
Stack
,
Lua Locals
, and
Watched Variables
windows change.
Tip
For greater convenience, you can float or dock these windows.
21. To detach from debugging, click
Debugging
.
22. In Lumberyard Editor, Press
Esc
to stop the game.
The following table summarizes common options available while debugging.
Icon Action
Run in Editor
Run on Target
Run/Continue
Step Into
Keyboard Shortcut
Alt+F5
Description
Run in Lumberyard Editor.
Ctrl+F5
F5
F11
Send script to the connected target and run it.
Run or continue running the current script.
Step into the function called on the current line.
Version 1.10
636
Icon Action
Step Out
Lumberyard Developer Guide
Maintaining Separate Search Results
Keyboard Shortcut
Shift+F11
Description
Step out of the called function.
Step Over F10
Toggle Breakpoint F9
Step over the function called on the current line.
Enable or disable a breakpoint on the current line.
In addition to the usual search capabilities, the
Find
feature can display the results of four different searches separately.
To maintain separate search results
1.
Click the
Find
icon files.
or press
Ctrl+F
to perform searches in the currently open file, or in all open
Version 1.10
637
Lumberyard Developer Guide
Editing
2. Before starting a search, choose
Find 1
,
Find 2
,
Find 3
, or
Find 4
to choose the the window in which you want to see the results. You can maintain the results of four searches separately in the tabbed windows. The search results in the other windows remain unchanged.
3. To go directly to the line in the code which a search result was found, double-click the line in the search results.
Note
In Lua Editor Preview, the line number shown in the
Find Results
window and the line number in the script pane differ by one.
Tip
For convenience, you can also dock or float the
Find Results
window.
Lua Editor can open multiple scripts at the same time. Each script has its own tab in the editor. The editor provides a standard set of capabilities for text editing but also includes useful features for editing source code.
The following table summarizes the options available while editing and debugging.
Action
Comment selected block
Copy
Cut
Find
Find in open files
Find next
Fold source functions
Go to line
Paste
Quick find local
Quick find local reverse
Redo
Replace
Replace in open files
Version 1.10
638
Keyboard Shortcut
Ctrl+K
Ctrl+C
Ctrl+X
Ctrl+F
Ctrl+Shift+F
F3
Alt+0
Ctrl+G
Ctrl+V
Ctrl+F3
Ctrl+Shift+F3
Ctrl+Y
Ctrl+R
Ctrl+Shift+R
Lumberyard Developer Guide
Perforce Integration
Action
Select all
Select to brace¹
Transpose lines down
Transpose lines up
Uncomment selected block
Undo
Unfold source functions
Keyboard Shortcut
Ctrl+A
Ctrl+Shift+]
Ctrl+Shift+Down Arrow
Ctrl+Shift+Up Arrow
Ctrl+Shift+K
Ctrl+Z
Alt+Shift+0
¹ Select to brace selects a block bounded by braces. Before using this option, the cursor must be immediately next to the beginning or ending brace of the block.
Lua Editor includes Perforce integration features. When you open a file from your Perforce environment,
Lua Editor displays the file's status in the top right of the text editing window.
The
Source Control
menu offers
Check Out/Check In
functionality.
This documentation is preliminary and subject to change.
You can use the Lua API calls in this reference for scripting the component entity system in Lumberyard.
For a tutorial on writing Lua scripts in Lumberyard, see
Writing Lua Scripts for the Component Entity
. For Lua scripting functions that load and unload canvases in Lumberyard Editor, see
.
Represents a request submitted by a user of the current component.
Version 1.10
639
Lumberyard Developer Guide
BehaviorTreeComponentRequestBus
Starts an inactive behavior tree associated with the current entity.
Syntax
void BehaviorTreeComponent::StartBehaviorTree()
Stops an active behavior tree associated with the current entity.
Syntax
void BehaviorTreeComponent::StopBehaviorTree()
Gets a list of cyclic redundancy check values for variable names.
Syntax
AZStd::vector<AZ::Crc32> GetVariableNameCrcs()
Returns:
A list of the 32-bit cyclic redundancy check values for all variable names.
Return Type:
AZStd::vector
Default Return:
s_defaultEmptyVariableIds
Gets the value for the specified variable name CRC-32 checksum.
Syntax
bool GetVariableValue(AZ::Crc32 variableNameCrc)
Parameter Type
variableNameCrc AZ::Crc32
Description
The CRC-32 checksum for the variable name.
Returns:
true
if successful; otherwise, false.
Return Type:
bool
Default Return:
false
Set the value associated with a variable.
Syntax
void SetVariableValue(AZ::Crc32 variableNameCrc, bool newValue)
Version 1.10
640
Lumberyard Developer Guide
NavigationComponentRequestBus
Parameter Type
variableNameCrc AZ::Crc32 newValue bool
Description
The CRC-32 checksum for the variable name.
The new value for the variable.
Requests serviced by the navigation component.
Creates a path finding request to navigate towards the specified entity.
Syntax
PathfindRequest::NavigationRequestId FindPathToEntity(AZ::EntityId entityId)
Parameter
entityId
Type
AZ::EntityId
Description
Request
EntityId
of the entity we want to navigate towards.
Returns:
A unique identifier to the pathfinding request.
Return Type:
PathfindRequest::NavigationRequestId
Default Return:
PathfindResponse::kInvalidRequestId
Stops all pathfinding operations for the specified requestId
. The ID is used to make sure that the request being cancelled is the request that is currently being processed. If the specified requestId
is different from the ID of the current request, the stop command can be safely ignored.
Syntax
void Stop(PathfindRequest::NavigationRequestId requestId)
Parameter
requestId
Type Description
Notifications sent by the Navigation component.
Indicates that the pathfinding request has been submitted to the navigation system.
Syntax
Version 1.10
641
Lumberyard Developer Guide
NavigationComponentNotificationBus void OnSearchingForPath(PathfindRequest::NavigationRequestId requestId)
Parameter
requestId
Type Description
Indicates that traversal for the indicated request has started.
Syntax
void OnTraversalStarted(PathfindRequest::NavigationRequestId requestId)
Parameter
requestId
Type Description
Indicates that traversal for the indicated request has started.
Syntax
void OnTraversalInProgress(PathfindRequest::NavigationRequestId requestId, float
distanceRemaining)
Parameter Type
requestId distanceRemainingfloat
Description
The remaining distance in the current path.
Indicates that traversal for the indicated request has completed successfully.
Syntax
void OnTraversalComplete(PathfindRequest::NavigationRequestId requestId)
Parameter
requestId
Type Description
Indicates that traversal for the indicated request was cancelled before it could be successfully completed.
Version 1.10
642
Lumberyard Developer Guide
NavigationSystemRequestBus
Syntax
void OnTraversalCancelled(PathfindRequest::NavigationRequestId requestId)
Parameter
requestId
Type Description
Requests serviced by the navigation system component. This currently contains the single function
RayCast
.
Creates a path finding request to navigate towards the specified entity.
Syntax
virtual NavRayCastResult RayCast(const AZ::Vector3& begin, const AZ::Vector3& direction,
float maxDistance) { return NavRayCastResult() }
Parameter Type
begin Vector3 direction Vector3 maxDistancefloat
Description
The origin of the ray.
The direction for the ray to travel.
The maximum distance the ray travels.
Returns:
A
NavRayCastResult
.
NavRayCastResult
has the following structure.
Parameter Type Description
bool m_collision
Boolean
Returns true if there was a collision. The default is false.
m_position Vector3 m_meshId
The position of the hit in world space. The default is
AZ::Vector3::CreateZero()
.
The mesh ID of the navigation mesh hit. This is callable from Lua script.
The default is 0.
Messages serviced by the
AttachmentComponent
. The
AttachmentComponent
lets an entity "stick" to a particular bone on a target entity.
Version 1.10
643
Lumberyard Developer Guide
AttachmentComponentNotificationBus
Change the attachment target. The entity will detach from any previous target.
Syntax
void Attach(AZ::EntityId targetId, const char* targetBoneName, const AZ::Transform& offset)
Parameter Type
targetId AZ::EntityId targetBoneName char
Description
Specifies the ID of the entity to attach to.
Specifies the bone on the target entity to attach to. If the target bone is not found, then attach to the target entity's transform origin.
The attachment's offset from the target.
offset AZ::Transform
Detaches an entity from its target.
Syntax
void Detach()
Update an entity's offset from its target.
Syntax
void SetAttachmentOffset(const AZ::Transform& offset)
Parameter
offset
Type
AZ::Transform
Description
The offset from the target.
This EBus interface handles events emitted by the
AttachmentComponent
. The
AttachmentComponent
lets an entity "stick" to a particular bone on a target entity.
The entity has attached to the target.
Syntax
void OnAttached(AZ::EntityId targetId)
Version 1.10
644
Lumberyard Developer Guide
CharacterAnimationRequestBus
Parameter
targetId
Type
AZ::EntityId
The entity is detaching from the target.
Syntax
void OnDetached(AZ::EntityId targetId)
Description
The target being attached to.
Parameter
targetId
Type
AZ::EntityId
Description
The target being detached from.
General character animation requests serviced by the
CharacterAnimationManager
component.
Sets a custom blend parameter.
Syntax
void SetBlendParameter(AZ::u32 blendParameter, float value)
Parameter Type
blendParameter AZ::u32 value float
Description
Corresponds to
EMotionParamID
.
The value to set.
Enables or disables animation-driven root motion.
Syntax
void SetAnimationDrivenMotion(bool useAnimDrivenMotion)
Parameter Type Description
Specify true
to enable animation-driven root motion; false
to disable.
Version 1.10
645
Lumberyard Developer Guide
MannequinRequestsBus
Services provided by the Mannequin component.
Queues the specified Mannequin fragment.
Syntax
FragmentRequestId QueueFragment(int priority, const char* fragmentName, const char*
fragTags, bool isPersistent)
Parameter
priority fragmentName fragTags isPersistent
Type
int char char bool
Description
Specifies priority. A higher number means higher priority
Name of the fragment to be played.
Fragment tags to be applied.
Specifies persistence.
Returns:
A request ID that can be used to identify and make modifications to the request.
Return Type:
FragmentRequestId
Default Return:
MannequinRequests::s_invalidRequestId
Pauses all actions being managed by the current Mannequin component
Syntax
void PauseAll()
Resumes all actions being managed by the current Mannequin component.
Syntax
void ResumeAll(IActionController::EResumeFlags resumeFlag)
Parameter
resumeFlag
Type Description
Flag that indicates how the animations are to be resumed. See the
EResumeFlags
enum for possible values.
enum EResumeFlags
Version 1.10
646
Lumberyard Developer Guide
MannequinRequestsBus
{
ERF_RestartAnimations = BIT(0),
ERF_RestoreLoopingAnimationTime = BIT(1),
ERF_RestoreNonLoopingAnimationTime = BIT(2),
ERF_Default = ERF_RestartAnimations | ERF_RestoreLoopingAnimationTime |
ERF_RestoreNonLoopingAnimationTime
};
Sets the specified tag for the action controller.
Syntax
void SetTag(const char* tagName)
Parameter
tagName
Type
char
Clears the specified tag for the action controller.
Syntax
void ClearTag(const char* tagName)
Description
The name of the tag to set.
Parameter
tagName
Type
char
Description
The name of the tag to be cleared.
Sets a tag in the specified group.
Syntax
void SetGroupTag(const char* groupName, const char* tagName)
Parameter
groupName tagName
Type
char char
Clears tags for the indicated group
Syntax
Description
The name of the group.
The name of the tag.
Version 1.10
647
Lumberyard Developer Guide
MannequinRequestsBus void ClearGroup(const char* groupName)
Parameter
groupName
Type
char
Description
The name of the group.
Sets the scope context for the current animation controller.
Syntax
void SetScopeContext(const char* scopeContextName, const AZ::EntityId entityId, const char*
animationDatabaseName)
Parameter Type
scopeContextName char entityId AZ::EntityId
Description
Name of the scope context that the animation database (.adb) file is to be attached to.
Reference to an entity whose character instance will be bound to this scope context.
The path to the animation database file.
Clears the specified scope context.
Syntax
void ClearScopeContext(const char* scopeContextName)
Parameter Type
scopeContextName char
Description
Name of the scope context that is to be cleared.
Stops the actions associated with the specified request.
Syntax
void StopRequest(FragmentRequestId requestId)
Parameter
requestId
Type
FragmentRequestId
Description
Specifies the ID of the request for which actions should be stopped.
Version 1.10
648
Lumberyard Developer Guide
MannequinRequestsBus
Retrieves the status of the specified request
Syntax
IAction::EStatus GetRequestStatus(FragmentRequestId requestId)
Parameter
requestId
Type
FragmentRequestId
Description
The ID of the request to retrieve status for.
Returns:
The status of the request.
Return Type:
IAction::EStatus
Default Return:
IAction::EStatus::None
Forces the actions associated with the specified request to finish.
Syntax
void ForceFinishRequest(FragmentRequestId requestId)
Parameter
requestId
Type
FragmentRequestId
Description
The ID of the request.
Sets the speed bias for the actions associated with the specified request.
Syntax
void SetRequestSpeedBias(FragmentRequestId requestId, float speedBias)
Parameter
requestId speedBias
Type
FragmentRequestId float
Description
The request ID.
The speed bias for this animation
Gets the speed bias for the actions associated with the specified request
Syntax
Version 1.10
649
Lumberyard Developer Guide
SimpleAnimationComponentRequestBus float GetRequestSpeedBias(FragmentRequestId requestId)
Parameter
requestId
Type
FragmentRequestId
Description
The ID of the request.
Returns:
The speed bias for the indicated request.
Return Type:
float
Default Return:
-1
Sets the animation weight for the actions associated with the specified request.
Syntax
void SetRequestAnimWeight(FragmentRequestId requestId, float animWeight)
Parameter
requestId animWeight
Type
FragmentRequestId float
Description
The ID of the request.
The weight for the animation.
Gets the animation weight for the actions associated with the specified request.
Syntax
float GetRequestAnimWeight(FragmentRequestId requestId)
Parameter
requestId
Type
FragmentRequestId
Description
The ID of the request.
Returns:
The animation weight for the indicated request.
Return Type:
float
Default Return:
-1
Services provided by the Simple Animation component. The Simple Animation component provides basic animation functionality for the entity. If the entity has a mesh component with a skinned mesh attached
(a .chr or .cdf file), the Simple Animation component will provide a list of all valid animations specified in the associated .chrparams file. The Simple Animation component does not provide interaction with
Mannequin and should be used for light-weight environment or background animation.
Version 1.10
650
Lumberyard Developer Guide
SimpleAnimationComponentRequestBus
Plays the default animations along with default looping and speed parameters that were set up as a part of the current component. Components allow for multiple layers to be set up with defaults. The
StartDefaultAnimations
method starts the playback of all the default animations of the component.
Syntax
SimpleAnimationComponentRequests::Result StartDefaultAnimations()
Returns:
A
Result
indicating whether the animations were started successfully.
Return Type:
SimpleAnimationComponentRequests::Result
Default Return:
SimpleAnimationComponentRequests::Result::Failure
Starts playback of the animation of the specified animatedLayer.
Syntax
SimpleAnimationComponentRequests::Result StartAnimation(const AnimatedLayer& animatedLayer)
Parameter
animatedLayer
Type
AnimatedLayer
Description
A layer configured with the animation that is to be played on it.
Returns:
A
Result
indicating whether the animation was started.
Return Type:
SimpleAnimationComponentRequests::Result
Default Return:
SimpleAnimationComponentRequests::Result::Failure
Plays the animation with the specified name.
Syntax
Result StartAnimationByName(const char* name, AnimatedLayer::LayerId layerId)
Parameter
name layerId
Type
char
AnimatedLayer::LayerId
Description
The name of the animation to play.
The layer in which to play the animation
Returns:
A
Result
indicating whether the animation was started.
Return Type:
SimpleAnimationComponentRequests::Result
Default Return:
SimpleAnimationComponentRequests::Result::Failure
Version 1.10
651
Lumberyard Developer Guide
SimpleAnimationComponentRequestBus
Stops all animations that are being played on all layers.
Syntax
Result StopAllAnimations()
Returns:
A
Result
indicating whether all animations were stopped.
Return Type:
SimpleAnimationComponentRequests::Result
Default Return:
SimpleAnimationComponentRequests::Result::Failure
Stops the animation currently playing on the specified layer.
Syntax
Result StopAnimationsOnLayer(AnimatedLayer::LayerId layerId, float blendOutTime)
Parameter
layerId blendOutTime
Type
AnimatedLayer::LayerId float
Description
Identifier for the layer that is to stop its animation (0 -
AnimatedLayer::s_maxActiveAnimatedLayers
)
Time that the animations take to blend out.
Returns:
A
Result
indicating whether the animation on the indicated layer was stopped.
Return Type:
SimpleAnimationComponentRequests::Result
Default Return:
SimpleAnimationComponentRequests::Result::Failure
Changes the playback speed for a particular layer.
Syntax
Result SetPlaybackSpeed(AnimatedLayer::LayerId layerId, float playbackSpeed)
Parameter
layerId playbackSpeed
Type
AnimatedLayer::LayerId float
Description
Identifier for the layer whose speed should be changed.
The playback speed.
Returns:
A
Result
indicating whether the animation on the indicated layer was updated or not. A failure likely indicated that no animation is playing on the specified layer.
Return Type:
SimpleAnimationComponentRequests::Result
Version 1.10
652
Lumberyard Developer Guide
SimpleAnimationComponentNotificationBus
Default Return:
SimpleAnimationComponentRequests::Result::Failure
This EBus interfaces handles events sent by the simple animation component.
Informs all listeners about an animation being started on a layer.
Syntax
void OnAnimationStarted(const AnimatedLayer& animatedLayer)
Parameter
animatedLayer
Type
AnimatedLayer
Description
Specifies the name and parameters of the animation that was started.
Informs all listeners about an animation being stopped on the indicated layer
Syntax
void OnAnimationStopped(const AnimatedLayer::LayerId animatedLayer)
Parameter
animatedLayer
Type
AnimatedLayer::LayerId
Description
Specifies the name and parameters of the animation that was stopped.
This EBus interface handles messages serviced by
AudioEnvironmentComponent
instances.
The environment refers to the effects (primarily the auxiliary effects) that the bus sends. See
AudioEnvironmentComponent.cpp
for details.
Sets an environment amount on the default assigned environment.
Syntax
void SetAmount(float amount)
Parameter
amount
Type
float
Description
The amount for the environment.
Version 1.10
653
Lumberyard Developer Guide
AudioListenerComponentRequestBus
Set an environment amount, specify an environment name at run time (that is, a script).
Syntax
void SetEnvironmentAmount(const char* environmentName,float amount)
Parameter Type
environmentName char amount float
Description
The name of the environment.
The amount for the environment.
This EBus interface handles messages serviced by
AudioListenerComponent
instances.
Sets the entity for which the audio listener tracks rotation.
Syntax
void SetRotationEntity(const AZ::EntityId entityId)
Parameter
entityId
Type
AZ::EntityId
Description
The ID of the entity.
Sets the entity for which the audio listener tracks position.
Syntax
void SetPositionEntity(const AZ::EntityId entityId)
Parameter
entityId
Type
AZ::EntityId
Description
The ID of the entity.
Essentially the same as calling
SetRotationEntity
and
SetPositionEntity
on the same entity.
Syntax
Version 1.10
654
Lumberyard Developer Guide
AudioRtpcComponentRequestBus void SetFullTransformEntity(const AZ::EntityId entityId)
Parameter
entityId
Type
AZ::EntityId
Description
The ID of the entity.
This EBus interface handles messages serviced by
AudioRtpcComponent
instances. RTPC stands for Real-
Time Parameter Control. The
AudioRtpcComponent
is used by the game to configure parameters in the audio engine. See
AudioRtpcComponent.cpp
for details.
Sets an RTPC value for the RTPC name that has been serialized with the component.
Syntax
void SetValue(float value)
Parameter
value
Type
float
Description
The RTPC value to set.
Use to manually specify an RTPC name and value at run time for use in scripting.
Syntax
void SetRtpcValue(const char* rtpcName, float value)
Parameter
rtpcName value
Type
char float
Description
Specifies an RTPC name to use.
Specifies a value for the RTPC name supplied.
This EBus interface handles messages serviced by
AudioSwitchComponent
instances. A
Switch
is an object that can be in one
State
at a time, but whose
State
value can be changed at run time. For example, a
Switch called SurfaceMaterial
might have states such as 'Grass', 'Snow', 'Metal', or 'Wood'. See
AudioSwitchComponent.h
for details.
Sets the name of the state on the default assigned switch.
Version 1.10
655
Lumberyard Developer Guide
AudioTriggerComponentRequestBus
Syntax
void SetState(const char* stateName)
Parameter
stateName
Type
char
Description
Specifies the name of the state to set.
Sets the specified switch to the specified state.
Syntax
void SetSwitchState(const char* switchName, const char* stateName)
Parameter
switchName stateName
Type
char char
Description
The name of the switch to set.
The name of the state to set on the specified switch.
This EBus interface handles messages serviced by
AudioTriggerComponent
instances. You can use the
AudioTriggerComponent
to execute, stop, and control ATL triggers. You can serialize the name of the trigger with the component or manually specify the name at run time for use in scripting. Only one
AudioTriggerComponent
is allowed on an entity, but the interface supports firing multiple ATL triggers.
Executes the play trigger if the play trigger is set.
Syntax
void Play()
Executes the stop trigger if one is set; otherwise, stops the play trigger.
Syntax
void Stop()
Executes the specified ATL trigger.
Syntax
Version 1.10
656
Lumberyard Developer Guide
AudioTriggerComponentNotificationBus void ExecuteTrigger(const char* triggerName)
Parameter
triggerName
Type
char
Kills the specified ATL Trigger.
Syntax
void KillTrigger(const char* triggerName)
Description
Specifies the name of the trigger to execute.
Parameter
triggerName
Type
char
Description
Specifies the name of the trigger to kill.
Forces a kill of triggers that are active on the underlying proxy.
Syntax
void KillAllTriggers()
Specifies whether the trigger should be repositioned as the entity moves.
Syntax
void SetMovesWithEntity(bool shouldTrackEntity)
Parameter Type
shouldTrackEntitybool
Description
Specify true
to have the trigger track the entity.
Specify false
to have the trigger not track the entity.
This EBus interface handles messages sent by
AudioTriggerComponent
instances.
Notifies when a trigger instance has finished.
Syntax
Version 1.10
657
Lumberyard Developer Guide
FloatGameplayNotificationBus
(
AZ::
GameplayNotificationBus<float>) void OnTriggerFinished(const Audio::TAudioControlID triggerID)
Parameter
triggerID
Type
Audio::TAudioControlID
Description
The ID of the trigger.
AZ::
This version of the
GameplayNotificationBus
EBus interface handles float-based game play notifications.
Event sent when the specified
GameplayEventAction
has occurred.
Event sent when the given
GameplayEventAction
has failed.
AZ::GameplayNotificationBus<AZ::Vector3>
This version of the
GameplayNotificationBus
EBus interface handles Vector3-based game play notifications.
Event sent when the given
GameplayEventAction
has occurred.
Event sent when the given
GameplayEventAction
has failed.
AZ::
::
This version of the
GameplayNotificationBus
EBus interface handles string-based game play notifications.
Event sent when the given
GameplayEventAction
has occurred.
Event sent when the given
GameplayEventAction
has failed.
Version 1.10
658
Lumberyard Developer Guide
EntityIdGameplayNotificationBus
(AZ::GameplayNotificationBus<AZ::EntityId>)
This EBus interface handles
EntityId
-based game play notifications. It is a specialization of the
GameplayNotificationBus
.
Event sent when the given
GameplayEventAction
has occurred.
Event sent when the given
GameplayEventAction
has failed.
This EBus interface handles messages serviced by Cry character physics.
Requests movement from Living Entity.
Syntax
void Move(const AZ::Vector3& velocity, int jump)
Parameter
velocity jump
Type
AZ::Vector3 int
Description
Requested velocity (direction and magnitude).
Controls how the value for the velocity parameter is applied within a Living Entity. To change the velocity to the new value, specify
1
. To add the value to the current velocity, specify
2
.
This EBus interface handles messages serviced by instances of the Constraint component. A Constraint component facilitates the creation of a physics constraint between two entities or an entity and a point in the world. Both entities must have a component that provides the physics service.
Sets the entity that owns the constraint and the target of the constraint.
Syntax
void SetConstraintEntities(const AZ::EntityId& owningEntity, const AZ::EntityId&
targetEntity)
Version 1.10
659
Lumberyard Developer Guide
ConstraintComponentNotificationBus
Parameter
owningEntity targetEntity
Type
AZ::EntityId
AZ::EntityId
Description
Specifies the ID of the entity that owns the constraint.
Specifies the ID of the entity that is the target of the constraint. The target is invalid if constrained to world space.
Sets the entity that owns the constraint, the target entity, and the animation part IDs (bone IDs) for the constraint to be attached to.
Syntax
void SetConstraintEntitiesWithPartIds(const AZ::EntityId& owningEntity, int ownerPartId,
const AZ::EntityId& targetEntity, int targetPartId)
Parameter
owningEntity ownerPartId targetEntity targetPartId
Type
AZ::EntityId int
AZ::EntityId int
Description
Specifies the ID of the entity that owns the constraint.
Specifies the ID of the owner part (the bone ID) for the constraint.
Specifies the ID of the entity that is the target of the constraint.
Specifies the ID of the target part (the bone ID) for the constraint.
Enable all constraints on the current entity.
Syntax
void EnableConstraint()
Disable all constraints on the current entity.
Syntax
void DisableConstraint()
This EBus interface handles messages dispatched by the Constraint component.
Version 1.10
660
Lumberyard Developer Guide
PhysicsComponentRequestBus
This event fires when either the constraint owner or target changes. The target is invalid if constrained to world space.
Note
This event also fires when partId
values change.
Syntax
void OnConstraintEntitiesChanged(const AZ::EntityId& oldOwner, const AZ::EntityId&
oldTarget, const AZ::EntityId& newOwner, const AZ::EntityId& newTarget)
Parameter
oldOwner oldTarget newOwner newTarget
Type
AZ::EntityId
AZ::EntityId
AZ::EntityId
AZ::EntityId
Description
Specifies the ID of the entity that owned the constraint.
Specifies the ID of the entity that was the target of the constraint.
Specifies the ID of the entity that is the new owner of the constraint.
Specifies the ID of the entity that is the new target of the constraint.
Fires when constraints have been enabled on the current entity.
Syntax
void OnConstraintEnabled()
Fires when a constraint has been disabled.
Syntax
void OnConstraintDisabled()
This EBus interface handles messages serviced by the in-game Physics component.
Makes the entity a participant in the physics simulation.
Syntax
Version 1.10
661
Lumberyard Developer Guide
PhysicsComponentRequestBus void EnablePhysics()
Stops the entity from participating in the physics simulation
Syntax
void DisablePhysics()
Checks if physics are enabled on the current entity.
Syntax
bool IsPhysicsEnabled()
Returns:
true
if physics are enabled; false
otherwise.
Return Type:
bool
Default Return:
false
Applies the specified impulse to the entity.
Syntax
void AddImpulse(const AZ::Vector3& impulse)
Parameter
impulse
Type
AZ::Vector3
Description
Vector of the impulse.
Applies an angular impulse to the entity.
Syntax
void AddAngularImpulse(const AZ::Vector3& /*impulse*/, const AZ::Vector3& worldSpacePivot)
Parameter Type
impulse AZ::Vector3 worldSpacePivot AZ::Vector3
Description
Vector of the impulse.
Vector of the world space pivot to apply to the entity.
Version 1.10
662
Lumberyard Developer Guide
PhysicsComponentRequestBus
Retrieves the velocity of the entity.
Syntax
AZ::Vector3 GetVelocity()
Returns:
The velocity of the entity.
Return Type:
AZ::Vector3
Default Return:
AZ::Vector3::CreateZero
()
Sets the velocity of the entity.
Syntax
void SetVelocity(const AZ::Vector3& velocity)
Parameter
velocity
Type
AZ::Vector3
Description
Specifies the velocity to set.
Gets the linear acceleration of the entity.
Syntax
AZ::Vector3 GetAcceleration()
Returns:
A vector containing the linear acceleration of the entity.
Return Type:
AZ::Vector3
Default Return:
AZ::Vector3::CreateZero
()
Gets the angular velocity of the entity.
Syntax
AZ::Vector3 GetAngularVelocity()
Returns:
A vector containing the angular velocity of the entity.
Return Type:
AZ::Vector3
Version 1.10
663
Lumberyard Developer Guide
PhysicsComponentNotificationBus
Default Return:
AZ::Vector3::CreateZero
()
Sets the angular velocity of the entity to the specified amount.
Syntax
void SetAngularVelocity(const AZ::Vector3& angularVelocity)
Parameter Type
angularVelocity AZ::Vector3
Description
The angular velocity to set.
Gets the angular acceleration of the entity
Syntax
AZ::Vector3 GetAngularAcceleration()
Returns:
A vector containing the angular acceleration of the entity.
Return Type:
AZ::Vector3
Default Return:
AZ::Vector3::CreateZero
()
Retrieves the mass of the entity.
Syntax
float GetMass()
Returns:
The mass of the entity.
Return Type:
float
Default Return:
0.0f
This bus handles events emitted by a Physics component and by the Physics system.
Fires when an entity begins participating in the physics simulation. If the entity is active when a handler connects to the bus, then
OnPhysicsEnabled
() is immediately dispatched.
Note
If physics is enabled,
OnPhysicsEnabled
fires immediately upon connecting to the bus.
Version 1.10
664
Lumberyard Developer Guide
PhysicsSystemRequestBus
Syntax
void OnPhysicsEnabled()
Fires when an entity ends its participation in the physics simulation.
Syntax
void OnPhysicsDisabled()
Fires when an entity collides with another entity.
Syntax
void OnCollision(const Collision& collision)
Parameter
collision
Type
Collision
Description
Contains information about the collision that occurred.
See the following
Collision
struct.
struct Collision
{
AZ_TYPE_INFO(Collision, "{33756BD4-24D4-4DAE-A849-537114D52F7D}");
AZ_CLASS_ALLOCATOR(Collision, AZ::SystemAllocator, 0);
AZ::EntityId m_entity; // ID of other entity involved in event
AZ::Vector3 m_position; // Contact point in world coordinates
AZ::Vector3 m_normal; // Normal to the collision
float m_impulse; // Impulse applied by the collision resolver
AZ::Vector3 m_velocityA; // Velocities of the first entity involved in the
collision
AZ::Vector3 m_velocityB; // Velocities of the second entity involved in
the collision
float m_massA; // Masses of the first entity involved in the
collision
float m_massB; // Masses of the second entity involved in the
collision
}
Requests for the physics system
Casts a ray and retrieves a list of results.
Syntax
Version 1.10
665
Lumberyard Developer Guide
RagdollPhysicsRequestBus
RayCastHit RayCast(const AZ::Vector3& begin, const AZ::Vector3& direction, float
maxDistance, AZ::u32 maxHits, AZ::u32 query)
Parameter
begin direction maxDistance maxHits query
Type
const AZ::Vector3& const AZ::Vector3& float
AZ::u32
AZ::u32
Description
The origin of the ray
The direction for the ray to travel
The maximum distance the ray will travel
The maximum number of hits found before the search is aborted
The entity types to hit. See the
PhysicalEntityTypes enum that follows.
Returns:
A
RayCastHit
struct. For details, see the code listing that follows.
Return Type:
PhysicsSystemRequests::RayCastHit
Default Return:
RayCastHit() struct RayCastHit
{
AZ_TYPE_INFO(RayCastHit, "{3D8FA68C-A145-44B4-BA18-F3405D83A9DF}");
AZ_CLASS_ALLOCATOR(RayCastHit, AZ::SystemAllocator, 0);
float m_distance = 0.0f; // The distance from RayCast begin to the hit.
AZ::Vector3 m_position; // The position of the hit in world space.
AZ::Vector3 m_normal; // The normal of the surface hit.
AZ::EntityId m_entityId; // The ID of the AZ::Entity hit, or
// AZ::InvalidEntityId if hit object is not an AZ::Entity.
};
Messages serviced by the Cry character physics ragdoll behavior.
Causes an entity with a skinned mesh component to disable its current physics and enable ragdoll physics.
Syntax
void EnterRagdoll()
Causes the ragdoll component to deactivate itself and reenable the entity's physics component.
Syntax
void ExitRagdoll()
Version 1.10
666
Lumberyard Developer Guide
DecalComponentRequestBus
This EBus interface handles messages serviced by the Decal component.
Specifies the decal's visibility.
Syntax
void SetVisibility(bool visible)
Parameter
visible
Type
bool
Description
Specify true
to make the decal visible, false
to hide it.
Makes the decal visible.
Syntax
void Show()
Hides the decal.
Syntax
void Hide()
This EBus interface handles messages serviced by the Lens Flare component.
Controls the lens flare state.
Syntax
void SetLensFlareState(State state)
Parameter
state
Type
State
Description
Specify
On
to turn on the lens flare; specify
Off
to turn it off.
Version 1.10
667
Lumberyard Developer Guide
LensFlareComponentNotificationBus
Turns the lens flare on.
Syntax
void TurnOnLensFlare()
Turns the lens flare off.
Syntax
void TurnOffLensFlare()
Toggles the lens flare state.
Syntax
void ToggleLensFlare()
This EBus interface handles events dispatched by the Lens Flare component.
Notifies that the lens flare has been turned on.
Syntax
void LensFlareTurnedOn()
Notifies that the lens flare has been turned off.
Syntax
void LensFlareTurnedOff()
This EBus interfaces handles messages serviced by the light component.
Controls the light state.
Version 1.10
668
Lumberyard Developer Guide
LightComponentNotificationBus
Syntax
void SetLightState(State state)
Parameter
state
Type
State
Description
Specify
On
to turn on the light; specify
Off
to turn it off.
Turns the light on.
Syntax
void TurnOnLight()
Turns the light off.
Syntax
void TurnOffLight()
Toggles the light state.
Syntax
void ToggleLight()
Light component notifications.
Event sent when a light component is turned on.
Syntax
void LightTurnedOn()
Event sent when a light component is turned off.
Syntax
Version 1.10
669
Lumberyard Developer Guide
ParticleComponentRequestBus void LightTurnedOff()
Provides access to the particle component.
Specifies the visibility of the particle component.
Syntax
void SetVisibility(bool visible)
Parameter
visible
Type
bool
Description
Specify true
to make the particle component visible; false
to hide it.
Makes the particle component visible.
Syntax
void Show()
Hides the particle component.
Syntax
void Hide()
Sets up an effect emitter with the specified name and settings.
Syntax
void SetupEmitter(const AZStd::string& emitterName, const ParticleEmitterSettings&
settings)
Parameter
emitterName settings
Type Description
const AZStd::string&
The name of the emitter to set up.
const
ParticleEmitterSettings&
Contains particle emitter settings. For more information, see
ParticleComponent.cpp
.
Version 1.10
670
Lumberyard Developer Guide
SimpleStateComponentRequestBus
This EBus interface handles messages serviced by the Simple State component. The Simple State component provides a simple state machine. Each state is represented by a name and zero or more entities that are activated when the state is entered and deactivated when the state is left.
Sets the active state
Syntax
void SetState(const char* stateName)
Parameter
stateName
Type
char
Sets the active state using a 0-based index.
Syntax
void SetStateByIndex(AZ::u32 stateIndex)
Description
The name of the state.
Parameter
stateIndex
Type
AZ::u32
Description
The 0-based index of the state.
Advances to the next state. If the next state is null, the first state is set.
Syntax
void SetToNextState()
Sets the previous state. If the previous state is null, the end state is set.
Syntax
void SetToPreviousState()
Sets the first state.
Syntax
Version 1.10
671
Lumberyard Developer Guide
SimpleStateComponentNotificationBus void SetToFirstState()
Sets the last state.
Syntax
void SetToLastState()
Get the number of states.
Syntax
AZ::u32 GetNumStates()
Returns:
The number of states.
Return Type:
AZ::u32
Default Return:
0
Gets the current state.
Syntax
const char* GetCurrentState()
Returns:
The current state.
Return Type:
const char*
Default Return:
nullptr
This EBus interface handles events dispatched by the Simple State component.
Notify that the state has changed from oldState
to newState
.
Syntax
void OnStateChanged(const char* oldState, const char* newState)
Parameter
oldState
Type
char
Description
The name of the old state.
Version 1.10
672
Lumberyard Developer Guide
SpawnerComponentRequestBus
Parameter
newState
Type
char
Description
The name of the new state.
This EBus interface handles messages serviced by the
SpawnerComponent
.
Spawns the selected slice at the entity's location.
Syntax
AzFramework::SliceInstantiationTicket Spawn()
Returns:
A slice instantiation ticket.
Return Type:
AzFramework::SliceInstantiationTicket
Default Return:
AzFramework::SliceInstantiationTicket
()
Spawns the selected slice at the entity's location with the specified relative offset.
Syntax
AzFramework::SliceInstantiationTicket SpawnRelative(const AZ::Transform& relative)
Parameter
relative
Type
AZ::Transform
Description
Relative offset from the entity's location.
Returns:
A slice instantiation ticket.
Return Type:
AzFramework::SliceInstantiationTicket
Default Return:
AzFramework::SliceInstantiationTicket
()
Spawns the selected slice at the specified world transform.
Syntax
AzFramework::SliceInstantiationTicket SpawnAbsolute(const AZ::Transform& world)
Parameter
world
Type
const AZ::Transform&
Description
Specifies the world transform at which to spawn the selected slice.
Version 1.10
673
Lumberyard Developer Guide
SpawnerComponentNotificationBus
Returns:
A slice instantiation ticket.
Return Type:
AzFramework::SliceInstantiationTicket
Default Return:
AzFramework::SliceInstantiationTicket
()
This EBus interface handles events dispatched by the
SpawnerComponent.
Notifies that a slice has been spawned, but that its entities have not yet been activated.
OnEntitySpawned events are about to be dispatched.
Syntax
void OnSpawnBegin(const AzFramework::SliceInstantiationTicket& ticket)
Parameter
ticket
Type Description
Notifies that a spawn has been completed. All
OnEntitySpawned
events have been dispatched.
Syntax
void OnSpawnEnd(const AzFramework::SliceInstantiationTicket& ticket)
Parameter
ticket
Type Description
Notifies that an entity has spawned. This event is called once for each entity spawned in a slice.
Syntax
void OnEntitySpawned(const AzFramework::SliceInstantiationTicket& ticket, const
AZ::EntityId& spawnedEntities)
Parameter Type
ticket AzFramework::SliceInstantiationTicket spawnedEntities AZ::EntityId
Version 1.10
674
Description
The slice instantiation ticket.
The ID of the spawned entity.
Lumberyard Developer Guide
TagComponentRequestBus
Provides services for managing tags on entities.
Checks for a specified tag on an entity.
Syntax
bool HasTag(const Tag&)
Parameter
tag
Type
Tag
Description
The tag to query for.
Returns:
true
if the entity has the specified tag; false
otherwise.
Return Type:
bool
Default Return:
false
Adds the specified tag to the entity if it doesn't already have it.
Syntax
void AddTag(const Tag&)
Parameter
Tag
Type
Tag
Description
The tag to add.
Adds a specified list of tags to the entity if the list does not exist on the entity.
Syntax
void AddTags(const Tags& tags)
Parameter
tags
Type
Tags
Description
The list of tags to add.
Removes a specified tag from the entity if the tag is present.
Version 1.10
675
Lumberyard Developer Guide
TagGlobalRequestBus
Syntax
void RemoveTag(const Tag&)
Parameter
tag
Type
Tag
Description
The tag to remove.
Removes the specified list of tags from the entity if the list exists on the entity.
Syntax
void RemoveTags(const Tags& tags)
Parameter
tags
Type
Tags
Description
The list of tags to remove.
Retrieves the list of tags on the entity.
Syntax
const Tags& GetTags()
Returns:
A list of the tags on the entity.
Return Type:
static Tags
Default Return:
s_emptyTags
Provides services for querying Tags on entities.
Queries for tagged entities. Handlers respond if they have the tag (that is, they are listening on the tag's channel). Use
AZ::EbusAggregateResults
to handle more than the first responder.
Syntax
const AZ::EntityId RequestTaggedEntities()
Returns:
The ID of an entity that has a tag.
Return Type:
const AZ::EntityId
Version 1.10
676
Lumberyard Developer Guide
TagGlobalNotificationBus
Default Return:
s_invalidEntityId
Handler for global Tag component notifications.
Notifies that a tag has been added to an entity. When connecting to the tag global notification bus, your
OnEntityTagAdded
handler fires once for each entity that already has a tag. After the initial connection, you are alerted whenever a new entity gains or loses a tag.
Syntax
void OnEntityTagAdded(const AZ::EntityId&)
Notifies that a Tag has been removed from an entity.
Syntax
void OnEntityTagRemoved(const AZ::EntityId&)
Provides notifications regarding tags on entities.
Notifies listeners when a tag has been added.
Syntax
void OnTagAdded(const Tag&)
Notifies listeners when a tag is removed.
Syntax
void OnTagRemoved(const Tag&)
This EBus interface services requests made to the Trigger Area component.
Adds a required tag to the activation filtering criteria of the current component.
Syntax
Version 1.10
677
Lumberyard Developer Guide
TriggerAreaNotificationBus void AddRequiredTag(const Tag& requiredTag)
Parameter
requiredTag
Type
Tag
Description
The tag to add to the activation filtering criteria.
Removes a required tag from the activation filtering criteria of the current component.
Syntax
void RemoveRequiredTag(const Tag& requiredTag)
Parameter
requiredTag
Type
Tag
Description
The tag to remove from the activation filtering criteria.
Adds an excluded tag to the activation filtering criteria of the current component.
Syntax
void AddExcludedTag(const Tag& excludedTag)
Parameter
excludedTag
Type
Tag
Description
The excluded tag to add to the activation filtering criteria.
Removes an excluded tag from the activation filtering criteria of the current component.
Syntax
void RemoveExcludedTag(const Tag& excludedTag)
Parameter
excludedTag
Type
Tag
Description
The excluded tag to remove from the activation filtering criteria.
This EBus handles events for a given trigger area when an entity enters or leaves.
Version 1.10
678
Lumberyard Developer Guide
TriggerAreaEntityNotificationBus
Notifies when an entity enters the trigger area.
Syntax
void OnTriggerAreaEntered(AZ::EntityId enteringEntityId)
Parameter Type
enteringEntityId AZ::EntityId
Description
The ID of the entity that entered the trigger area.
Notifies when an entity exits the trigger area.
Syntax
void OnTriggerAreaExited(AZ::EntityId exitingEntityId)
Parameter Type
exitingEntityId AZ::EntityId
Description
The ID of the entity that exited the trigger area.
Events fired for a specified trigger when the trigger area has been entered or exited.
Notifies when an enteringEntityId
instance has entered the specified trigger area.
Syntax
void OnEntityEnteredTriggerArea(AZ::EntityId triggerId)
Parameter
triggerId
Type
AZ::EntityId
Description
The ID of the trigger that has been entered.
Notifies when an enteringEntityId
instance has exited the specified trigger area.
Syntax
void OnEntityExitedTriggerArea(AZ::EntityId triggerId)
Version 1.10
679
Lumberyard Developer Guide
BoxShapeComponentRequestsBus
Parameter
triggerId
Type
AZ::EntityId
Description
The ID of the trigger that has been exited.
Services provided by the Box Shape component.
Retrieves the box configuration.
Syntax
BoxShapeConfiguration GetBoxConfiguration()
Return Type:
BoxShapeConfiguration
Default Return:
BoxShapeConfiguration()
Sets new dimensions for the Box Shape.
Syntax
void SetBoxDimensions(AZ::Vector3 newDimensions)
Parameter
newDimensions
Type
AZ::Vector3
Description
Specifies dimensions along the X, Y, and Z axes.
Services provided by the Capsule Shape Component.
Retrieves the capsule configuration.
Syntax
CapsuleShapeConfiguration GetCapsuleConfiguration()
Returns:
The capsule configuration.
Return Type:
CapsuleShapeConfiguration
Default Return:
CapsuleShapeConfiguration
()
Version 1.10
680
Lumberyard Developer Guide
CylinderShapeComponentRequestsBus
Sets the end to end height of capsule, including the cylinder and both caps.
Syntax
void SetHeight(float newHeight)
Parameter
newHeight
Type
float
Sets the radius of the capsule.
Syntax
void SetRadius(float newRadius)
Description
Specifies the new height of the capsule.
Parameter
newRadius
Type
float
Description
Specifies the new radius of the capsule.
This EBus interface handles messages for the Cylinder Shape component.
Retrieves the cylinder configuration.
Syntax
CylinderShapeConfiguration GetCylinderConfiguration()
Returns:
The cylinder configuration.
Return Type:
CylinderShapeConfiguration
Default Return:
CylinderShapeConfiguration
()
Sets the height of the cylinder.
Syntax
void SetHeight(float newHeight)
Version 1.10
681
Lumberyard Developer Guide
ShapeComponentRequestsBus
Parameter
newHeight
Type
float
Sets the radius of the cylinder.
Syntax
void SetRadius(float newRadius)
Description
Specifies the height of the cylinder.
Parameter
newRadius
Type
float
Description
Specifies the radius of the cylinder.
Handles requests for services provided by the Shape component.
Retrieves the type of shape of a component.
Syntax
AZ::Crc32 GetShapeType()
Returns:
A Crc32 value that indicates the type of shape of the current component.
Return Type:
AZ::Crc32
Default Return:
AZ::Crc32()
Checks if a given point is inside or outside a shape.
Syntax
bool IsPointInside(const AZ::Vector3& point)
Parameter
point
Type
AZ::Vector3
Description
Specifies the coordinates of the point to be tested.
Returns:
A bool
value that indicates whether the point is inside or out.
Return Type:
bool
Version 1.10
682
Lumberyard Developer Guide
ShapeComponentNotificationsBus
Default Return:
false
Retrieves the minimum distance the specified point is from the shape.
Syntax
float DistanceFromPoint(const AZ::Vector3& point)
Parameter
point
Type
AZ::Vector3
Description
Specifies the coordinates of the point from which to calculate distance.
Returns:
A float that indicates the distance the point is from the shape.
Return Type:
float
Default Return:
0.f
Retrieves the minimum squared distance the specified point is from the shape.
Syntax
float DistanceSquaredFromPoint(const AZ::Vector3& point)
Parameter
point
Type
AZ::Vector3
Description
Specifies the coordinates of the point from which to calculate the squared distance.
Returns:
A float that contains the minimum squared distance the specified point is from the shape.
Return Type:
float
Default Return:
0.f
Notifications sent by the shape component.
Notifies that the shape component has been modified.
Syntax
void OnShapeChanged(ShapeChangeReasons changeReason)
Version 1.10
683
Lumberyard Developer Guide
SphereShapeComponentRequestsBus
Parameter
changeReason
Type
ShapeChangeReasons
Description
Informs listeners of the reason for this shape change
(transform change, the shape dimensions being altered.)
Services provided by the Sphere Shape Component
Retrieves the sphere configuration.
Syntax
SphereShapeConfiguration GetSphereConfiguration()
Returns:
The sphere configuration.
Return Type:
SphereShapeConfiguration
Default Return:
SphereShapeConfiguration
()
Sets the specified radius for the sphere shape component.
Syntax
void SetRadius(float newRadius)
Parameter
newRadius
Type
float
Description
Specifies the radius of the sphere shape.
Dispatches events specific to a given entity.
Notifies when entity activation has completed. If the entity is active when a handler connects to the bus, then the
OnEntityActivated
event is sent immediately.
Syntax
void OnEntityActivated(const AZ::EntityId&)
Notifies when the entity is about to be deactivated.
Version 1.10
684
Lumberyard Developer Guide
TickBus
Syntax
void OnEntityDeactivated(const AZ::EntityId&)
Tick events are executed on the main game or component thread.
Note
Warning: Adding mutex to the tick bus degrades performance in most cases.
Notifies the delta time if the delta from the previous tick (in seconds) and time point is its absolute value.
Syntax
void OnTick(float deltaTime, ScriptTimePoint time)
Parameter
deltaTime time
Type
float
ScriptTimePoint
Description
The latest time between ticks.
The time at the current tick.
Make requests from this bus to get the frame time or return the current time as seconds.
Gets the latest time between ticks.
Syntax
float GetTickDeltaTime()
Returns:
The latest time between ticks.
Return Type:
float
Default Return:
0.f
Gets the time in seconds at the current tick.
Syntax
ScriptTimePoint GetTimeAtCurrentTick()
Returns:
The time in seconds at the current tick.
Version 1.10
685
Lumberyard Developer Guide
TransformNotificationBus
Return Type:
ScriptTimePoint
Default Return:
ScriptTimePoint
()
This EBus is a listener for transform changes.
Notifies when the local transform of the entity has changed. A local transform update always implies a world transform change.
Syntax
void OnTransformChanged(const Transform& local, const Transform& world)
Parameter
local world
Type
Transform
Transform
Description
The local transform of the entity.
The world transform.
Notifies when the parent of an entity has changed. When the old or new parent is invalid, the invalid
EntityId
is equal to
InvalidEntityId
.
Syntax
void OnParentChanged(EntityId oldParent, EntityId newParent)
Parameter
oldParent newParent
Type
EntityId
EntityId
Description
The entity ID of the old parent.
The entity ID of the new parent.
This EBus interfaces makes requests to the game entity context component.
Destroys an entity. The entity is deactivated immediately and is destroyed in the next tick.
Syntax
void DestroyGameEntity(const AZ::EntityId& id)
Version 1.10
686
Lumberyard Developer Guide
GameEntityContextRequestBus
Parameter
id
Type
AZ::EntityId
Description
The ID of the entity to be destroyed.
Destroys an entity and all its descendants, the entity and its descendants are deactivated immediately and will be destroyed the next tick.
Syntax
void DestroyGameEntityAndDescendants(AZ::EntityId& id)
Parameter
id
Type
AZ::EntityId
Description
The ID of the entity to be destroyed. The entity's descendants will also be destroyed.
Activates an entity by the specified ID.
Syntax
void ActivateGameEntity(AZ::EntityId& id)
Parameter
id
Type
AZ::EntityId
Deactivates an entity by the specified ID.
Syntax
void DeactivateGameEntity(AZ::EntityId& id)
Description
The ID of the entity to activate.
Parameter
id
Type
AZ::EntityId
Description
The ID of the entity to deactivate.
Destroys the slice instance that contains the entity with the specified ID.
Syntax
Version 1.10
687
Lumberyard Developer Guide
RandomManagerBus bool DestroySliceByEntity(AZ::EntityId& id)
Parameter
id
Type
AZ::EntityId
Description
Returns
: true
if the slice instance was successfully destroyed.
Return Type:
bool
Default Return:
false
Provides functions for random numbers.
Generates a random float value.
Syntax
float RandomFloat()
Parameter
tag
Type
AZStd::string
Returns:
A random value between [0.0f, 1.0f).
Return Type:
float
Default Return:
0.0f
Generates a random Boolean value.
Syntax
bool RandomBool(const AZStd::string& tag)
Description
The tag.
Parameter
tag
Type
AZStd::string
Returns:
A random Boolean value.
Return Type:
bool
Default Return:
false
Description
The tag.
Version 1.10
688
Lumberyard Developer Guide
CameraRequestBus
Generates a random unsigned integer value.
Syntax
unsigned int RandomInt(const AZStd::string& tag)
Parameter
tag
Type
AZStd::string
Description
The tag.
Returns:
A random unsigned integer value.
Return Type:
unsigned int
Default Return:
0
Generates a random unsigned integer value within a specified range.
Syntax
unsigned int RandomInRange(const AZStd::string& tag, unsigned int min, unsigned int max)
Parameter
tag min max
Type
AZStd::string unsigned int unsigned int
Description
The tag.
The minimum value that can be returned.
The maximum value that can be returned.
Returns:
A random unsigned integer value within the specified range.
Return Type:
unsigned int
Default Return:
0
Provides access to camera properties and services.
Gets the camera's field of view in degrees
Syntax
float GetFOV()
Version 1.10
689
Lumberyard Developer Guide
CameraRequestBus
Returns:
The camera's field of view as a float.
Return Type:
float
Default Return:
s_defaultFoV
Gets the camera's distance from the near clip plane in meters.
Syntax
float GetNearClipDistance()
Returns:
The camera's distance from the near clip plane as a float in meters.
Return Type:
float
Default Return:
s_ defaultNearPlaneDistance
Gets the camera's distance from the far clip plane in meters.
Syntax
float GetFarClipDistance()
Returns:
The camera's distance from the far clip plane as a float in meters.
Return Type:
float
Default Return:
s_ defaultFarClipPlaneDistance
Gets the camera frustum's width.
Syntax
float GetFrustumWidth()
Returns:
The camera frustum's width as a float.
Return Type:
float
Default Return:
s_ defaultFrustumDimension
Gets the camera frustum's height.
Syntax
float GetFrustumHeight()
Version 1.10
690
Lumberyard Developer Guide
CameraRequestBus
Returns:
The camera frustum's height as a float.
Return Type:
float
Default Return:
s_ defaultFrustumDimension
Sets the camera's field of view in degrees.
Syntax
void SetFov(float fov)
Parameter
fov
Type
float
Description
The field of view in degrees. Possible values are 0 < fov
< 180.
Sets the near clip plane to the specified distance from the camera in meters.
Syntax
void SetNearClipDistance(float nearClipDistance)
Parameter Type
nearClipDistance float
Description
The distance from the camera in meters. The value should be small, but greater than 0.
Sets the far clip plane to the specified distance from the camera in meters.
Syntax
void SetFarClipDistance(float farClipDistance)
Parameter Type
farClipDistance float
Sets the camera frustum's width.
Syntax
Description
The distance from the camera in meters.
Version 1.10
691
Lumberyard Developer Guide
HttpClientComponentNotificationBus void SetFrustumWidth(float width)
Parameter
width
Type
float
Sets the camera frustum's height.
Syntax
void SetFrustumHeight(float height)
Description
The camera frustum's width.
Parameter
height
Type
float
Description
The camera frustum's height.
Makes the camera the active view.
Syntax
void MakeActiveView()
Event handler for Http requests.
Notifies when an HTTP request is successful.
Syntax
void OnHttpRequestSuccess(int responseCode, AZStd::string responseBody)
Parameter
responseCode responseBody
Type
int
AZStd::string
Sent when an HTTP request failed.
Syntax
Description
The response code.
The body of the response.
Version 1.10
692
Lumberyard Developer Guide
HttpClientComponentRequestBus void OnHttpRequestFailure(int responseCode)
Parameter
responseCode
Type
int
Description
The response code.
Provides services to make HTTP requests.
Makes an HTTP request.
Syntax
void MakeHttpRequest(AZStd::string url, AZStd::string method, AZStd::string jsonBody)
Parameter
url method jsonBody
Type
AZStd::string
AZStd::string
AZStd::string
Description
The request URL.
The HTTP request method.
The JSON body of the request.
HMD device bus used to communicate with the rest of the engine. Every device supported by the engine lives in its own Gem and supports this bus. A device wraps the underlying SDK into a single object for easy use by the rest of the system. Every device created should register with the EBus in order to be picked up as a usable device during initialization by the EBus function
BusConnect
().
Gets the most recent HMD tracking state.
Syntax
TrackingState* GetTrackingState()
Returns:
The tracking state.
Return Type:
TrackingState*
Default Return:
nullptr
Center the current pose for the HMD based on the current direction in which the viewer is looking.
Version 1.10
693
Lumberyard Developer Guide
HMDDeviceRequestBus
Syntax
void RecenterPose()
Set the current tracking level of the HMD. Supported tracking levels are defined in struct
TrackingLevel
.
Syntax
void SetTrackingLevel(const AZ::VR::HMDTrackingLevel level)
Parameter
level
Type Description
AZ::VR::HMDTrackingLevel
The tracking level to use with the current HMD.
Possible values: kHead
- The sensor reads as if the player is standing.
kFloor
- The sensor reads as if the player is seated or on the floor.
Outputs the information about the currently connected HMD (contained in the
HMDDeviceInfo
object) to the console and log file.
Syntax
void OutputHMDInfo()
Get the device info object for this particular HMD.
Syntax
HMDDeviceInfo* GetDeviceInfo()
Returns:
A pointer to the current HMD's
HMDDeviceInfo
struct .
Return Type:
HMDDeviceInfo*
Default Return:
nullptr
Gets whether or not the HMD has been initialized. The HMD has been initialized when it has fully established an interface with its required SDK and is ready to be used.
Syntax
Version 1.10
694
Lumberyard Developer Guide
ControllerRequestBus bool IsInitialized()
Returns:
true
if the device has been initialized and is usable; otherwise, returns false
.
Return Type:
bool
Default Return:
false
Provides information about HMD device controllers.
Returns a
TrackingState
object that contains tracking info about a connected controller. For more information, see struct TrackingState .
Syntax
TrackingState* GetTrackingState(ControllerIndex controllerIndex)
Parameter Type
controllerIndex int
Description
Specify 0 for the left controller; 1 for the right controller.
Returns:
A pointer to the
TrackingState
object for the connected controller.
Return Type:
TrackingState*
Default Return:
nullptr
Returns whether the specified controller is connected.
Syntax
bool IsConnected(ControllerIndex controllerIndex)
Parameter Type
controllerIndex int
Description
Specify 0 for the left controller; 1 for the right controller.
Returns:
A Boolean that indicates whether the specified controller is connected.
Return Type:
bool
Default Return:
false
Version 1.10
695
Lumberyard Developer Guide
VideoPlaybackRequestBus
Provides access to video playback services.
Start or resume playing a movie that is attached to the current entity.
Syntax
void Play()
Pause a movie that is attached to the current entity.
Syntax
void Pause()
Stop playing a movie that is attached to the current entity.
Syntax
void Stop()
Set whether or not the movie attached to the current entity loops.
Syntax
void EnableLooping(bool enable)
Parameter
enable
Type
bool
Description
Specify true
to loop; false
to not loop.
Returns whether or not the video is currently playing
Syntax
bool IsPlaying()
Returns:
true
if the video is currently playing; false
if the video is paused or stopped.
Version 1.10
696
Lumberyard Developer Guide
VideoPlaybackNotificationBus
Return Type:
bool
Default Return:
false
Sets the playback speed based on a factor of the current playback speed.
Syntax
void SetPlaybackSpeed(float speedFactor)
Parameter
speedFactor
Type
float
Description
The speed modification factor to apply to playback speed. For example, specify 0.5f to play at half speed or 2.0f to play at double speed.
This bus contains event handlers for video playback services.
Event that fires when the movie starts playback.
Syntax
void OnPlaybackStarted()
Event that fires when the movie pauses playback.
Syntax
void OnPlaybackPaused()
Event that fires when the movie stops playback.
Syntax
void OnPlaybackStopped()
Event that fires when the movie completes playback.
Syntax
Version 1.10
697
Lumberyard Developer Guide
VR Lua Functions void OnPlaybackFinished()
You can use Lua bindings to interact programmatically with head-mounted display (HMD) devices that provide Virtual Reality (VR) experiences.
For general information on configuring your Lumberyard game project for VR, see Virtual Reality in the
Amazon Lumberyard User Guide .
The following functions provide programming interfaces for HMD devices.
Function Description
Returns an
HMDDeviceRequestBusSender object that is connected to the specified entity. For more information, see
.
Returns a
ControllerRequestBusSender object that is connected to the specified entity. For more information, see
ControllerRequestBus (p. 699) .
Contains functions that return information about an HMD and control its pose and tracking level.
Function
Bool IsInitialized()
Void RecenterPose()
Void OutputHMDInfo()
Description
Returns true
if an HMD has successfully initialized on the bus. Returns false
if no HMD is connected or failed to initialize.
Causes the direction that the HMD is currently facing to be considered forward’.
Outputs the information about the currently connected HMD
(contained in the HMDDeviceInfo object) to the console and log file.
Void SetTrackingLevel(int)
Sets the tracking level for the HMD. 0 specifies head level tracking (the player is standing); 1 is floor level tracking (the player is seated or on the floor).
Returns an
HMDDeviceInfo
object that contains device information about a connected HMD. For more information, see
.
Returns a
TrackingState
object that contains the most recent tracking information about a connected HMD. For more information, see
.
Version 1.10
698
Lumberyard Developer Guide
ControllerRequestBus
Returns status information about an HMD controller.
Function
Bool IsConnected(int controllerIndex) controllerIndex)
Description
Returns true if the given controller is connected, false if a controller is not connected. Pass 0 for the left controller, pass 1 for the right controller.
Returns a
TrackingState
object that contains tracking info about a connected controller. Pass 0 for the left controller, pass 1 for the right controller. For more information, see
Contains information about a device that displays on the screen when the device is detected.
Field
String productName
String manufacturer
Int renderWidth
Int renderHeight
Float fovH
Float fovV
Description
Name of the connected HMD. The default is nullptr
.
Name of the company that manufactured the connected HMD. The default is nullptr
.
The render width for the HMD in pixels. This is normally half the full resolution of the device (rendering is per eye). The default is
0
.
The render height in pixels for a single eye of the HMD. The default is
0
.
The horizontal field of view for both eyes in radians. The default is
0.0f
.
The vertical field of view in radians. The default is
0.0f
.
Stores position and connection state information about the HMD. When an HMD is in use, certain parts of the device can go offline or online. For example, a controller can be disconnected, or the HMD can temporarily lose rotational tracking. You can use the
TrackingState
to determine what part of the pose is currently valid.
Field
PoseState pose
Description
The position and orientation in object space of the HMD. For more information, see
DynamicsState dynamics
Int statusFlags
Contains the current state of the physics dynamics for the current device such as linear velocity, angular velocity, and acceleration. For more information, see
.
Bit field that describes the current tracking state. For bit flags, see the
.
Version 1.10
699
Lumberyard Developer Guide struct PoseState
A specific pose of the HMD device. Each HMD device has its own way of representing its current pose in three dimensional space. This structure acts as a common data set between a connected device and the rest of the system. All data is in a local coordinate space.
Field Description
Quaternion orientation
A quaternion representing the current orientation in object space of the HMD.
Vector3 position
A three dimensional vector representing the current position of the HMD in object space as an offset from the centered pose.
Dynamics (accelerations and velocities) of the current HMD. Many HMDs have the ability to track the current movements of VR devices for prediction. Not all devices support velocities and accelerations. All data is in a local coordinate space.
Field
Vector3 angularVelocity
Description
A three dimensional vector representing angular velocity in object space.
Vector3 angularAcceleration
A three dimensional vector representing angular acceleration in object space.
Vector3 linearVelocity
A three dimensional vector representing linear velocity in object space.
Vector3 linearAcceleration
A three dimensional vector representing linear acceleration in object space.
The following code shows the status flags for HMDStatus.
enum HMDStatus
{
HMDStatus_OrientationTracked = BIT(1),
HMDStatus_PositionTracked = BIT(2),
HMDStatus_CameraPoseTracked = BIT(3),
HMDStatus_PositionConnected = BIT(4),
HMDStatus_HmdConnected = BIT(5),
HMDStatus_IsUsable = HMDStatus_HmdConnected | HMDStatus_OrientationTracked,
HMDStatus_ControllerValid = HMDStatus_OrientationTracked | HMDStatus_PositionConnected,
};
You can use the following Lua scripting functions when you work with UI canvases in Lumberyard Editor.
For non-UI component entity Lua scripting functions, see the Component Entity Lua API Reference .
Version 1.10
700
Lumberyard Developer Guide
LyShineLua.ShowMouseCursor
Topics
•
LyShineLua.ShowMouseCursor (p. 701)
•
•
•
•
•
•
UIDropTargetComponent (p. 713)
•
UIDynamicLayoutComponent (p. 715)
•
UIDynamicScrollBoxComponent (p. 715)
•
•
•
•
UIInteractableComponent (p. 722)
•
•
UiLayoutCellComponent (p. 730)
•
UILayoutColumnComponent (p. 732)
•
UILayoutGridComponent (p. 733)
•
•
•
•
•
•
•
•
•
UITooltipDisplayComponent (p. 758)
•
UITransform2dComponent (p. 760)
•
Controls the visibility of the mouse cursor.
1
specifies that the mouse cursor is displayed;
0
specifies that it is hidden.
Syntax
void ShowMouseCursor(bool visible)
You can use a button component to make an element behave like a button.
Services messages for the
UiButtonComponent
.
Version 1.10
701
Lumberyard Developer Guide
UICanvasComponent
GetOnClickActionName
Returns the action triggered when the button is released.
Syntax
AZStd::string UiButtonBus::GetOnClickActionName()
SetOnClickActionName
Sets the action triggered when the button is released.
Syntax
void UiButtonBus::SetOnClickActionName(const AZStd::string& actionName)
Services notifications for the
UiButtonComponent
.
OnButtonClick
Occurs when a button has been clicked.
Syntax
void OnButtonClick()
Contains buses and notification buses for UI canvas and animation.
Services messages for the
UiCanvasComponent
.
FindElementByName
Returns the entity ID of the first UI element in this canvas that has the specified name.
Syntax
AZ::EntityId FindElementByName(const AZStd::string& name)
GetChildElement
Returns the entity ID of the child element that has the specified index.
Syntax
AZ::EntityId GetChildElement(int index)
GetChildElements
Returns a list of entity IDs of the child elements of the canvas.
Version 1.10
702
Lumberyard Developer Guide
UICanvasComponent
Syntax
AZStd::vector<AZ::EntityId> GetChildElements()
GetDrawOrder
Returns the draw order on the canvas.
Syntax
int GetDrawOrder()
GetEnabled
Returns the enabled flag of the canvas. True if the canvas is enabled; false otherwise. Enabled canvases are updated and rendered for each frame.
Syntax
bool GetEnabled()
GetIsNavigationSupported
Returns true if the canvas accepts navigation input; false otherwise.
Syntax
bool GetIsNavigationSupported()
GetIsPixelAligned
Returns true if pixel alignment is enabled for this canvas; false otherwise. If pixel alignment is enabled, then all corners of all elements are rounded to the nearest pixel when they are rendered.
Syntax
bool GetIsPixelAligned()
GetIsRenderToTexture
Returns true if the canvas is rendered to a texture instead of the full screen; false otherwise.
Syntax
bool GetIsRenderToTexture()
GetKeepLoadedOnLevelUnload
Returns true if the canvas stays loaded when the level is unloaded; false
otherwise.
Syntax
bool GetKeepLoadedOnLevelUnload()
Version 1.10
703
Lumberyard Developer Guide
UICanvasComponent
GetNumChildElements
Returns the number of child elements that the canvas has.
Syntax
int GetNumChildElements()
GetRenderTargetName
Returns the name of the texture that is created when this canvas is rendered to a texture.
Syntax
AZStd::string GetRenderTargetName()
GetTooltipDisplayElement
Returns the entity ID of the tooltip element that is to be displayed when the pointer pauses on an interactable element.
Syntax
AZ::EntityId GetTooltipDisplayElement()
RecomputeChangedLayouts
Tells the layout manager for the canvas to recompute the layout. This happens automatically every frame. Occasionally a script modifies something that affects the layout (such as the reparenting of an element) and tries to query positions in the same frame. In this case you can call
RecomputeChangedLayouts
to force an immediate recalculation of all layouts on the canvas that have been flagged for recomputing.
Syntax
void RecomputeChangedLayouts()
SetDrawOrder
Sets the draw order on the canvas.
Syntax
void SetDrawOrder(int drawOrder)
SetEnabled
Sets whether the canvas is enabled. Enabled canvases are updated and rendered for each frame. Specify true to enable the canvas, false to disable.
Syntax
void SetEnabled(bool enabled)
Version 1.10
704
Lumberyard Developer Guide
UICanvasComponent
SetHoverInteractable
Sets the interactable element on the canvas on which the pointer has been paused.
Note
This action is done automatically, but in unusual situations it can be useful to call this function from a script.
Syntax
void SetHoverInteractable(AZ::EntityId entityId)
SetIsNavigationSupported
Specify true to make the canvas accept navigation input; false otherwise.
Syntax
void SetIsNavigationSupported(bool isSupported)
SetIsPixelAligned
Specify true to enable pixel alignment for this canvas; false otherwise.
Syntax
void SetIsPixelAligned(bool isPixelAligned)
SetIsRenderToTexture
Sets whether the canvas is rendered to a texture instead of the full screen. Specify true to render the canvas to a texture; false otherwise.
Syntax
void SetIsRenderToTexture(bool isRenderToTexture)
SetKeepLoadedOnLevelUnload
Sets whether the canvas stays loaded when the level is unloaded. Specify true to keep the canvas loaded on level unload; false otherwise.
Syntax
void SetKeepLoadedOnLevelUnload(bool keepLoaded)
SetRenderTargetName
Sets the name of the texture that is created when this canvas is rendered to a texture.
Syntax
void SetRenderTargetName(const AZStd::string& name)
Version 1.10
705
Lumberyard Developer Guide
UICanvasComponent
SetTooltipDisplayElement
Sets the element that is to be displayed when the pointer pauses over an interactable element.
Syntax
void SetTooltipDisplayElement(AZ::EntityId entityId)
Services notifications for the
UiCanvasComponent
.
OnAction
Maps the name of an action to the entity ID of a canvas component that triggers the action.
Syntax
void OnAction(AZ::EntityId entityId, const AZStd::string& actionName)
Animation messages serviced by the
UiCanvasComponent
.
AbortSequence
Aborts the specified sequence.
Syntax
void AbortSequence (const AZStd::string& sequenceName)
GetSequencePlayingSpeed
Returns the current playing speed of the specified sequence.
Syntax
float GetSequencePlayingSpeed(const AZStd::string& sequenceName)
GetSequencePlayingTime
Returns the current playing time of the specified sequence.
Syntax
float GetSequencePlayingTime(const AZStd::string& sequenceName)
IsSequencePlaying
Returns true if the specified sequence is playing; false otherwise.
Syntax
bool IsSequencePlaying(const AZStd::string& sequenceName)
Version 1.10
706
Lumberyard Developer Guide
UICanvasComponent
PauseSequence
Pauses the specified sequence.
Syntax
void PauseSequence (const AZStd::string& sequenceName)
ResetSequence
Resets the specified sequence to the start.
Syntax
void ResetSequence (const AZStd::string& sequenceName)
ResumeSequence
Causes the specified sequence to resume.
Syntax
void ResumeSequence (const AZStd::string& sequenceName)
SetSequencePlayingSpeed
Sets the current playing speed of the specified sequence.
Syntax
void SetSequencePlayingSpeed(const AZStd::string& sequenceName, float speed)
StartSequence
Starts playing the specified sequence.
Syntax
void StartSequence(const AZStd::string& sequenceName)
StopSequence
Stops playing the specified sequence.
Syntax
void StopSequence (const AZStd::string& sequenceName)
Services animation notifications for the
UiCanvasComponent
.
OnUiAnimationEvent
Specifies the animation event for the specified sequence.
Version 1.10
707
Lumberyard Developer Guide
UICanvasManager
Syntax
void OnUiAnimationEvent(eUiAnimationEvent uiAnimationEvent, AZStd::string animSequenceName)
Following are possible values for the eUiAnimationEvent
flag.
enum eUiAnimationEvent
{
eUiAnimationEvent_Started,
eUiAnimationEvent_Stopped,
eUiAnimationEvent_Aborted,
eUiAnimationEvent_Updated
};
Contains functions for loading, unloading, and finding UI canvases.
Services messages for the
UiCanvasManager
component.
FindLoadedCanvasByPathName
Returns the entity ID of the loaded canvas that has the specified canvas pathname.
Syntax
AZ::EntityId FindLoadedCanvasByPathName(const AZStd::string& canvasPathname)
LoadCanvas
Loads a canvas and returns the entity ID of the loaded canvas.
Syntax
AZ::EntityId LoadCanvas(const AZStd::string& canvasPathname)
UnloadCanvas
Unloads a UI canvas.
Syntax
void UnloadCanvas(AZ::EntityId canvasEntityId)
You can use this component to implment a UI check box in Amazon Lumberyard.
Services messages for the
UiCheckboxComponent
.
Version 1.10
708
Lumberyard Developer Guide
UICheckboxComponent
GetChangedActionName
Returns the action triggered when the check box value changes.
Syntax
AZStd::string & GetChangedActionName()
GetCheckedEntity
Returns the child element that is shown when the check box is selected.
Syntax
AZ::EntityId GetCheckedEntity()
GetState
Returns the state of the check box. True if selected; false otherwise.
Syntax
bool GetState()
GetTurnOffActionName
Returns the action triggered when the check box is is cleared.
Syntax
const AZStd::string & GetTurnOffActionName()
GetTurnOnActionName
Returns the name of the action that is triggered when the check box is selected.
Syntax
const AZStd::string& GetTurnOnActionName()
GetUncheckedEntity
Returns the child element that is shown when the check box is cleared.
Syntax
AZ::EntityId GetUncheckedEntity()
SetChangedActionName
Sets the action triggered when the check box value changes.
Syntax
Version 1.10
709
Lumberyard Developer Guide
UICheckboxComponent void SetChangedActionName(const AZStd::string& actionName)
SetCheckedEntity
Sets the child element to show when the check box is selected.
Syntax
void SetCheckedEntity(AZ::EntityId entityId)
SetState
Sets the state of the check box. True if selected; false otherwise.
Syntax
void SetState(bool checked)
SetTurnOffActionName
Sets the action triggered when the check box is is cleared.
Syntax
void SetTurnOffActionName(const AZStd::string & actionName)
SetTurnOnActionName
Sets the action triggered when the check box is is selected.
Syntax
void SetTurnOnActionName(const AZStd::string & actionName)
SetUncheckedEntity
Sets the child element to show when the check box is cleared.
Syntax
void SetUncheckedEntity(AZ::EntityId entityId)
ToggleState
Toggles the state of the check box.
Syntax
bool ToggleState()
Services notifications for the
UiCheckboxComponent
.
Version 1.10
710
Lumberyard Developer Guide
UIDraggableComponent
OnCheckboxStateChange
Notifies that the check box state has changed.
Syntax
void OnCheckboxStateChange(bool checked)
You can use a draggable component to make an element draggable for drag-and-drop behavior.
Services messages for the
UiDraggableComponent
.
GetCanDropOnAnyCanvas
Gets the flag that indicates whether this draggable can be dropped on this canvas or any loaded canvas.
Syntax
bool GetCanDropOnAnyCanvas()
GetDragState
Returns the current drag state of the draggable component.
Syntax
eUiDragState GetDragState()
Following are possible values for eUiDragState
.
enum eUiDragState
{
eUiDragState_Normal,
eUiDragState_Valid,
eUiDragState_Invalid
};
GetOriginalFromProxy
Gets the original draggable component from a draggable component that is acting as a proxy.
Syntax
AZ::EntityId GetOriginalFromProxy()
IsProxy
Checks whether a draggable component is acting as a proxy for another draggable component.
Syntax
Version 1.10
711
Lumberyard Developer Guide
UIDraggableComponent bool IsProxy()
ProxyDragEnd
Concludes the drag of a proxy. Call
ProxyDragEnd
at the end of a drag if
SetAsProxy
was used for the drag. Call
ProxyDragEnd
from the
OnDragEnd
handler of the proxy element. This results in a call to
OnDragEnd
for the original draggable component.
Syntax
void ProxyDragEnd(AZ::Vector2 point)
RedoDrag
Causes the draggable component to redetect the drop targets that are underneath the pointer and resend
OnDropHoverStart
or
OnDropHoverEnd
messages if needed. You can call
RedoDrag
from a script after the script has caused drop targets to change positions. This function is most useful for keyboard or gamepad navigation.
Syntax
void RedoDrag(AZ::Vector2 point)
SetAsProxy
Sets a draggable component to act as a proxy for another draggable component and starts dragging the draggable component at the specified point. A proxy is useful if you want the visible element being dragged to be on a canvas other than the one on which the original draggable component is selected. It is also useful if you want to avoid moving the original draggable component.
Syntax
void SetAsProxy(AZ::EntityId originalDraggableId, AZ::Vector2 point)
SetCanDropOnAnyCanvas
Sets the flag that indicates whether a draggable can be dropped on this canvas or any loaded canvas.
Syntax
void SetCanDropOnAnyCanvas(bool anyCanvas)
SetDragState
Sets the current drag state of the draggable component.
Syntax
void SetDragState(eUiDragState dragState)
For possible values for eUiDragState
, see
Services notifications for the
UiDraggableComponent
.
Version 1.10
712
Lumberyard Developer Guide
UIDropTargetComponent
OnDrag
Occurs each time the drag position changes during dragging.
OnDrag
events happen only between
OnDragStart
and
OnDragEnd
events.
Syntax
void OnDrag(AZ::Vector2 position)
OnDragEnd
Occurs at the end of dragging when the release input event occurs. The
OnDragEnd
notification is sent before the
OnDrop
drop target notification.
Syntax
void OnDragEnd(AZ::Vector2 position)
OnDragStart
Occurs when dragging is detected on the draggable component. For mouse or touch input, this occurs when movement has been detected after the press or touch.
Syntax
void OnDragStart(AZ::Vector2 position)
You can use a drop target component to make an element a target for drag-and-drop behavior.
Services messages for the
UiDropTargetComponent
.
GetDropState
Returns the current drop state of the drop target component.
Syntax
eUiDropState GetDropState()
Following are possible values for eUiDropState
.
enum eUiDropState
{
eUiDropState_Normal,
eUiDropState_Valid,
eUiDropState_Invalid
};
GetOnDropAction
Returns the action triggered when a draggable component is dropped on this drop target.
Version 1.10
713
Lumberyard Developer Guide
UIDropTargetComponent
Syntax
const AZStd::string& GetOnDropAction()
SetDropState
Sets the current drop state of the drop target component.
Syntax
Void SetDropState(eUiDropState dragState)
For possible values for eUiDropState
, see
.
SetOnDropAction
Sets the action triggered when a draggable component is dropped on this drop target.
Syntax
void SetOnDropAction(const AZStd::string& actionName)
Tip
A more flexible way to be notified when a drop occurs is to use the
UiDropTargetNotificationBus (p. 714) .
Services notifications for the
UiDropTargetComponent
.
OnDrop
Occurs when a draggable component is dropped on this drop target. The draggable component is passed in. Implement the game logic of what should happen on drag and drop here.
Syntax
void OnDrop(AZ::EntityId draggable)
OnDropHoverEnd
Occurs when the focus stops being on this drop target during dragging. The draggable component that is being dragged is passed into this function.
Syntax
void OnDropHoverEnd(AZ::EntityId draggable)
OnDropHoverStart
Occurs when the focus starts to be on this drop target during dragging. The draggable component that is being dragged is passed into this function.
Syntax
Version 1.10
714
Lumberyard Developer Guide
UIDynamicLayoutComponent void OnDropHoverStart(AZ::EntityId draggable)
Clones a prototype element to achieve the specified number of child elements.
Services messages for the
UiDynamicLayoutComponent
.
SetNumChildElements
Specifies the number of child elements to be created dynamically.
Syntax
void SetNumChildElements(int numChildren)
Dynamically sets up scrollbox content as a horizontal or vertical list of elements that are cloned from a prototype element. For efficient scrolling, only the minimum number of elements are created.
Services messages for the
UiDynamicScrollBoxComponent
.
GetChildElementAtLocationIndex
Returns the child element at the specified location index.
Syntax
AZ::EntityId GetChildElementAtLocationIndex(int index)
GetLocationIndexOfChild
Returns the location index of the specified child element. Returns -1 if not found.
Syntax
int GetLocationIndexOfChild(AZ::EntityId childElement)
RefreshContent
Refreshes the content. You should call this when the list size or element content has changed.
Syntax
void RefreshContent()
Create this handler to provide a dynamic scrollbox with the number of elements to display.
Version 1.10
715
Lumberyard Developer Guide
UIElementComponent
GetNumElements
Returns the total number of elements that the dynamic scrollbox is to display.
Syntax
int GetNumElements()
Create this handler to receive notifications of dynamic scrollbox element state changes, such as when an element is about to scroll into view.
OnElementBecomingVisible
An element is about to become visible. Use this event to populate the element with data for display.
Specifies the entity ID of the element that is about to become visible and its location index.
Syntax
void OnElementBecomingVisible(AZ::EntityId entityId, int index)
Provides functionality for UI elements.
Services messages for the
UiElementComponent
.
DestroyElement
Deletes this element and removes it from its parent element.
Syntax
Void DestroyElement()
FindChildByName
Returns the first immediate child with the specified name. Returns
AZ::InvalidEntityId
if no match is found.
Syntax
AZ::EntityId FindChildByName(const AZStd::string & name)
FindDescendantByName
Returns the first descendant entity with the specified name. Returns
AZ::InvalidEntityId
if no match is found.
Syntax
Version 1.10
716
Lumberyard Developer Guide
UIElementComponent
AZ::EntityId FindDescendantByName(const AZStd::string & name)
GetCanvas
Returns the canvas that contains this element. Returns
AZ::InvalidEntityId
if the element has no canvas.
Syntax
AZ::EntityId GetCanvas()
GetChild
Returns the child at the specified index. Index must be less than
GetNumChildElements()
.
Syntax
AZ::EntityId GetChild(int index)
GetChildren
Returns the child elements of this element.
Syntax
AZStd::vector<AZ::EntityId> GetChildren()
GetIndexOfChildByEntityId
Returns the index of the specified child element.
Syntax
int GetIndexOfChildByEntityId(AZ::EntityId childId)
GetName
Returns the name of this element.
Syntax
AZStd::string GetName()
GetNumChildElements
Returns the number of child elements of this element.
Syntax
int GetNumChildElements()
GetParent
Returns the parent of this element. Returns an invalid entity ID if the element has no parent.
Version 1.10
717
Lumberyard Developer Guide
UIFaderComponent
Syntax
AZ::EntityId GetParent()
IsEnabled
Returns true if the element is enabled; false otherwise.
Syntax
bool IsEnabled()
Reparent
Changes this element to be the child of a new parent. The element is removed from its current parent and added as a child of newParent
. If newParent
is invalid, the element becomes a top-level element.
If insertBefore
is a valid entity ID, then the element is inserted before the insertBefore
element if insertBefore
is a child of the new parent.
Syntax
void Reparent(AZ::EntityId newParent, AZ::EntityId insertBefore)
SetIsEnabled
Sets the enabled state of the element.
Syntax
void SetIsEnabled(bool isEnabled)
You can use a fader component to simultaneously adjust the transparency of an element and its children.
Services messages for the
UiFaderComponent
.
Fade
Triggers a fade animation.
Syntax
void Fade(float targetValue, float speed)
Parameter Description
targetValue
The value at which to end the fade [0,1].
speed
The speed of the fade animation in full fade amount per second; 0 means instant.
Version 1.10
718
Lumberyard Developer Guide
UIFaderComponent
GetFadeValue
Returns the fade value. The fade value is a float between zero and one. One means no fade; zero means complete fade to invisible.
Syntax
float GetFadeValue()
IsFading
Returns whether a fade animation is taking place.
Syntax
bool IsFading()
SetFadeValue
Sets the fade value.
Syntax
void SetFadeValue(float fade)
Services notifications for the
UiFaderComponent
.
OnDestroyed
The fader component has been destroyed.
Syntax
void OnFaderDestroyed()
OnFadeComplete
The fade animation is done.
Syntax
void OnFadeComplete()
OnFadeInterrupted
The fade animation has been interrupted.
Syntax
void OnFadeInterrupted()
Version 1.10
719
Lumberyard Developer Guide
UIImageComponent
Controls sprites, images, and textures.
Services messages for the
UiImageComponent
.
GetColor
Returns the color tint for the image.
Syntax
AZ::Color GetColor()
SetColor
Sets the color tint for the image.
Syntax
void SetColor(const AZ::Color& color)
GetSpritePathname
Returns the source location of the image to be displayed by the element.
Syntax
AZStd::string GetSpritePathname()
SetSpritePathname
Sets the source location of the image to be displayed by the element.
Syntax
void SetSpritePathname(AZStd::string spritePath)
GetRenderTargetName
Returns the name of the render target associated with the sprite.
Syntax
AZStd::string GetRenderTargetName()
SetRenderTargetName
Sets the name of the render target associated with the sprite.
Syntax
Version 1.10
720
Lumberyard Developer Guide
UIImageComponent void SetRenderTargetName(AZStd::string renderTargetName)
GetSpriteType
Returns the type of the sprite.
Syntax
eUiSpriteType GetSpriteType()
Possible sprite types are as follows.
enum eUiSpriteType
{
eUiSpriteType_SpriteAsset,
eUiSpriteType_RenderTarget
};
SetSpriteType
Sets the type of the sprite.
Syntax
void SetSpriteType(eUiSpriteType spriteType)
For possible sprite types, see
GetImageType
Returns the type of the image. Affects how the texture or sprite is mapped to the image rectangle.
Syntax
eUiImageType GetImageType()
Possible values for eUiImageType
are as follows.
enum eUiImageType
{
eUiImageType_Stretched,
eUiImageType_Sliced,
eUiImageType_Fixed,
eUiImageType_Tiled,
eUiImageType_StretchedToFit,
eUiImageType_StretchedToFill
};
SetImageType
Sets the type of the image. Affects how the texture or sprite is mapped to the image rectangle.
Syntax
void SetImageType(eUiImageType imageType)
Version 1.10
721
Lumberyard Developer Guide
UIInteractableComponent
For possible values for eUiImageType
, see
.
Controls elements that respond to user input.
Services messages for the
UiInteractableComponent
.
IsHandlingEvents
Returns true if event handling is enabled; false otherwise.
Syntax
bool IsHandlingEvents()
SetIsHandlingEvents
Sets whether event handling is enabled.
Syntax
void SetIsHandlingEvents(bool isHandlingEvents)
Services actions for the
UiInteractableComponent
.
GetHoverEndActionName
Returns the current hover end action name.
Syntax
AZStd::string& GetHoverEndActionName()
GetHoverStartActionName
Returns the current hover start action name.
Syntax
AZStd::string& GetHoverStartActionName()
GetPressedActionName
Returns the pressed action name.
Syntax
AZStd::string& GetPressedActionName()
Version 1.10
722
Lumberyard Developer Guide
UIInteractableComponent
GetReleasedActionName
Returns the released action name.
Syntax
AZStd::string& GetReleasedActionName()
SetHoverEndActionName
Sets the hover end action name.
Syntax
SetHoverEndActionName(const AZStd::string& actionName)
SetHoverStartActionName
Sets the hover start action name.
Syntax
SetHoverStartActionName(const AZStd::string& actionName)
SetPressedActionName
Sets the pressed action name.
Syntax
SetPressedActionName(const AZStd::string& actionName)
SetReleasedActionName
Sets the released action name.
Syntax
SetReleasedActionName(const AZStd::string& actionName)
Services states for the
UiInteractableComponent
.
GetStateAlpha
Returns the alpha to be used for the specified target when the interactable element is in the specified state.
Syntax
float GetStateAlpha(eUiInteractableState state, AZ::EntityId target)
Version 1.10
723
Lumberyard Developer Guide
UIInteractableComponent
GetStateColor
Returns the color to be used for the specified target when the interactable element is in the specified state.
Syntax
AZ::Color GetStateColor(eUiInteractableState state, AZ::EntityId target)
Possible values for eUiInteractableState
are as follows.
enum eUiInteractableState
{
eUiInteractableState_Normal,
eUiInteractableState_Hover,
eUiInteractableState_Pressed,
eUiInteractableState_Disabled
};
GetStateFontEffectIndex
Returns the font effect to be used for the specified target when the interactable element is in the specified state..
Syntax
unsigned int GetStateFontEffectIndex(eUiInteractableState state, AZ::EntityId target)
GetStateFontPathname
Returns the font path to be used for the specified target when the interactable element is in the specified state..
Syntax
AZStd::string GetStateFontPathname(eUiInteractableState state, AZ::EntityId target)
GetStateSpritePathname
Returns the sprite path to be used for the specified target when the interactable element is in the specified state..
Syntax
AZStd::string GetStateSpritePathname(eUiInteractableState state, AZ::EntityId target)
HasStateAlpha
Returns true if the interactable element has an alpha action for the specified state and target combination..
Syntax
bool HasStateAlpha(eUiInteractableState state, AZ::EntityId target)
Version 1.10
724
Lumberyard Developer Guide
UIInteractableComponent
HasStateColor
Returns true if the interactable element has a color action for the specified state and target combination..
Syntax
bool HasStateColor(eUiInteractableState state, AZ::EntityId target)
HasStateFont
Returns true if the interactable element has a font action for the specified state and target combination..
Syntax
bool HasStateFont(eUiInteractableState state, AZ::EntityId target)
HasStateSprite
Returns true if the interactable element has a sprite action for the specified state and target combination..
Syntax
bool HasStateSprite(eUiInteractableState state, AZ::EntityId target)
SetStateAlpha
Sets the alpha to be used for the specified target when the interactable element is in the specified state. If the interactable element already has an alpha action for this state and target combination, then
SetStateAlpha
replaces the alpha action.
Syntax
void SetStateAlpha(eUiInteractableState state, AZ::EntityId target, float alpha)
SetStateColor
Sets the color to be used for the specified target when the interactable element is in the specified state.
If the interactable element already has a color action for the current state and target combination, then
SetStateColor
replaces the color action.
Syntax
void SetStateColor(eUiInteractableState state, AZ::EntityId target, const AZ::Color& color)
SetStateFont
Sets the font to be used for the specified target when the interactable element is in the specified state.
If the interactable element already has a font action for the specified state and target combination, then
SetStateFont
replaces the font action.
Syntax
Version 1.10
725
Lumberyard Developer Guide
UIInteractableComponent void SetStateFont(eUiInteractableState state, AZ::EntityId target, const AZStd::string&
fontPathname, unsigned int fontEffectIndex)
SetStateSpritePathname
Sets the sprite path to be used for the specified target when the interactable element is in the specified state. If the interactable element already has a sprite action for the specified state and target combination, then
SetStateSpritePathname
replaces the sprite action.
Syntax
void SetStateSpritePathname(eUiInteractableState state, AZ::EntityId target, const
AZStd::string& spritePath)
Services notifications for the
UIInteractableComponent
.
OnHoverEnd
Called on hover end.
Syntax
void OnHoverEnd()
OnHoverStart
Called on hover start.
Syntax
void OnHoverStart()
OnPressed
Called when an element has been pressed.
Syntax
void OnPressed()
OnReleased
Called when an element has been released.
Syntax
void OnReleased()
Services navigation for the
UIInteractableComponent
.
Version 1.10
726
Lumberyard Developer Guide
UIInteractableComponent
GetNavigationMode
Returns the navigation mode.
Syntax
eUiNavigationMode GetNavigationMode()
Possible values for eUiNavigationMode
are as follows.
enum eUiNavigationMode
{
eUiNavigationMode_Automatic,
eUiNavigationMode_Custom,
eUiNavigationMode_None
};
GetOnDownEntity
Returns the ID of the entity that receives focus when down is pressed.
Syntax
AZ::EntityId GetOnDownEntity()
GetOnLeftEntity
Returns the ID of the entity to receive focus when left is pressed.
Syntax
AZ::EntityId GetOnLeftEntity()
GetOnRightEntity
Returns the ID of the entity to receive focus when right is pressed.
Syntax
AZ::EntityId GetOnRightEntity()
GetOnUpEntity
Returns the ID of the entity that receives focus when up is pressed.
Syntax
AZ::EntityId GetOnUpEntity()
SetNavigationMode
Sets the navigation mode.
Syntax
Version 1.10
727
Lumberyard Developer Guide
UiLayout void SetNavigationMode(eUiNavigationMode navigationMode)
SetOnDownEntity
Sets the entity to receive focus when down is pressed.
Syntax
void SetOnDownEntity(AZ::EntityId entityId)
SetOnLeftEntity
Sets the entity to receive focus when left is pressed.
Syntax
void SetOnLeftEntity(AZ::EntityId entityId)
SetOnRightEntity
Sets the entity to receive focus when right is pressed.
Syntax
void SetOnRightEntity(AZ::EntityId entityId)
SetOnUpEntity
Sets the entity to receive focus when up is pressed.
Syntax
void SetOnUpEntity(AZ::EntityId entityId)
Provides common functionality for row, column, and grid layouts.
Services messages for the
UILayout
components.
GetHorizontalChildAlignment
Returns the horizontal child alignment.
Syntax
eUiHAlign GetHorizontalChildAlignment()
Following are possible values for eUiHAlign
.
enum eUiHAlign
{
Version 1.10
728
Lumberyard Developer Guide
UiLayout
eUiHAlign_Left,
eUiHAlign_Center,
eUiHAlign_Right
};
GetIgnoreDefaultLayoutCells
Returns whether default layout cell values calculated by other components on the child are ignored.
Syntax
bool GetIgnoreDefaultLayoutCells()
GetVerticalChildAlignment
Returns the vertical child alignment.
Syntax
eUiVAlign GetVerticalChildAlignment()
Following are possible values for eUiVAlign
.
enum eUiVAlign
{
eUiVAlign_Top,
eUiVAlign_Center,
eUiVAlign_Bottom
};
SetHorizontalChildAlignment
Sets the horizontal child alignment.
Syntax
void SetHorizontalChildAlignment(eUiHAlign hAlign)
For possible values for eUiHAlign
, see GetHorizontalChildAlignment (p. 728)
.
SetIgnoreDefaultLayoutCells
Sets whether default layout cell values calculated by other components on the child are ignored.
Syntax
void SetIgnoreDefaultLayoutCells (bool ignore)
SetVerticalChildAlignment
Sets the vertical child alignment.
Syntax
void SetVerticalChildAlignment(eUiVAlign vAlign)
Version 1.10
729
Lumberyard Developer Guide
UiLayoutCellComponent
For possible values for eUiVAlign
, see GetVerticalChildAlignment (p. 729)
.
Overrides default layout cell values.
Services messages for the
UiLayoutCellComponent
.
GetExtraHeightRatio
Returns the overridden extra height ratio for the element. A value of –1 means that the ratio has not been overridden.
Syntax
float GetExtraHeightRatio()
GetExtraWidthRatio
Returns the overridden extra width ratio for the element. A value of –1 means that the ratio has not been overridden.
Syntax
float GetExtraWidthRatio()
GetMinHeight
Returns the overridden minimum height for the element. A value of –1 means that the height has not been overridden.
Syntax
float GetMinHeight()
GetMinWidth
Returns the overridden minimum width for the element. A value of –1 means it has not been overridden.
Syntax
float GetMinWidth()
GetTargetHeight
Returns the overridden target height for the element. A value of –1 means that the height has not been overridden.
Syntax
float GetTargetHeight()
Version 1.10
730
Lumberyard Developer Guide
UiLayoutCellComponent
GetTargetWidth
Returns the overridden target width for the element. -1 means it has not been overridden.
Syntax
float GetTargetWidth()
SetExtraHeightRatio
Sets the overridden extra height ratio for the element. A value of –1 means don’t override.
Syntax
void SetExtraHeightRatio(float height)
SetExtraWidthRatio
Sets the overridden extra width ratio for the element. A value of –1 means don’t override.
Syntax
void SetExtraWidthRatio(float width)
SetMinHeight
Sets the overridden minimum height for the element. A value of –1 means don’t override.
Syntax
void SetMinHeight(float height)
SetMinWidth
Sets the overridden minimum width for the element. A value of –1 means don’t override.
Syntax
void SetMinWidth(float width)
SetTargetHeight
Sets the overridden target height for the element. A value of –1 means don’t override.
Syntax
void SetTargetHeight(float height)
SetTargetWidth
Sets the overridden target width for the element. A value of –1 means don’t override.
Syntax
Version 1.10
731
Lumberyard Developer Guide
UILayoutColumnComponent void SetTargetWidth(float width)
Controls column layout.
Services messages for the
UiLayoutColumnComponent
.
GetOrder
Returns the vertical order for this layout.
Syntax
eUiVerticalOrder GetOrder()
Following are the possible values for eUiVerticalOrder
.
enum eUiVerticalOrder
{
eUiVerticalOrder_TopToBottom,
eUiVerticalOrder_BottomToTop
};
GetPadding
Returns, in pixels, the padding inside the edges of the element.
Syntax
UiPadding GetPadding()
Following are the possible values for
UiPadding
.
class UiPadding
{
int left;
int right;
int top;
int bottom;
};
GetSpacing
Returns, in pixels, the spacing between child elements.
Syntax
float GetSpacing()
SetOrder
Sets the vertical order for this layout.
Version 1.10
732
Lumberyard Developer Guide
UILayoutGridComponent
Syntax
void SetOrder(eUiVerticalOrder order)
For possible values for eUiVerticalOrder
, see
SetPadding
Sets the padding inside the edges of the element to the pixel value specified.
Syntax
void SetPadding(UiPadding padding)
For the possible values for
UiPadding
, see
SetSpacing
Sets the spacing between child elements to the pixel value specified.
Syntax
void SetSpacing(float spacing)
Controls grid layout characteristics.
Services messages for the
UiLayoutGridComponent
.
GetCellSize
Returns, in pixels, the size of a child element.
Syntax
AZ::Vector2 GetCellSize()
GetHorizontalOrder
Returns the horizontal order for the layout.
Syntax
eUiHorizontalOrder GetHorizontalOrder()
Following are possible values for eUiHorizontalOrder
.
enum eUiHorizontalOrder
{
eUiHorizontalOrder_LeftToRight,
eUiHorizontalOrder_RightToLeft
};
Version 1.10
733
Lumberyard Developer Guide
UILayoutGridComponent
GetPadding
Returns, in pixels, the padding inside the edges of the element.
Syntax
UiPadding GetPadding()
Following are the attributes for
UiPadding
.
class UiPadding
{
int left;
int right;
int top;
int bottom;
};
GetSpacing
Returns, in pixels, the spacing between child elements.
Syntax
AZ::Vector2 GetSpacing()
GetStartingDirection
Returns the starting direction for the layout.
Syntax
eUiLayoutGridStartingDirection GetStartingDirection()
Following are possible values for eUiLayoutGridStartingDirection
.
enum eUiLayoutGridStartingDirection
{
eUiLayoutGridStartingDirection_HorizontalOrder,
eUiLayoutGridStartingDirection_VerticalOrder
};
GetVerticalOrder
Returns the vertical order for the layout.
Syntax
eUiVerticalOrder GetVerticalOrder()
Following are possible values for eUiVerticalOrder
.
enum eUiVerticalOrder
{
eUiVerticalOrder_TopToBottom,
eUiVerticalOrder_BottomToTop
Version 1.10
734
Lumberyard Developer Guide
UILayoutGridComponent
};
SetCellSize
Sets the size of a child element to the specified number of pixels.
Syntax
void SetCellSize(AZ::Vector2 size)
SetHorizontalOrder
Sets the horizontal order for the layout.
Syntax
void SetHorizontalOrder(eUiHorizontalOrder order)
For possible values for eUiHorizontalOrder
, see GetHorizontalOrder (p. 733) .
SetPadding
Sets the padding inside the edges of the element to the specified number of pixels.
Syntax
void SetPadding(UiPadding padding)
For possible values for
UiPadding
.
SetSpacing
Sets the spacing between child elements to the specified number of pixels.
Syntax
void SetSpacing(AZ::Vector2 spacing)
SetStartingDirection
Sets the starting direction for the layout.
Syntax
void SetStartingDirection(eUiLayoutGridStartingDirection direction)
For possible values for eUiLayoutGridStartingDirection
, see GetStartingDirection (p. 734) .
SetVerticalOrder
Sets the vertical order for the layout.
Syntax
void SetVerticalOrder(eUiVerticalOrder order)
Version 1.10
735
Lumberyard Developer Guide
UILayoutRowComponent
For possible values for eUiVerticalOrder
, see
.
Controls the grid layout of rows.
Messages serviced by the
UiLayoutRowComponent
.
GetOrder
Returns the horizontal order for this layout.
Syntax
eUiHorizontalOrder GetOrder()
Following are possible values for eUiHorizontalOrder
.
enum eUiHorizontalOrder
{
eUiHorizontalOrder_LeftToRight,
eUiHorizontalOrder_RightToLeft
};
GetPadding
Returns, in pixels, the padding inside the edges of the element.
Syntax
UiPadding GetPadding()
Following are possible values for
UiPadding
.
class UiPadding
{
int left;
int right;
int top;
int bottom;
};
GetSpacing
Returns, in pixels, the spacing between child elements.
Syntax
float GetSpacing()
SetOrder
Sets the horizontal order for this layout.
Version 1.10
736
Lumberyard Developer Guide
UIMaskComponent
Syntax
void SetOrder(eUiHorizontalOrder order)
For possible values for eUiHorizontalOrder
.
SetPadding
Sets the padding inside the edges of the element to the specified number of pixels.
Syntax
void SetPadding(UiPadding padding)
For possible values for
UiPadding
.
SetSpacing
Sets the spacing between child elements to the specified number of pixels.
Syntax
void SetSpacing(float spacing)
You can add a mask component to an element to show only a part of the content of its child elements
(for example, example, image or text).
Services messages for the
UiMaskComponent
.
GetDrawBehind
Returns whether the mask is drawn behind the child elements.
Syntax
bool GetDrawBehind()
GetDrawInFront
Returns whether the mask is drawn in front of child elements.
Syntax
bool GetDrawInFront()
GetIsMaskingEnabled
Returns whether masking is enabled.
Syntax
Version 1.10
737
Lumberyard Developer Guide
UIScrollBarComponent bool GetIsMaskingEnabled()
GetUseAlphaTest
Returns whether to use the alpha channel in the mask visual's texture to define the mask.
Syntax
bool GetUseAlphaTest()
SetDrawBehind
Sets whether the mask is drawn behind the child elements.
Syntax
void SetDrawBehind(bool drawMaskVisualBehindChildren)
SetDrawInFront
Sets whether the mask is drawn in front of child elements.
Syntax
void SetDrawInFront(bool drawMaskVisualInFrontOfChildren)
SetIsMaskingEnabled
Sets whether masking is enabled.
Syntax
void SetIsMaskingEnabled(bool enableMasking)
SetUseAlphaTest
Sets whether to use the alpha channel in the mask visual's texture to define the mask.
Syntax
void SetUseAlphaTest(bool useAlphaTest)
Controls scrollbar characteristics.
Services messages for the
UiScrollBarComponent
.
GetHandleEntity
Returns the handle entity.
Version 1.10
738
Lumberyard Developer Guide
UIScrollBarComponent
Syntax
AZ::EntityId GetHandleEntity()
GetHandleSize
Returns the size of the handle relative to the scrollbar (0 - 1).
Syntax
float GetHandleSize()
GetMinHandlePixelSize
Returns the minimum size of the handle in pixels.
Syntax
float GetMinHandlePixelSize()
SetHandleEntity
Sets the handle entity.
Syntax
void SetHandleEntity(AZ::EntityId entityId)
SetHandleSize
Sets the size of the handle relative to the scrollbar (0 - 1).
Syntax
void SetHandleSize(float size)
SetMinHandlePixelSize
Sets the minimum size of the handle in pixels.
Syntax
void SetMinHandlePixelSize(float size)
Services scrolling for the
UiScrollBarComponent
.
GetOrientation
Returns the orientation of the scroller.
Syntax
Version 1.10
739
Lumberyard Developer Guide
UIScrollBarComponent eUiScrollerOrientation GetOrientation()
Following are possible values for eUiScrollerOrientation
.
enum eUiScrollerOrientation
{
eUiScrollerOrientation_Horizontal,
eUiScrollerOrientation_Vertical
};
GetValue
Returns the current value for the scroller (0 - 1).
Syntax
float GetValue()
GetValueChangedActionName
Returns the name of the action triggered when the value has changed.
Syntax
const AZStd::string& GetValueChangedActionName()
GetValueChangingActionName
Returns the name of the action triggered while the value is changing.
Syntax
AZStd::string& GetValueChangingActionName()
SetOrientation
Sets the orientation of the scroller.
Syntax
SetOrientation(eUiScrollerOrientation orientation)
For possible values for eUiScrollerOrientation
, see
SetValue
Sets the value of the scroller (0 - 1).
Syntax
void SetValue(float value)
SetValueChangedActionName
Sets the action triggered when the value has changed.
Version 1.10
740
Lumberyard Developer Guide
UIScrollBoxComponent
Syntax
void SetValueChangedActionName(const AZStd::string& actionName)
SetValueChangingActionName
Sets the name of the action triggered while the value is changing.
Syntax
void SetValueChangingActionName(const AZStd::string& actionName)
Controls the characteristics of a scroll box.
Services messages for the
UiScrollBoxComponent
.
FindClosestContentChildElement
Finds the child of the content element that is closest to the content anchors at the current scroll offset
(the currently selected child).
Syntax
AZ::EntityId FindClosestContentChildElement()
GetContentEntity
Returns the content element for the scroll box.
Syntax
AZ::EntityId GetContentEntity()
GetHorizontalScrollBarEntity
Returns the horizontal scroll bar element for the scroll box.
Syntax
AZ::EntityId GetHorizontalScrollBarEntity()
GetHorizontalScrollBarVisibility
Returns the visibility behavior for the horizontal scroll bar of the scroll box.
Syntax
eUiScrollBoxScrollBarVisibility GetHorizontalScrollBarVisibility()
Version 1.10
741
Lumberyard Developer Guide
UIScrollBoxComponent
Following are possible values for eUiScrollBoxScrollBarVisibility
.
enum eUiScrollBoxScrollBarVisibility
{
eUiScrollBoxScrollBarVisibility_AlwaysShow,
eUiScrollBoxScrollBarVisibility_AutoHide,
eUiScrollBoxScrollBarVisibility_AutoHideAndResizeViewport
};
GetIsHorizontalScrollingEnabled
Returns whether the scroll box allows horizontal scrolling.
Syntax
bool GetIsHorizontalScrollingEnabled()
GetIsScrollingConstrained
Returns whether the scroll box restricts scrolling to the content area.
Syntax
bool GetIsScrollingConstrained()
GetIsVerticalScrollingEnabled
Returns whether the scroll box allows vertical scrolling.
Syntax
bool GetIsVerticalScrollingEnabled()
GetNormalizedScrollValue
Returns the scroll value from 0 – 1.
Syntax
AZ::Vector2 GetNormalizedScrollValue()
GetScrollOffset
Returns the scroll offset of the scroll box. The scroll offset is the offset from the content element's anchor point to the content element's pivot.
Syntax
AZ::Vector2 GetScrollOffset()
GetScrollOffsetChangedActionName
Returns the action triggered when the scroll box drag is completed.
Syntax
Version 1.10
742
Lumberyard Developer Guide
UIScrollBoxComponent const AZStd::string& GetScrollOffsetChangedActionName()
GetScrollOffsetChangingActionName
Returns the action triggered while the scroll box is being dragged.
Syntax
AZStd::string& GetScrollOffsetChangingActionName()
GetSnapGrid
Returns the snapping grid of the scroll box.
Syntax
AZ::Vector2 GetSnapGrid()
GetSnapMode
Returns the snap mode for the scroll box.
Syntax
eUiScrollBoxSnapMode GetSnapMode()
Following are possible values for eUiScrollBoxSnapMode
.
enum eUiScrollBoxSnapMode
{
eUiScrollBoxSnapMode_None,
eUiScrollBoxSnapMode_Children,
eUiScrollBoxSnapMode_Grid
};
GetVerticalScrollBarEntity
Returns the vertical scroll bar element for the scroll box.
Syntax
AZ::EntityId GetVerticalScrollBarEntity()
GetVerticalScrollBarVisibility
Returns the visibility behavior for the vertical scroll bar of the scroll box.
Syntax
eUiScrollBoxScrollBarVisibility GetVerticalScrollBarVisibility()
HasHorizontalContentToScroll
Returns whether there is content to scroll horizontally.
Version 1.10
743
Lumberyard Developer Guide
UIScrollBoxComponent
Syntax
bool HasHorizontalContentToScroll()
HasVerticalContentToScroll
Returns whether there is content to scroll vertically.
Syntax
bool HasVerticalContentToScroll()
SetContentEntity
Sets the content element for the scroll box.
Syntax
void SetContentEntity(AZ::EntityId entityId)
SetHorizontalScrollBarEntity
Sets the horizontal scroll bar element for the scroll box.
Syntax
void SetHorizontalScrollBarEntity(AZ::EntityId entityId)
SetHorizontalScrollBarVisibility
Sets the visibility behavior for the horizontal scroll bar of the scroll box.
Syntax
void SetHorizontalScrollBarVisibility(eUiScrollBoxScrollBarVisibility visibility)
For possible values for eUiScrollBoxScrollBarVisibility
, see
GetHorizontalScrollBarVisibility (p. 741) .
SetIsHorizontalScrollingEnabled
Sets whether the scroll box allows horizontal scrolling.
Syntax
void SetIsHorizontalScrollingEnabled(bool isEnabled)
SetIsScrollingConstrained
Sets whether the scroll box restricts scrolling to the content area.
Syntax
void SetIsScrollingConstrained(bool isConstrained)
Version 1.10
744
Lumberyard Developer Guide
UIScrollBoxComponent
SetIsVerticalScrollingEnabled
Sets whether the scroll box allows vertical scrolling.
Syntax
void SetIsVerticalScrollingEnabled(bool isEnabled)
SetScrollOffset
Sets the scroll offset of the scroll box.
Syntax
void SetScrollOffset(AZ::Vector2 scrollOffset)
SetScrollOffsetChangedActionName
Sets the action triggered when the scroll box drag is completed.
Syntax
void SetScrollOffsetChangedActionName(const AZStd::string& actionName)
SetScrollOffsetChangingActionName
Sets the action triggered while the scroll box is being dragged.
Syntax
void SetScrollOffsetChangingActionName(const AZStd::string& actionName)
SetSnapGrid
Sets the snapping grid of the scroll box.
Syntax
void SetSnapGrid(AZ::Vector2 snapGrid)
SetSnapMode
Sets the snap mode for the scroll box.
Syntax
void SetSnapMode(eUiScrollBoxSnapMode snapMode)
For possible values for eUiScrollBoxSnapMode
SetVerticalScrollBarEntity
Sets the vertical scroll bar element for the scroll box.
Syntax
Version 1.10
745
Lumberyard Developer Guide
UISliderComponent void SetVerticalScrollBarEntity(AZ::EntityId entityId)
SetVerticalScrollBarVisibility
Sets the visibility behavior for the vertical scroll bar of the scroll box.
Syntax
void SetVerticalScrollBarVisibility(eUiScrollBoxScrollBarVisibility visibility
Services scroll offset change notifications for the
UiScrollBoxComponent
.
OnScrollOffsetChanged
Called when the scroll offset has changed.
Syntax
void OnScrollOffsetChanged(AZ::Vector2 newScrollOffset)
OnScrollOffsetChanging
Called when the scroll offset is changing.
Syntax
void OnScrollOffsetChanging(AZ::Vector2 newScrollOffset)
Services scrollable value change notifications for the
UiScrollBoxComponent
.
OnScrollableValueChanged
Called when the scroll value (0 - 1) has changed.
Syntax
void OnScrollableValueChanged(AZ::Vector2 value)
OnScrollableValueChanging
Called when the scroll value (0 - 1) is changing.
Syntax
void OnScrollableValueChanging(AZ::Vector2 value)
Controls the values of a slider.
Version 1.10
746
Lumberyard Developer Guide
UISliderComponent
Services messages for the
UiSliderComponent
.
GetFillEntity
Returns the fill element.
Syntax
AZ::EntityId GetFillEntity()
GetManipulatorEntity
Returns the entity ID of the manipulator element.
Syntax
AZ::EntityId GetManipulatorEntity()
GetMaxValue
Returns the maximum value of the slider.
Syntax
float GetMaxValue()
GetMinValue
Returns the minimum value of the slider.
Syntax
float GetMinValue()
GetStepValue
Returns the smallest increment allowed between values. Zero means no restriction.
Syntax
float GetStepValue()
GetTrackEntity
Returns the track element.
Syntax
AZ::EntityId GetTrackEntity()
GetValue
Returns the value of the slider.
Version 1.10
747
Lumberyard Developer Guide
UISliderComponent
Syntax
float GetValue()
GetValueChangedActionName
Returns the action triggered when the value has finished changing.
Syntax
const AZStd::string& GetValueChangedActionName()
GetValueChangingActionName
Returns the name of the action triggered while the value is changing.
Syntax
const AZStd::string& GetValueChangingActionName()
SetFillEntity
Sets the fill element.
Syntax
void SetFillEntity(AZ::EntityId entityId)
SetManipulatorEntity
Sets the manipulator element.
Syntax
void SetManipulatorEntity(AZ::EntityId entityId)
SetMaxValue
Sets the maximum value of the slider.
Syntax
void SetMaxValue(float value)
SetMinValue
Sets the minimum value of the slider.
Syntax
void SetMinValue(float value)
SetStepValue
Sets the smallest increment allowed between values. Use zero for no restriction.
Version 1.10
748
Lumberyard Developer Guide
UISliderComponent
Syntax
void SetStepValue(float step)
SetTrackEntity
Sets the track element.
Syntax
void SetTrackEntity(AZ::EntityId entityId)
SetValue
Sets the value of the slider.
Syntax
void SetValue(float value)
SetValueChangedActionName
Sets the action triggered when the value is done changing.
Syntax
void SetValueChangedActionName(const AZStd::string& actionName)
SetValueChangingActionName
Sets the action triggered while the value is changing.
Syntax
void SetValueChangingActionName(const AZStd::string& actionName)
Services notifications for the
UiSliderComponent
.
OnSliderValueChanged
The slider value has finished changing.
Syntax
void OnSliderValueChanged(float value)
OnSliderValueChanging
The slider value is changing.
Syntax
Version 1.10
749
Lumberyard Developer Guide
UITextComponent void OnSliderValueChanging(float value)
Controls the text and formatting of a text element.
Services messages for the
UiTextComponent
.
GetColor
Returns the color to draw the text string.
Syntax
AZ::Color GetColor()
GetFont
Returns the pathname to the font.
Syntax
AZStd::string GetFont()
GetFontEffect
Returns the font effect.
Syntax
int GetFontEffect()
GetFontSize
Returns the size of the font in points.
Syntax
float GetFontSize()
GetHorizontalTextAlignment
Returns the horizontal text alignment.
Syntax
eUiHAlign GetHorizontalTextAlignment()
Following are possible values for eUiHAlign
.
enum eUiHAlign
Version 1.10
750
Lumberyard Developer Guide
UITextComponent
{
eUiHAlign_Left,
eUiHAlign_Center,
eUiHAlign_Right
};
GetOverflowMode
Returns the overflow behavior of the text.
Syntax
eUiTextOverflowMode GetOverflowMode()
Following are possible values for eUiTextOverflowMode
.
enum eUiTextOverflowMode
{
eUiTextOverflowMode_OverflowText,
eUiTextOverflowMode_ClipText
};
GetText
Returns the text string being displayed by the element.
Syntax
AZStd::string GetText()
GetVerticalTextAlignment
Returns the vertical text alignment.
Syntax
eUiVAlign GetVerticalTextAlignment()
Following are possible values for eUiVAlign.
enum eUiVAlign
{
eUiVAlign_Top,
eUiVAlign_Center,
eUiVAlign_Bottom
};
GetWrapText
Returns whether text is wrapped.
Syntax
eUiTextWrapTextSetting GetWrapText()
Following are possible values for eUiTextWrapTextSetting
.
Version 1.10
751
Lumberyard Developer Guide
UITextComponent enum eUiTextWrapTextSetting
{
eUiTextWrapTextSetting_NoWrap,
eUiTextWrapTextSetting_Wrap
};
SetColor
Sets the color to draw the text string.
Syntax
void SetColor(const AZ::Color& color)
SetFont
Sets the pathname to the font.
Syntax
void SetFont(const AZStd::string& fontPath)
SetFontEffect
Sets the font effect.
Syntax
void SetFontEffect(int effectIndex)
SetFontSize
Sets the size of the font in points.
Syntax
void SetFontSize(float size)
SetHorizontalTextAlignment
Sets the horizontal text alignment.
Syntax
void SetHorizontalTextAlignment(eUiHAlign alignment)
For possible values for eUiHAlign
, see GetHorizontalTextAlignment (p. 750) .
SetOverflowMode
Sets the overflow behavior of the text.
Syntax
void SetOverflowMode(eUiTextOverflowMode overflowMode)
Version 1.10
752
Lumberyard Developer Guide
UITextInputComponent
For possible values for eUiTextOverflowMode
, see GetOverflowMode (p. 751) .
SetText
Sets the text string being displayed by the element.
Syntax
void SetText(const AZStd::string& text)
SetVerticalTextAlignment
Sets the vertical text alignment.
Syntax
void SetVerticalTextAlignment(eUiVAlign alignment)
For possible values for eUiVAlign
, see GetVerticalTextAlignment (p. 751) .
SetWrapText
Sets whether text is wrapped.
Syntax
void SetWrapText(eUiTextWrapTextSetting wrapSetting)
For possible values for eUiTextWrapTextSetting
, see
.
You can use a text input component to provide player text input capability.
Services messages for the
UiTextInputComponent
.
GetChangeAction
Returns the action triggered when the text is changed.
Syntax
const AZStd::string& GetChangeAction()
GetCursorBlinkInterval
Returns the cursor blink interval of the text input.
Syntax
float GetCursorBlinkInterval()
Version 1.10
753
Lumberyard Developer Guide
UITextInputComponent
GetEndEditAction
Returns the action triggered when the editing of text is finished.
Syntax
const AZStd::string& GetEndEditAction()
GetEnterAction
Returns the action triggered when enter is pressed.
Syntax
const AZStd::string& GetEnterAction()
GetIsPasswordField
Returns whether the text input is configured as a password field.
Syntax
bool GetIsPasswordField()
GetMaxStringLength
Returns the maximum number of characters that can be entered.
Syntax
int GetMaxStringLength()
GetPlaceHolderTextEntity
Returns the placeholder text element.
Syntax
AZ::EntityId GetPlaceHolderTextEntity()
GetReplacementCharacter
Returns the replacement character used to hide password text.
Syntax
char GetReplacementCharacter()
GetText
Returns the text string being displayed or edited by the element.
Syntax
Version 1.10
754
Lumberyard Developer Guide
UITextInputComponent
AZStd::string GetText()
GetTextCursorColor
Returns the color to be used for the text cursor.
Syntax
AZ::Color GetTextCursorColor()
GetTextEntity
Returns the text element.
Syntax
AZ::EntityId GetTextEntity()
GetTextSelectionColor
Returns the color to be used for the text background when it is selected.
Syntax
AZ::Color GetTextSelectionColor()
SetChangeAction
Sets the action triggered when the text is changed.
Syntax
void SetChangeAction(const AZStd::string& actionName)
SetCursorBlinkInterval
Sets the cursor blink interval of the text input.
Syntax
void SetCursorBlinkInterval(float interval)
SetEndEditAction
Sets the action triggered when the editing of text is finished.
Syntax
void SetEndEditAction(const AZStd::string& actionName)
SetEnterAction
Sets the action triggered when enter is pressed.
Version 1.10
755
Lumberyard Developer Guide
UITextInputComponent
Syntax
void SetEnterAction(const AZStd::string& actionName)
SetIsPasswordField
Sets whether the text input is configured as a password field.
Syntax
void SetIsPasswordField(bool passwordField)
SetMaxStringLength
Sets the maximum number of characters that can be entered.
Syntax
void SetMaxStringLength(int maxCharacters)
SetPlaceHolderTextEntity
Sets the placeholder text element.
Syntax
void SetPlaceHolderTextEntity(AZ::EntityId textEntity)
SetReplacementCharacter
Sets the replacement character used to hide password text.
Syntax
void SetReplacementCharacter(char replacementChar)
SetText
Sets the text string being displayed or edited by the element.
Syntax
void SetText(const AZStd::string& text)
SetTextCursorColor
Sets the color to be used for the text cursor.
Syntax
void SetTextCursorColor(const AZ::Color& color)
SetTextEntity
Sets the text element.
Version 1.10
756
Lumberyard Developer Guide
UITooltipComponent
Syntax
void SetTextEntity(AZ::EntityId textEntity)
SetTextSelectionColor
Sets the color to be used for the text background when it is selected.
Syntax
void SetTextSelectionColor(const AZ::Color& color)
Services notifications for the
UiTextInputComponent
.
OnTextInputChange
Called when a character is added, removed, or changed.
Syntax
void OnTextInputChange(const AZStd::string& textString)
OnTextInputEndEdit
Called when edit of text is completed.
Syntax
void OnTextInputEndEdit(const AZStd::string& textString)
OnTextInputEnter
Called when
Enter
is pressed on the keyboard.
Syntax
void OnTextInputEnter(const AZStd::string& textString)
You can use a tooltip component to provide the text of a tooltip.
Services messages for the
UiTooltipComponent
.
GetText
Returns the tooltip text.
Syntax
Version 1.10
757
Lumberyard Developer Guide
UITooltipDisplayComponent
AZStd::string GetText()
SetText
Sets the tooltip text.
Syntax
void SetText(const AZStd::string& text)
Controls the display behavior of a tooltip.
Services messages for the
UiTooltipDisplayComponent
.
GetAutoPosition
Returns whether the tooltip display element is auto positioned.
Syntax
bool GetAutoPosition()
GetAutoPositionMode
Returns the auto position mode.
Syntax
eUiTooltipDisplayAutoPositionMode GetAutoPositionMode()
Following are possible values for eUiTooltipDisplayAutoPositionMode
.
enum eUiTooltipDisplayAutoPositionMode
{
eUiTooltipDisplayAutoPositionMode_OffsetFromMouse,
eUiTooltipDisplayAutoPositionMode_OffsetFromElement
};
GetAutoSize
Returns whether the tooltip display element should be resized so that the text element size matches the size of the string.
Syntax
bool GetAutoSize()
GetDelayTime
Returns the amount of time to wait before showing the tooltip display element after hover start.
Version 1.10
758
Lumberyard Developer Guide
UITooltipDisplayComponent
Syntax
float GetDelayTime()
GetDisplayTime
Returns the amount of time the tooltip display element is to remain visible.
Syntax
float GetDisplayTime()
GetOffset
Returns the offset from the tooltip display element's pivot to the mouse position.
Syntax
const AZ::Vector2& GetOffset()
GetTextEntity
Returns the entity ID of the text element that is used for resizing.
Syntax
AZ::EntityId GetTextEntity()
SetAutoPosition
Sets whether the tooltip display element is auto positioned.
Syntax
void SetAutoPosition(bool autoPosition)
SetAutoPositionMode
Sets the auto position mode.
Syntax
void SetAutoPositionMode(eUiTooltipDisplayAutoPositionMode autoPositionMode)
For possible values for eUiTooltipDisplayAutoPositionMode
, see
.
SetAutoSize
Sets whether the tooltip display element should be resized so that the text element size matches the size of the string.
Syntax
void SetAutoSize(bool autoSize)
Version 1.10
759
Lumberyard Developer Guide
UITransform2dComponent
SetDelayTime
Sets the amount of time to wait before showing the tooltip display element after hover start.
Syntax
void SetDelayTime(float delayTime)
SetDisplayTime
Sets the amount of time the tooltip display element is to remain visible.
Syntax
void SetDisplayTime(float displayTime)
SetOffset
Sets the offset from the tooltip display element's pivot to the mouse position.
Syntax
void SetOffset(const AZ::Vector2& offset)
SetTextEntity
Sets the entity ID of the text element that is used for resizing. The text element must be a child of this entity.
Syntax
void SetTextEntity(AZ::EntityId textEntity)
Controls positioning, scaling, rotation, anchor, and offset settings for UI elements.
Services messages for the
UiTransform2dComponent
.
GetCanvasPosition
Returns the position for this element in canvas space.
Syntax
AZ::Vector2 GetCanvasPosition()
GetLocalPosition
Returns the position for this element relative to the center of the element's anchors.
Syntax
Version 1.10
760
Lumberyard Developer Guide
UITransform2dComponent
AZ::Vector2 GetLocalPosition()
GetPivot
Returns the pivot point.
Syntax
AZ::Vector2 GetPivot()
GetScale
Returns the scale.
Syntax
AZ::Vector2 GetScale()
GetScaleToDevice
Returns whether this element and all its children are scaled to allow for the difference between the authored canvas size and the actual viewport size.
Syntax
bool GetScaleToDevice()
GetViewportPosition
Returns the position for this element in viewport space.
Syntax
AZ::Vector2 GetViewportPosition()
GetZRotation
Returns the rotation about the z-axis.
Syntax
float GetZRotation()
MoveCanvasPositionBy
Moves this element in canvas space.
Syntax
void MoveCanvasPositionBy(const AZ::Vector2& offset)
MoveLocalPositionBy
Moves this element relative to the center of the element's anchors.
Version 1.10
761
Lumberyard Developer Guide
UITransform2dComponent
Syntax
void MoveLocalPositionBy(const AZ::Vector2& offset)
MoveViewportPositionBy
Moves this element in viewport space.
Syntax
void MoveViewportPositionBy(const AZ::Vector2& offset)
SetCanvasPosition
Sets the position for this element in canvas space.
Syntax
void SetCanvasPosition(const AZ::Vector2& position)
SetLocalPosition
Sets the position for this element relative to the center of the element's anchors.
Syntax
void SetLocalPosition(const AZ::Vector2& position)
SetPivot
Sets the pivot point.
Syntax
void SetPivot(AZ::Vector2 pivot)
SetScale
Sets the scale.
Syntax
void SetScale(AZ::Vector2 scale)
SetScaleToDevice
Sets whether the element and all its children are scaled to allow for the difference between the authored canvas size and the actual viewport size.
Syntax
void SetScaleToDevice(bool scaleToDevice)
Version 1.10
762
Lumberyard Developer Guide
UITransform2dComponent
SetViewportPosition
Sets the position for this element in viewport space.
Syntax
void SetViewportPosition(const AZ::Vector2& position)
SetZRotation
Sets the rotation about the z-axis.
Syntax
void SetZRotation(float rotation)
Services anchors and offsets for the
UITransform2dComponent
.
GetAnchors
Returns the UI anchors.
Syntax
UiAnchors GetAnchors()
Following are possible values for
UiAnchors
.
class UiAnchors
{
float left;
float top;
float right;
float bottom;
};
GetOffsets
Returns the UI offsets.
Syntax
UiOffsets GetOffsets()
Following are possible values for
UiOffsets
.
class UiOffsets
{
float left;
float top;
float right;
float bottom;
};
Version 1.10
763
Lumberyard Developer Guide
UI World Components
SetAnchors
Sets the anchors.
Syntax
void SetAnchors(UiAnchors anchors, bool adjustOffsets, bool allowPush)
For possible values for
UiAnchors
Parameter
adjustOffsets allowPush
Description
If true, the offsets are adjusted to keep the rectangle in the same position.
Only takes effect if the anchors are invalid. If true, when an anchor is changed to overlap the anchor opposite it, the opposite anchor moves.
SetOffsets
Sets UI offsets.
Syntax
void SetOffsets(UiOffsets offsets)
For possible values for
UiOffsets
.
SetPivotAndAdjustOffsets
Sets the pivot and adjusts the offsets so that this element stays in the same place.
Syntax
void SetPivotAndAdjustOffsets(AZ::Vector2 pivot)
Controls the loading and unloading of UI canvases.
Services messages for the
UiCanvasAssetRefComponent
.
LoadCanvas
Loads the UI canvas using the stored asset reference. Returns the entity ID of the loaded canvas.
Syntax
AZ::EntityId LoadCanvas()
UnloadCanvas
Unloads the UI canvas using the stored asset reference.
Version 1.10
764
Lumberyard Developer Guide
UI World Components
Syntax
void UnloadCanvas()
Handles events sent by the
UiCanvasAssetRefComponent
.
OnCanvasLoadedIntoEntity
Called when the canvas asset reference loads a UI canvas.
Syntax
void OnCanvasLoadedIntoEntity(AZ::EntityId uiCanvasEntity)
Services messages for the
UiCanvasProxyRefComponent
.
SetCanvasRefEntity
Sets the entity that manages the UI canvas for this proxy.
Syntax
void SetCanvasRefEntity(AZ::EntityId canvasAssetRefEntity)
Services messages for the
UiCanvasAssetRefComponent
and
UiCanvasProxyRefComponent
.
GetCanvas
Returns the UI canvas associated with this entity
Syntax
AZ::EntityId GetCanvas()
Provides notifications of when the UI canvas reference changes.
OnCanvasRefChanged
Called when the canvas referenced by a
UiCanvasAssetRefComponent
has changed. This can happen when
LoadCanvas (p. 764) , UnloadCanvas (p. 764) , or
is called.
Syntax
void OnCanvasRefChanged(AZ::EntityId uiCanvasRefEntity, AZ::EntityId uiCanvasEntity
Version 1.10
765
Lumberyard Developer Guide
Working with Lua Scripting
CryLua is deprecated and will be removed in a future version of Lumberyard.
The topics in this section document Lua functionality for the legacy script context
. Starting with
Lumberyard 1.8, Lua scripts use the new behavior context (p. 480) that replaces the legacy script
context. Scripts that were written before the integration of the behavior context no longer work in
Lumberyard versions 1.8 and later. For information on updating Lua code from legacy script context to the new behavior context, see the migration notes for Lumberyard 1.8
. For information on using Lua
with Lumberyard's new component entity system, see Writing Lua Scripts for the Component Entity
.
Topics
•
Working with Lua Scripting (p. 766)
•
Loading Canvases in Lua (p. 772)
•
Entity System Script Callbacks (p. 773)
•
Game Rules Script Callbacks (p. 775)
•
Common Lua Globals and Functions (p. 777)
•
EntityUtils Lua Functions (p. 782)
•
Lua Vector and Math Functions (p. 785)
•
Physics Lua Functions (p. 795)
•
Lua ScriptBind Reference (p. 796)
•
Integrating Lua and C++ (p. 1002)
CryLua is deprecated and will be removed in a future version of Lumberyard.
Version 1.10
766
Lumberyard Developer Guide
Running Scripts
Lumberyard uses Lua for its scripting language.
The Entity system can attach a script proxy to any entity, which is in the form of a table that can include data and functions. AI behaviors are often written in scripts. Additionally, several game systems, including Actor, Item, Vehicle, and GameRules, rely on scripting to extend their functionality.
The advantages of using scripts include:
• Fast iteration – Scripts can be reloaded within the engine.
• Runtime performance – Careful usage of available resources can result into scripts that run nearly as fast as compiled code.
• Easy troubleshooting – An embedded Lua debugger can be invoked at any time.
Most of the systems in Lumberyard expose ScriptBind functions, which allow Lua scripts to call existing
code written in C++. See the Lua ScriptBind Reference (p. 796)
for more details.
You can run scripts either by calling script files directly from code or by using console commands.
In code
Scripts are stored in the
\Game\Scripts
directory. To invoke a script file, call the
LoadScript
function
from your C++ code. For more information, see Integrating Lua and C++ (p. 1002)
. Another option is to create a script entity, as described in
.
In the Console
Script instructions can be executed using the in-game console. This can be done by appending the
#
character before the instructions. This functionality is limited to Lumberyard Editor or when running the launcher in dev mode (using the
-DEVMODE
command-line argument).
In Lumberyard Editor it is always possible to reload entities within the user interface. When reloading a script entity, choose the
Reload Script
button, which is found in the Rollup Bar.
You can also use the following ScriptBind functions to reload scripts.
•
Script.ReloadScript(filename)
•
Script.ReloadScripts()
To invoke these functions from the console, use the following syntax:
#Script.ReloadScript("Scripts\\EntityCommon.lua")
The following resources on the Lua language are recommended reading when working with scripts with
Lumberyard.
• Lua 5.1 Reference Manual
• Programming in Lua, Third Edition
Version 1.10
767
Lumberyard Developer Guide
Using the Lua Remote Debugger
• Other books
Topics
•
Using the Lua Remote Debugger (p. 768)
•
Using the Lua XML Loader (p. 769)
Lumberyard includes a standalone visual script debugger for Lua. To start the debugger, you first enable it in the console, and then run the
LuaRemoteDebugger.exe
executable file.
1. In the Lumberyard Editor console or game console, type
lua_debugger 1
or
lua_debugger 2
. This enables enable debugging in one of the following two modes:
• Mode 1 – The debugger breaks on both breakpoints and script errors.
• Mode 2 – The debugger breaks only on script errors.
2. Run the Lua remote debugger executable file at the Lumberyard directory location
\dev\Tools
\LuaRemoteDebugger\LuaRemoteDebugger.exe
.
3. In the Lua remote debugger, on the
File
menu, choose
Connect
.
4. If you are running the game in the editor (you pressed
Ctrl+G
) and want to debug your scripts, choose
PC (Editor)
. If you want to attach the debugger to the built game executable, choose
PC
(Game)
.
For
IP address
and
Port
, type the IP address and port of the computer to which you want to connect. The default options connect to the game on your local computer. The default IP address is 127.0.01 (localhost). For
PC (Editor)
, the default port is 9433. For
PC (Game)
, the default port is
9432.
5. Choose
Connect
. In Lumberyard Editor, the console window displays
Lua remote debug client connected
.
The first time you run Lua remote debugger, it prompts you for the scripts folder:
The default folder is the
Scripts
folder of the project that you are running. For example, if you are running the samples project, the folder is samplesproject/Scripts
.
6. To accept the default location, click
Yes
.
Note
To change the scripts folder location, choose
File
,
Set Scripts Folder
.
After you choose the location for your scripts folder, the folder's contents are shown in the navigation tree on the left.
To perform specific tasks in the Lua remote debugger, see the following table:
Version 1.10
768
Lumberyard Developer Guide
Using the Lua XML Loader
To do this
Open a script file
Set a break point
Remove a break point
Use the Breakpoints tab
To watch (inspect) variable values
Pause execution
Resume execution
Step over a procedure
Do this
Double click the script file in the navigation pane, or press
Ctrl+O
to open the
Find File
dialog.
Place the cursor on the line in the script where you want the break to occur, and then click the red dot in the toolbar or press
F9
. When program execution stops on a break point, the
Call Stack
and
Locals
tabs populate.
Place the cursor on the line with the breakpoint that you want to remove, and then click the red dot in the toolbar or press
F9
.
The
Breakpoints
tab window displays each of your breakpoints with a check box next to it. To enable or disable a breakpoint, select or clear its check box. In the script window, the breakpoint's status is indicated by its color: red is active; gray is disabled.
When execution is paused on a breakpoint, click the
Watch
tab, click the first column of a blank row, and then type the name of the variable that you want to watch.
Click the pause (break) button on the toolbar or press
Ctrl+Alt+Pause
.
Click the play button on the toolbar or press
F5
.
Click the toolbar icon or press
F10
.
Step into a procedure
Click the toolbar icon or press
F11
.
Step out of a procedure
Close a script file
Disconnect from the editor or game
Click the toolbar icon or press
Shift+F11
.
Choose
File
,
Close
, or press
Ctrl+W
In the Lua debugger, choose
File
,
Disconnect
. The Lumberyard console displays a
network connection terminated
message.
Note
Code changes that you make in the debugger window do not change the loaded script and are discarded after the debugger window is closed.
CryLua is deprecated and will be removed in a future version of Lumberyard.
There is a generic interface for parsing and translating XML files into Lua files. This interface uses an
XML file as a definition format that declares what kind of XML is included in a file and what kind of Lua to create from the XML. The format includes some simple validation methods to ensure that the data received is what is expected.
Version 1.10
769
Lumberyard Developer Guide
Using the Lua XML Loader
The XML loader can distinguish between three kinds of data: properties, arrays, and tables.
Tables
This table represents a Lua-based table: letters = { a="a", b="b", c="c" }
In an XML data file, this table would look like this:
<letters a="a" b="b" c="c"/>
The XML definition file would look like this:
<Table name="letters">
<Property name="a" type="string"/>
<Property name="b" type="string"/>
<Property name="c" type="string"/>
</Table>
Each element can be marked as optional in the definition file using the attribute optional="1"
.
Arrays
There are two possible types of arrays. The first type is a simple group of elements, shown in Lua like this: numbers = {0,1,2,3,4,5,6,7,8,9}
In the XML data file, the array would look like this:
<numbers>
<number value="0"/>
<number value="1"/>
<number value="2"/>
<number value="3"/>
<number value="4"/>
<number value="5"/>
<number value="6"/>
<number value="7"/>
<number value="8"/>
<number value="9"/>
</numbers>
The data definition file would look like this:
<Array name="numbers" type="int" elementName="number"/>
The second array type is an array of tables. In Lua: wheels = {
{size=3, weight=10},
{size=2, weight=1},
{size=4, weight=20},
Version 1.10
770
Lumberyard Developer Guide
Using the Lua XML Loader
}
In the XML data file:
<wheels>
<wheel size="3" weight="10"/>
<wheel size="2" weight="1"/>
<wheel size="4" weight="20"/>
</wheels>
The XML definition file:
<Array name="wheels" elementName="wheel"> <!-- note no type is attached -->
<Property name="size" type="float"/>
<Property name="weight" type="int"/>
</Array>
To load and initialize a Lua table: someTable = CryAction.LoadXML( definitionFileName, dataFileName )
When storing XML files for scripts, the recommended practice is to keep the definition files with the scripts that use them, but store the data files in a directory outside the Scripts directory.
To save a table from Lua:
CryAction.SaveXML( definitionFileName, dataFileName, table )
The following data types are available, and can be set wherever a "type" attribute is present in the definition file.
• float – Floating point number.
• int – Integer.
• string – String.
• bool – Boolean value.
• Vec3 – Floating point vectors with three components. Values of this type are expressed as follows:
• XML –
"1,2,3"
• Lua –
{x=1,y=2,z=3}
For string type properties, an optional
<Enum>
definition can be used. Property values will be validated against the enum.
Example:
<Property name="view" type="string">
<Enum>
<Value>GhostView</Value>
Version 1.10
771
Lumberyard Developer Guide
Loading Canvases in Lua
<Value>ThirdPerson</Value>
<Value>BlackScreen</Value>
</Enum>
</Property>
Enum support for other data types can be added, if necessary.
XML definition file:
<Definition root="Data">
<Property name="version" type="string"/>
<Table name="test">
<Property name="a" type="string"/>
<Property name="b" type="int" optional="1"/>
<Array name="c" type="string" elementName="Val"/>
<Array name="d" elementName="Value">
<Property name="da" type="float"/>
<Property name="db" type="Vec3"/>
</Array>
<Property name="e" type="int"/>
</Table>
</Definition>
Corresponding XML data file:
<Data version="Blag 1.0">
<test
a="blag"
e="3">
<c>
<Val value="blag"/>
<Val value="foo"/>
</c>
<d>
<Value da="3.0" db="2.1,2.2,2.3"/>
<Value da="3.1" db="2.1,2.2,2.3"/>
<Value da="3.2" db="3.1,3.2,2.3"/>
</d>
</test>
</Data>
CryLua is deprecated and will be removed in a future version of Lumberyard.
The Lumberyard UI Editor uses the concept of a UI canvas as an invisible backdrop for user interface elements. You can use the Lua scripting language to load and unload UI canvases in Lumberyard.
To load a canvas in Lua
1. Create a new, plain text file in your game project directory with a
.lua
file extension.
Version 1.10
772
Lumberyard Developer Guide
Entity System Script Callbacks
2. Type or paste the following sample script into your new
Lua
file:
Note
The following script uses a Lua file named loadcanvas.lua
and loads a canvas file named menu.uicanvas
saved at the root of the game project directory. Substitute the appropriate file names for your script.
loadcanvas =
{
Properties =
{
},
} function
loadcanvas
:OnActivate()
self.uiCanvasLuaProxy = UiCanvasLuaProxy()
self.uiCanvasLuaProxy:LoadCanvas("
menu.uicanvas
") end
3. In Lumberyard Editor, right-click in the
Viewport
and click
Create Component Entity
.
4. If the
Entity Inspector
does not open automatically, click
Tools
,
Entity Inspector
.
5. Click
Add Component
.
6. Select
Scripting
,
Lua Script
.
7. Under
Lua Script
, click
...
and open the Lua script file that you created.
8. In Lumberyard Editor, click
Game
,
Switch to Game
to enter game mode. Verify that your canvas file loads.
See Also
For more information, consult the following resources.
• For a full listing of UI Lua API calls, see UI Lua Reference (p. 700)
.
• For general information about UI canvases, see Working with UI Canvases in the Amazon Lumberyard
User Guide .
CryLua is deprecated and will be removed in a future version of Lumberyard.
This topic describes all callbacks for the Entity system. Use of these callbacks functions is not obligatory, but some cases require that entities behave properly within the Lumberyard Editor. For example, the
OnReset
callback should be used to clean the state when a user enters or leaves the game mode within the Lumberyard Editor.
Callback Function
OnSpawn
OnDestroy
Description
Called after an entity is created by the Entity system.
Called when an entity is destroyed (like
OnShutDown()
gets called).
Version 1.10
773
Lumberyard Developer Guide
Script State Functions
Callback Function
OnInit
OnShutDown
OnReset
OnPropertyChange
Description
Called when an entity gets initialized via ENTITY_EVENT_INIT, and when its
ScriptProxy gets initialized.
Called when an entity is destroyed (like
OnDestroy()
gets called).
Usually called when an editor wants to reset the state.
Called by Lumberyard Editor when the user changes one of the properties.
Callback Function
OnBeginState
OnBind
OnCollision
OnEndState
OnEnterArea
OnEnterNearArea
OnLeaveArea
OnLeaveNearArea
OnMove
OnMoveNearArea
OnProceedFadeArea
Description
Called during
Entity.GotoState()
after the state has been changed (that is, after
OnEndState()
is called on the old state).
Called when a child entity is attached to an entity. Parameters include:
• script table for the child entity
Called when a collision between an entity and something else occurs.
Parameters include:
• script table with information about the collision
Called during
Entity.GotoState()
while the old state is still active and before
OnBeginState()
is called on the new state.
Called when an entity has fully entered an area or trigger. Parameters include:
•
areaId
(int)
•
fade fraction
(float) This value is 1.0f if the entity has fully entered the area, or 0.0f in the case of trigger boxes.
Called when an entity enters the range of an area. Works with Box-, Sphereand Shape-Areas if a sound volume entity is connected. Takes OuterRadius of sound entity into account to determine when an entity is near the area.
Called when an entity has fully left an area or trigger. Parameters include:
•
areaId
(int)
•
fade fraction
(float) This value is always 0.0f.
Called when an entity leaves the range of an area. Works with Box-, Sphereand Shape-Areas if a sound volume entity is connected. Takes OuterRadius of sound entity into account to determine when an entity is near the area.
Called whenever an entity moves through the world.
Called when an entity moves. Works with Box-, Sphere- and Shape-Areas if a sound volume entity is connected. Takes OuterRadius of sound entity into account to determine when an entity is near the area.
Called when an entity has recently entered an area and fading is still in progress. Parameters include:
Version 1.10
774
Callback Function
OnSoundDone
OnStartGame
OnStartLevel
OnTimer
OnUnBind
OnUpdate
Lumberyard Developer Guide
Game Rules Script Callbacks
Description
•
areaId
(int)
•
fade fraction
(float)
Called when a sound stops. Parameters include:
•
soundId
(int) The ID of the sound played, which was provided with the request to play the sound.
Called when a game is started.
Called when a new level is started.
Called when a timer expires. Parameters include:
•
timerId
(int) The ID of the time, provided by
Entity.SetTimer()
.
•
period
(int) Length of time, in milliseconds, that the timer runs
Called when a child entity is about to be detached from an entity.
Parameters include:
• script table for the child entity
Called periodically by the engine on the entity's current state. This assumes the console variable es_UpdateScript
is set to 1.
CryLua is deprecated and will be removed in a future version of Lumberyard.
This topic provides reference information on callbacks used with the GameRules scripts.
Callback Function
OnAddTaggedEntity
Description
Called when a player is added as a tagged player on the minimap. Called on the server only.
•
shooterId
– Entity that tagged the target player.
•
targetId
– Tagged player.
Called when a player connects. Called on the server only.
OnClientConnect
OnClientDisconnect
•
channelId
Called when a player disconnects. Called on the server only.
•
channelId
OnClientEnteredGame
Called when a player enters the game and is part of the game world. Called on the server only.
•
channelId
– Channel identifier of the player.
•
playerScriptTable
– The player's script table.
Version 1.10
775
Lumberyard Developer Guide
Game Rules Script Callbacks
Callback Function Description
•
bReset
– Boolean indicating whether or not the channel is from the reset list.
•
bLoadingSaveGame
– Boolean indicating whether or not the call was made during a saved game loading.
Called when the player disconnects on the client. Called on the client only.
OnDisconnect
•
cause
– Integer identifying the disconnection cause. See
EDisconnectionCause
.
•
description
– Human readable description of the disconnection cause.
OnChangeSpectatorMode
Called when a player changes the spectator mode. Called on the server only.
OnChangeTeam
•
entityId
– Player who made the change.
•
mode
– New spectator mode (1=fixed, 2=free, 3= follow).
•
targetId
– Possible target entity to spectate.
•
resetAll
– Boolean indicating whether or not to reset player-related things like the inventory.
Called when a player switches teams. Called on the server only.
•
entityId
– Player who switched teams.
•
teamId
– New team identifier.
Version 1.10
776
Callback Function
OnExplosion
Lumberyard Developer Guide
Common Lua Globals and Functions
Description
Called when an explosion is simulated. Called on the server and client.
•
pos
– Position of the explosion in the game world.
•
dir
– Direction of the explosion.
•
shooterId
•
weaponId
•
shooter
•
weapon
•
materialId
•
damage
•
min_radius
•
radius
•
pressure
•
hole_size
•
effect
•
effectScale
•
effectClass
•
typeId
•
type
•
angle
•
impact
•
impact_velocity
•
impact_normal
•
impact_targetId
•
shakeMinR
•
shakeMaxR
•
shakeScale
•
shakeRnd
•
impact
•
impact_velocity
•
impact_normal
•
impact_targetId
•
AffectedEntities
– Affected entities table.
•
AffectedEntitiesObstruction
– Affected entities obstruction table.
CryLua is deprecated and will be removed in a future version of Lumberyard.
• File location:
Game/Scripts/common.lua
• Loaded from:
Game/Scripts/main.lua
Version 1.10
777
Lumberyard Developer Guide
Globals
Use the following globals to avoid temporary Lua memory allocations:
Name
g_SignalData_point g_SignalData_point2 g_SignalData g_StringTemp1 g_HitTable
Description
Basic 3D vector value used by
g_SignalData.
Basic 3D vector value used by
g_SignalData.
Used to pass signal data in AI behavior scripts (see:
Commonly used for temporary strings inside Lua functions.
Commonly used by the
Physics.RayWorldIntersection
function.
A
g_HitTable
used with
Physics.RayWorldIntersection
can contain the following parameters:
Parameter
pos normal dist surface entity renderNode
Description
3D vector world coordinates of the ray hit.
3D normal vector of the ray hit.
Distance of the ray hit.
Type of surface hit.
Script table of entity hit (if one was hit).
Script handle to a foliage or static render node.
A
g_SignalData
table can contain the following parameter types:
Type
Vec3
ScriptHandle
Floating Point
Integer
String
Description
3D vector.
Normally used to pass along an entity ID.
Floating point value.
Integer or number value.
String value.
Reloads the
aiconfig.lua
Lua script (
Game/Scripts/AI/
).
Toggles the ai_DebugDraw console variable on and off.
Version 1.10
778
Lumberyard Developer Guide
ShowTime()
Logs the current system time to the console. Format is Day/Month/Year, Hours:Minutes.
Returns the number of key-value pairs in a given table.
Parameter
_tbl
Description
Table to retrieve the number of key-value pairs from.
Creates a new table by copying an specified existing table. This function is commonly used to create a local table based on an entity parameter table.
Parameter
_obj norecurse
Description
Existing table you want to create a new one from.
Flag indicating whether or not to recursively recreate all sub-tables. If set to
TRUE, sub-tables will not be recreated.
Merges two tables without merging functions from the source table.
Parameter
dst src recurse
Description
Destination table to merge source table information into.
Source table to merge table information from.
Flag indicating whether or not to recursively merge all sub-tables.
Merges two tables including merging functions from the source table.
Parameter
dst src recursive
Description
Destination table to merge source table information into.
Source table to merge table information from.
Flag indicating whether or not to recursively merge all sub-tables.
Version 1.10
779
Lumberyard Developer Guide
Vec2Str()
Converts a 3D vector table into a string and returns it in the following format: (x: X.XXX y: Y.YYY z:
Z.ZZZ).
Parameter
vec
Description
3D vector table to convert. Example:
{x=1,y=1,z=1}
.
Logs an error message to the console and the log file. Message appears in red text in the console.
Parameter
fmt
...
Description
Formatted message string.
Optional argument list. For example:
LogError("MyError: %f", math.pi);
Logs a warning message to the console and the log file. Message appears in yellow text in the console.
Parameter
fmt
...
Description
Formatted message string.
Optional argument list. For example:
LogWarning("MyError: %f", math.pi);
Logs a message to the console and the log file. Commonly used for debugging purposes.
Parameter
fmt
...
Description
Formatted message string.
Optional argument list. For example:
Log("MyLog: %f", math.pi);
Dumps information from a specified table to the console.
Parameter
_class no_func
Description
Table to dump to console. For example: g_localActor
Flag indicating whether or not to dump the table functions.
Version 1.10
780
Lumberyard Developer Guide
EmptyString()
Parameter
depth
Description
Depth of the tables tree dump information from.
Checks whether or not a given string is set and its length is greater than zero. Returns
TRUE
or
FALSE
.
Parameter
str
Description
String to check for.
Checks whether or not a number value is true (non-zero) or false (zero).
Parameter
n
Description
Number to check for.
Retrieves the name of a specified entity ID or entity table. If the entity doesn't exist, this function returns an empty string.
Parameter
entity
Description
Entity table or entity ID to return a name for.
Checks whether or not an entity with the specified name exists in the entity system. Returns
TRUE
or
FALSE
. Commonly used for debugging.
Parameter
name
Description
Name of entity to check for.
Checks whether or not a sub-table with a specified name exists in a table. If the sub-table exists, this function returns it; otherwise the function returns nil
.
Parameter
table
Description
Table to check for the existence of a sub-table.
Version 1.10
781
Lumberyard Developer Guide
EntityUtils Lua Functions
Parameter
name
Description
Sub-table name to check for.
CryLua is deprecated and will be removed in a future version of Lumberyard.
This topic describes the commonly used Lua entity utility functions.
• File location:
Game/Scripts/Utils/EntityUtils.lua
• Loaded from:
Game/Scripts/common.lua
Dumps to console all entity IDs, names, classes, positions, and angles that are currently used in a map.
For example:
[userdata: 00000002]..name=Grunt1 clsid=Grunt pos=1016.755,1042.764,100.000
ang=0.000,0.000,1.500
[userdata: 00000003]..name=Grunt2 clsid=Grunt pos=1020.755,1072.784,100.000
ang=0.000,0.000,0.500
...
Compares two entities identified by name. This function is commonly used when sorting tables.
Parameter
ent1 ent2
Description
Name of first entity table.
Name of second entity table.
local entities = System.GetEntitiesByClass("SomeEntityClass") table.sort(entities, CompareEntitiesByName)
Compares the distance of two entities from a specified point. If the distance is greater for Entity 1 than for Entity 2 (that is, Entity 1 is further away), this function returns
TRUE
, otherwise it returns
FALSE
.
Parameter
ent1
Description
Entity 1 table
Version 1.10
782
Lumberyard Developer Guide
BroadcastEvent()
Parameter
ent2 point
Description
Entity 2 table
3D position vector identifying the point to measure distance to.
local ent1 = System.GetEntityByName("NameEntityOne") local ent2 = System.GetEntityByName("NameEntityTwo") if(CompareEntitiesByDistanceFromPoint( ent1, ent2, g_localActor:GetPos()))then
Log("Entity One is further away from the Player than Entity two...") end
Processes an entity event broadcast.
Parameter
sender event
Description
Entity that sent the event.
String based entity event to process.
BroadcastEvent(self, "Used")
Creates a new table that is a derived version of a parent entity table. This function is commonly used to simplify the creation of a new entity script based on another entity.
Parameter
_DerivedClass
_Parent
Description
Derived class table.
Parent or base class table.
Creates a new table that is a derived class of a parent entity. The derived table's properties will override those from the parent.
Parameter
_DerivedClass
Description
Derived class table.
Version 1.10
783
Lumberyard Developer Guide
MakeUsable()
Parameter
_Parent
Description
Parent or base class table.
Adds usable functionality, such as an
OnUsed
event, to a specified entity.
Parameter
entity
Description
Entity table to make usable.
MyEntity = { ... whatever you usually put here ... }
MakeUsable(MyEntity) function MyEntity:OnSpawn() ...
function MyEntity:OnReset()
self:ResetOnUsed()
...
end
Adds basic "pickable" functionality to a specified entity. The bPickable
property is added to the entity's properties table.
Parameter
entity
Description
Entity table to make pickable.
Adds spawn functionality to a specified entity. Commonly used for
AI
actors during creation.
Parameter
entity
Description
Entity table to make spawnable.
Physicalizes an entity based on the specified entity slot and its physics properties.
Parameter
entity
Description
Entity table to physicalize.
Version 1.10
784
Parameter
nSlot
Properties bActive
Lumberyard Developer Guide
Lua Vector and Math Functions
Description
Entity slot to physicalize.
Physics properties table
Not used.
CryLua is deprecated and will be removed in a future version of Lumberyard.
This topic describes the commonly used math global vectors, constants, and functions.
• File location:
Game/Scripts/Utils/Math.lua
• Loaded from:
Game/Scripts/common.lua
The following globals should be used to avoid temporary Lua memory allocations:
Global Name
g_Vectors.v000
g_Vectors.v001
g_Vectors.v010
g_Vectors.v100
g_Vectors.v101
g_Vectors.v110
g_Vectors.v111
g_Vectors.up
g_Vectors.down
g_Vectors.temp
g_Vectors.tempColor
g_Vectors.temp_v1
Description
Basic zero vector.
Positive z-axis direction vector.
Positive y-axis direction vector.
Positive x-axis direction vector.
The x and z-axis direction vector.
The x and y-axis direction vector.
The x, y and z-axis vector.
Positive z-axis direction vector.
Negative z-axis direction vector.
Temporary zero vector.
Temporary zero vector. Commonly used for passing rgb color values.
Temporary zero vector.
g_Vectors.temp_v2
g_Vectors.temp_v3
g_Vectors.temp_v4
Temporary zero vector.
Temporary zero vector.
Temporary zero vector.
g_Vectors.vecMathTemp1 Temporary zero vector.
Version 1.10
785
Lumberyard Developer Guide
Constants
Global Name Description
g_Vectors.vecMathTemp2 Temporary zero vector.
Constant Name
g_Rad2Deg g_Deg2Rad g_Pi g_2Pi g_Pi2
Description
Basic radian-to-degree conversion value.
Basic degree-to-radian conversion value.
Basic Pi constant based on math.pi
.
Basic double-Pi constant based on math.pi
.
Basic half-Pi constant based on math.pi
.
Checks whether or not all components of a specified vector are null.
Parameter
a
Description
Vector to check.
Checks whether or not any components of a specified vector is not null.
Parameter
a
Description
Vector to check.
Retrieves the squared length of a specified vector.
Parameter
a
Description
Vector to retrieve length for.
Retrieves the length of a specified vector.
Version 1.10
786
Lumberyard Developer Guide
DistanceSqVectors()
Parameter
a
Description
Vector to retrieve length for.
Retrieves the squared distance between two vectors.
Parameter
a b
Description
First vector.
Second vector.
Retrieves the squared distance between two vectors in 2D space (without z-component).
Parameter
a b
Description
First vector.
Second vector.
Retrieves the distance between two vectors.
Parameter
a b
Description
First vector.
Second vector.
Retrieves the dot product between two vectors.
Parameter
a b
Description
First vector.
Second vector.
Retrieves the dot product between two vectors in 2D space (without z-component).
Version 1.10
787
Lumberyard Developer Guide
LogVec()
Parameter
a b
Description
First vector.
Second vector.
Logs a specified vector to console.
Parameter
name v
Description
Descriptive name of the vector.
Vector to log.
LogVec("Local Actor Position", g_localActor:GetPos())
Console output:
<Lua> Local Actor Position = (1104.018066 1983.247925 112.769440)
Sets all components of a specified vector to zero.
Parameter
dest
Description
Vector to zero out.
Copies the components of one vector to another.
Parameter
dest src
Description
Destination vector.
Source vector.
Adds up the components of two vectors.
Version 1.10
788
Lumberyard Developer Guide
NegVector()
Parameter
a b
Description
First vector.
Second vector.
Negates all components of a specified vector.
Parameter
a
Description
Vector to negate.
Copies the componentwise subtraction of two vectors to a destination vector.
a b
Parameter
dest
Description
Destination vector.
First vector.
Second vector.
Copies the componentwise addition of two vectors to a destination vector.
a b
Parameter
dest
Description
Destination vector.
First vector.
Second vector.
Retrieves the difference between two vectors.
Parameter
a b
Description
First vector.
Second vector.
Version 1.10
789
Lumberyard Developer Guide
FastDifferenceVectors()
Copies the componentwise difference between two vectors to a destination vector.
a b
Parameter
dest
Description
Destination vector.
First vector.
Second vector.
Retrieves the product of two vectors.
Parameter
a b
Description
First vector.
Second vector.
Copies the product of two vectors to a destination vector.
a b
Parameter
dest
Description
Destination vector.
First vector.
Second vector.
Scales a specified vector
a
by a factor of
b
.
Parameter
a b
Description
Vector.
Scalar.
Retrieves a new vector based on a copy of vector
a
scaled by a factor
b
.
Version 1.10
790
Lumberyard Developer Guide
ScaleVectorInPlace(dest,a,b)
Parameter
a b
Description
First vector.
Scalar.
Copies vector
a
scaled by the factor of
b
to a destination vector.
Parameter
dest a b
Description
Destination vector.
First vector.
Scalar.
Normalizes a specified vector.
Parameter
a
Description
Vector to normalize.
Rotates a specified vector by 90 degree around the z-axis.
Parameter
v
Description
Vector to rotate.
Rotates a specified vector by -90 degree around the z-axis.
Parameter
v
Description
Vector to rotate.
Copies the result of the cross product between two vectors to a destination vector.
Version 1.10
791
Lumberyard Developer Guide
RotateVectorAroundR()
Parameter
dest p q
Description
Destination vector.
First vector.
Second vector.
Copies to a destination vector the result of the vector rotation of vector
p
around vector
r
by a specified angle.
Parameter
dest r p angle
Description
Destination vector.
First vector.
Second vector.
Rotation angle.
Copies to a destination vector the result of the vector projection of vector
P
to the surface with a specified normal
N
.
P
N
Parameter
dest
Description
Destination vector.
Vector to project.
Surface normal.
Retrieves the distance between point
a
and the line between
p
and
q
.
Parameter
a p q
Description
Point to measure from.
Vector p.
Vector q.
Performs linear interpolation between two color/vectors with a factor of
k
.
Version 1.10
792
Lumberyard Developer Guide
Lerp()
Parameter
a b k
Description
Color/vector a.
Color/vector b.
Factor k.
Performs linear interpolation between two scalars with a factor of
k
.
Parameter
a b k
Description
Scalar a.
Scalar b.
Factor k.
Retrieves the maximum of two scalars.
Parameter
a b
Description
Scalar a.
Scalar b.
Retrieves the minimum of two scalars.
Parameter
a b
Parameter
_n
Description
Scalar a.
Scalar b.
Clamps a specified number between minimum and maximum.
Description
Number to clamp.
Version 1.10
793
Lumberyard Developer Guide
Interpolate()
Parameter
_min
_max
Description
Lower limit.
Upper limit.
Interpolates a number to a specified goal by a specified speed.
Parameter
actual goal speed
Description
Number to interpolate.
Goal.
Interpolation speed.
Retrieves the sign of a specified number (0 returns 0).
Parameter
a
Description
Number to get sign for.
Retrieves the sign of a specified number (0 returns 1).
Parameter
a
Description
Number to get sign for.
Retrieves the square of a specified number.
Parameter
a
Description
Number to square.
Retrieves a random float value between two specified numbers.
Version 1.10
794
Lumberyard Developer Guide iff()
Parameter
a b
Description
First number.
Second number.
Checks the condition of a test value and returns one of two other values depending on whether the test value is nil
or not.
Parameter
c a b
Description
Test value.
Return value if test value is not nil.
Return value if test value is nil.
CryLua is deprecated and will be removed in a future version of Lumberyard.
These functions are commonly used to register new explosion and crack shapes in the physics engine.
File location:
Game/Scripts/physics.lua
• Loaded from:
Game/Scripts/main.lua
Registers a boolean carving shape for breakable objects in the physics engine.
Parameter
sGeometryFile fSize
BreakId fProbability sSplintersfile fSplintersOffset sSplintersCloudEffect
Description
Name of a boolean shape cgf file.
Shape's characteristic size.
Breakability index (0-based) used to identify the breakable material.
Shape's relative probability; when several shapes with the same size appear as candidates for carving, these relative probabilities are used to select one.
Name of a splinters cgf file, used for trees to add splinters at the breakage location.
Size offset for the splinters.
Name of splinters particle fx; this effect is played when a splinters-based constraint breaks and splinters disappear.
Version 1.10
795
Lumberyard Developer Guide
Physics.RegisterExplosionCrack()
Registers a new explosion crack for breakable objects in the physics engine.
Parameter
sGeometryFile
BreakId
Description
Name of a crack shape cgf file. This type of file must have three helpers to mark the corners, named "1","2" and "3".
Breakability index (0-based) used to identify the breakable material.
CryLua is deprecated and will be removed in a future version of Lumberyard.
You can use
ScriptBind
functions in Lua scripts to call legacy code written in C++.
Topics
•
ScriptBind Engine Functions (p. 796)
•
ScriptBind Action Functions (p. 952)
•
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ engine functions that you can call from Lua script.
Topics
•
•
•
•
•
•
•
•
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ AI functions that can be called from Lua scripts.
Version 1.10
796
Lumberyard Developer Guide
ScriptBind Engine Functions
AbortAction
Aborts execution of a specified action.
Syntax
AI.AbortAction(userId [, actionId ])
Parameter
userId actionId (optional)
Description
The ID of the entity.
Unique ID of the action to be aborted. If 0 (or nil), all actions on the specified entity are aborted.
AddAggressiveTarget
Adds a target to a specified entity's list as an aggressive potential target.
Syntax
AI.AddAggressiveTarget(entityId, targetId)
Returns True if successfully added.
Parameter
entityId targetId
Description
The ID of the entity.
Target's entity ID to add.
AddCombatClass
Creates new combat class.
Syntax
AI.AddCombatClass(int combatClass, SmartScriptTable pTable, const char* szCustomSignal)
Parameter
combatClass pTable szCustomSignal
Description
Combat class to add.
Parameters table.
Specifies optional custom
OnSeen
signal.
AddFormationPoint
Adds a follow-type node to a formation descriptor.
Version 1.10
797
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
AI.AddFormationPoint(name, sightangle, distance, offset, [unit_class [,distanceAlt,
offsetAlt]])
Parameter
name sightangle distance offset unit_class
Description
Name of the formation descriptor.
Angle of sight of the node (-180,180; 0 = the entity looks forward).
Distance from the formation's owner.
Offset along the following line (negative = left, positive = right).
Class of soldier (see eSoldierClass
definition in
IAgent.h
).
DistanceAlt
(optional): alternative distance from the formation owner offsetAlt
(optional): alternative offset.
AddFormationPointFixed
Adds a node with a fixed offset to a formation descriptor.
Syntax
AI.AddFormationPointFixed(name, sightangle, x, y, z [,unit_class])
Parameter
name sightangle x, y, z unit_class
Description
Name of the formation descriptor.
Angle of sight of the node (-180,180; 0 = the entity looks forward).
Offset from formation owner.
Class of soldier (see eSoldierClass
definition in
IAgent.h
).
AddPatternBranch
Creates a branch pattern at the specified node. When the entity has approached the specified node
(nodeName) and it is time to choose a new point, the rules defined by this function are used to select the new point. This function can associate multiple target points and an evaluation rule.
Syntax
AI.AddPatternBranch(nodeName, method, branchNode1, branchNode2, ..., branchNodeN)
Parameter
nodeName method
Description
Name of the node to add branches to.
Method used to choose the next node. Valid values include:
Version 1.10
798
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter Description
•
AITRACKPAT_CHOOSE_ALWAYS
– Choose the next point from the list in linear sequence.
•
AITRACKPAT_CHOOSE_LESS_DEFORMED
– Choose the least deformed point in the list. Each node is associated with a deformation value (percentage), which describes how much it must move in order to stay within the physical world. These deformation values are summed down to the parent nodes so that deformation at the end of the hierarchy will be caught down the hierarchy.
•
AITRACKPAT_CHOOSE_RANDOM
– Choose a point in the list randomly.
AddPatternNode
Adds a point to the track pattern.
When validating the points, the test is performed from the start position to the end position. Start position is either the pattern origin or, if the parent is provided, the parent position. The end position is either the relative offset from the start position or from the pattern origin; this position is chosen based on the node flag. The offset is clamped to the physical world based on the test method. The points will be evaluated in the same order they are added to the descriptor, and the system does not try to correct the evaluation order. If hierarchies are used (parent name is defined), it is up to the pattern creator to make sure the nodes are created in such an order that the parent is added before it is referenced.
Syntax
AI.AddPatternNode(nodeName, offsetx, offsety, offsetz, flags, [parent], [signalValue])
Parameter
nodeName offsetx, offsety, offsetz flags parent (optional)
Description
Name of the new point. , Point names are local to the current pattern.
Offset from the start position or from the pattern center. See
AITRACKPAT_NODE_ABSOLUTE.
Track pattern functionality flags.
Node evaluation flags:
•
AITRACKPAT_NODE_START
– Node can be used as the first node in the pattern. There can be multiple start nodes. In that case the closest one is chosen.
•
AITRACKPAT_NODE_ABSOLUTE
– Interpret offset as an offset from the pattern center (otherwise the offset is from the start position).
•
AITRACKPAT_NODE_SIGNAL
– A signal "OnReachedTrackPatternNode" will be sent when the node is reached.
•
AITRACKPAT_NODE_STOP
– Advancing will be stopped. It can be continued by calling entity:ChangeAIParameter(AIPARAM_TRACKPATTERN_ADVANCE,
1)
.
•
AITRACKPAT_NODE_DIRBRANCH
– For the direction at each pattern node, use the average direction to the branch nodes (otherwise use the direction from the node position to the center of the pattern).
Parent node position, which will be used as the start position instead of the pattern center.
Version 1.10
799
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
signalValue
(optional)
Description
If the signal flag is set, this value is passed as a signal parameter, accessible from the signal handler in data.iValue
.
AddPersonallyHostile
Syntax
AI.AddPersonallyHostile(ScriptHandle entityID, ScriptHandle hostileID)
AgentLookAtPos
Causes the specified entity to look at a certain position.
Syntax
AI.AgentLookAtPos(entityId, Vec3 pos)
Parameter
entityId pos
Description
The ID of the entity.
Vec3 to look at.
AllowLowerBodyToTurn
Syntax
AI.AllowLowerBodyToTurn(entityID, bAllowLowerBodyToTurn)
Parameter Description
entityId
Entity ID of the agent you want to set the look style to.
bAllowLowerBodyToTurn.
True if you want to allow the turning movement of the body, false otherwise.
BeginTrackPattern
Begins the definition of a new track pattern descriptor. The pattern is created by calling
AI.AddPatternPoint()
and
AI.AddPatternBranch()
, and finalized by calling
AI.EndTrackPattern()
.
Syntax
AI.BeginTrackPattern(patternName, flags, validationRadius, [stateTresholdMin],
Parameter
patternName
Description
Name of the new track pattern descriptor.
Version 1.10
800
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
flags
Description
Track pattern functionality flags.
Validation flags describe how the pattern is validated to fit the physical world:
•
AITRACKPAT_VALIDATE_NONE
– No validation.
AITRACKPAT_VALIDATE_SWEPTSPHERE
– Validate using swept sphere tests, where the spehre radius equals the validation radius plus the entity pass radius.
•
AITRACKPAT_VALIDATE_RAYCAST
– Validate using raycasting, where the hit position is pulled back by the amount of validation radius plus the entity pass radius.
validationRadius stateTresholdMin
(optional) stateTresholdMax
(optional) globalDeformTreshold
(optional) localDeformTreshold
(optional) exposureMod
(optional) randomRotAng
(optional)
Alignment flags describe how, when the pattern is selected to be used, the alignment of the pattern can be changed. Flags are evaluated in the following order:
•
AITRACKPAT_ALIGN_TO_TARGET
– Align the pattern so that the y-axis points towards the target each time it is set. If the agent does not have a valid attention target at the time, the pattern is aligned to the world.
•
AITRACKPAT_ALIGN_RANDOM
– Align the pattern randonly each time it is set.
The rotation ranges are set using
SetRandomRotation()
.
Validation radius is added to the entity pass radius when validating the pattern along the offsets.
If the state of the pattern is 'enclosed' (high deformation) and the global deformation < stateTresholdMin, the state becomes exposed. Default 0.35.
If the state of the pattern is 'exposed' (low deformation) and the global deformation > stateTresholdMax, the state becomes enclosed. Default 0.4.
Deformation of the whole pattern is tracked in range [0..1]. This treshold value can be used to clamp the bottom range, so that values in range
[trhd..1] becomes [0..1], default 0.0.
Deformation of the each node is tracked in range [0..1]. This treshold value can be used to clamp the bottom range, so that values in range [trhd..1] becomes [0..1], default 0.0.
Importance of the node exposure (how much it is seen by the tracked target) to consider when branching. Valid range is [-1..1], where -1 means to favor unseen nodes and 1 means to favor seen, exposed nodes. Default is 0 (no effect).
Flag indicating whether or not to randomly rotate the pattern each time it is set. Rotation is performed in XYZ order. This parameter defines angles (in degrees) around each axis.
CanFireInStance
Syntax
AI.CanFireInStance(entityId, stance)
Version 1.10
801
Lumberyard Developer Guide
ScriptBind Engine Functions
Returns true if AI can fire at his target in the specified stance at his current position
Parameter
entityId stance.
Description
The ID of the entity.
Stance Id (STANCE_*).
CanMelee
Determines whether or not the AI is able to do melee attack.
Syntax
AI.CanMelee(entityId)
Returns True or false (1 or 0).
Parameter
entityId
Description
The ID of the entity.
CanMoveStraightToPoint
Determines whether or not a specified entity can move in a straight line from its current position to a specified point.
Syntax
AI.CanMoveStraightToPoint(entityId, position)
Parameter
entityId position
Description
The ID of the entity.
Position to check path to.
ChangeFormation
Changes the formation descriptor for the current formation of a specified entity's group (if one exists).
Syntax
AI.ChangeFormation(entityId, name [,scale])
Returns True if the formation change was successful.
Parameter
entityId
Description
Unique entity ID used to identify the group.
Version 1.10
802
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
name scale (optional)
Description
Name of the formation descriptor.
Scale factor for the formation (1 = default).
ChangeMovementAbility
Changes the value of an AI movement ability parameter for the entity specified.
Syntax
AI.ChangeMovementAbility(entityId, paramEnum, paramValue)
Parameter
entityId paramEnum
Description
The ID of the entity.
Index of the parameter to change. Valid values include:
•
AIMOVEABILITY_OPTIMALFLIGHTHEIGHT
– Optimal flight height in meters while finding path.
•
AIMOVEABILITY_MINFLIGHTHEIGHT
– Minimum flight height in meters while finding path.
•
AIMOVEABILITY_MAXFLIGHTHEIGHT
– Maximum flight height in meters while finding path.
New value for the specified parameter.
paramValue
ChangeParameter
Updates a parameter value for a specified entity.
Syntax
AI.ChangeParameter(entityId, paramEnum, paramValue)
Parameter
entityId paramEnum paramValue
Description
The ID of the entity.
The enum of the parameter.
The new value for the specified parameter.
CheckForFriendlyAgentsAroundPoint
Syntax
AI.CheckForFriendlyAgentsAroundPoint(ScriptHandle entityID, Vec3 point, float radius)
Version 1.10
803
Lumberyard Developer Guide
ScriptBind Engine Functions
CheckMeleeDamage
Determines whether or not the AI performing melee is actually hitting target.
Syntax
AI.CheckMeleeDamage(entityId, targetId, radius, minheight, maxheight, angle)
Returns (distance,angle) pair between entity and target (degrees) if melee is possible, nil otherwise
Parameter
entityId targetId radius.
minheight.
maxheight.
angle.
Description
The ID of the entity.
Target's entity ID.
max distance in 2d to target.
min distance in height.
max distance in height.
FOV to include target.
ClearAnimationTag
Syntax
AI.ClearAnimationTag(ScriptHandle entityID, const char* tagName)
Parameter
entityId tagName.
.
Description
AI's entity.
ClearMovementContext
Resets the specified entity's movement context.
Syntax
AI.ClearMovementContext(entityId)
Parameter
entityId context.
Description
The ID of the entity.
context value.
ClearPotentialTargets
Clears all the potential targets from a specified entity's perception handler.
Version 1.10
804
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
AI.ClearPotentialTargets(entityId)
Parameter
entityId
Description
The ID of the entity.
ClearTempTarget
Removes the specified entity's temporary potential target so that it is no longer considered for target selection.
Syntax
AI.ClearTempTarget(entityId)
Returns True if successfully updated.
Parameter
entityId
Parameter
position shapeName checkHeight
(optional)
Description
The ID of the entity.
ConstrainPointInsideGenericShape
Syntax
AI.ConstrainPointInsideGenericShape(position, shapeName[, checkHeight])
Returns Nearest point inside the specified shape.
Description
Position to check.
Name of the shape to test (returned by
AI.GetEnclosingGenericShapeOfType
).
Flag indicating whether or not to test for shape height. (default=false). If set to true, the test will check the space between shape.aabb.min.z and shape.aabb.min.z+shape.height.
CreateFormation
Creates a formation descriptor and adds a fixed node at 0,0,0 (owner's node).
Syntax
AI.CreateFormation(name)
Version 1.10
805
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
name
Description
Name of the new formation descriptor.
CreateGroupFormation
Creates a group formation with leader (or updates leader).
Syntax
AI.CreateGroupFormation(entityId, leaderId)
Parameter
entityId leaderId.
Description
AI's entity.
New leader.
CreateStimulusEvent
Creates a target track stimulus event for the specified entity.
Syntax
AI.CreateStimulusEvent(ScriptHandle ownerId, ScriptHandle targetId, const char*
stimulusName, SmartScriptTable pData)
Parameter
ownerId targetId stimulusName pData
Description
Unique ID of the entity that owns and receives the event.
Unique ID of the entity that sends the event and becomes the target.
Name of the stimulus event.
Event data (see
TargetTrackHelpers::SStimulusEvent
).
CreateTempGenericShapeBox
Creates a temporary box-shaped generic shape. This temporary shape will be destroyed upon an AI system reset.
Syntax
AI.CreateTempGenericShapeBox(Vec3 center, float radius, float height, int type)
Returns Shape name.
Parameter
center.
Description
Center point of the box.
Version 1.10
806
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
radius.
height type
Description
Size of the box in x and y directions.
Height of the box.
Box shape type (AIAnchor).
DebugReportHitDamage
Creates a debug report for the hit damage.
Syntax
AI.DebugReportHitDamage(pVictimEntity, pShooterEntity)
Parameter
pVictimEntity.
pShooterEntity.
Description
Victim ID.
Shooter ID.
DestroyAllTPSQueries
Destroys all the tactical point system queries.
Syntax
AI2.DestroyAllTPSQueries()
DistanceToGenericShape
Syntax
AI.DistanceToGenericShape(Vec3 position, const char* shapeName[, int checkHeight])
Returns True if the point is inside the specified shape.
Parameter
position shapeName checkHeight
(optional)
Description
Position to check.
Name of the shape to test (returned by
AI.GetEnclosingGenericShapeOfType
).
Flag indicating whether or not to test for shape height. (default=false). If set to true, the test will check the space between shape.aabb.min.z and shape.aabb.min.z+shape.height.
DropTarget
Clears the target from a specified entity's perception handler.
Version 1.10
807
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
AI.DropTarget(entityId, targetId)
Parameter
entityId targetId
Description
The ID of the entity.
Target's entity ID.
EnableCoverFire
Enables or disables fire when the
FIREMODE_COVER
is selected.
Syntax
AI.EnableCoverFire(entityId, enable)
Parameter
entityId enable
Description
The ID of the entity.
Boolean.
EnableFire
Enables or disables fire.
Syntax
AI.EnableFire(entityId, enable)
Parameter
entityId enable
Description
The ID of the entity.
Boolean.
EnableUpdateLookTarget
Syntax
AI.EnableUpdateLookTarget(ScriptHandle entityID, bool bEnable)
EnableWeaponAccessory
Enables or disables certain weapon accessory usage.
Syntax
Version 1.10
808
Lumberyard Developer Guide
ScriptBind Engine Functions
AI.EnableWeaponAccessory(entityId, int accessory, bool state)
Parameter
entityId accessory
Description
The ID of the entity.
Enum of the accessory to enable. Possible values (see enum EAIWeaponAccessories
in the
IAgent.h
file):
AIWEPA_NONE = 0,
AIWEPA_LASER = 0x0001
AIWEPA_COMBAT_LIGHT = 0x0002
AIWEPA_PATROL_LIGHT = 0x0004
Set to true or false to enable or disable.
state
EndTrackPattern
Finalizes the track pattern definition. This function should always called to finalize the pattern. Failing to do so will cause erratic behavior.
Syntax
AI.EndTrackPattern()
Error
The fallback error message used when the system experiences an unhandled exception. The code following should continue if it is running in the editor so that the original cause of the problem can be fixed, but halt execution when it is running in the game.
Syntax
AI.Error(szMessage)
Parameter
szMessage
Description
The message to write to the log.
EvalPeek
Determines whether or not specified entity can peek from its current position.
Syntax
AI.EvalPeek(entityId [, bGetOptimalSide])
Returns One of the following values:
• -1 – don't need to peek
Version 1.10
809
• 0 – cannot peek
• 1 – can peek from left
• 2 – can peek from right
• 3 – can peek from left & right
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
entityId bGetOptimalSide
(optional)
Description
The ID of the entity.
Flag indicating whether or not to return the side that best fits the attention target's current location, if the AI object can peek from both sides. The default is false.
ExecuteAction
Executes an action on a set of participants.
Syntax
AI.ExecuteAction(action, participant1 [, participant2 [, ... , participantN ] ])
Parameter
action participant1 participant2..N
(optional)
Parameter
entityId position radius
Description
The smart object action name or ID.
The entity ID of the first participant in the action.
The entity ID of additional participants.
FindObjectOfType
Searches for the closest AIObject of a specified type in an area around a specified entity or position.
Once an AIObject is found, it is devalued and can't be found again for a certain number of seconds
(unless turned off in flags).
Syntax
AI.FindObjectOfType(entityId, radius, AIObjectType, flags [,returnPosition
[,returnDirection]]) AI.FindObjectOfType(position, radius, AIObjectType, [,returnPosition
[,returnDirection]])
Returns The found AIObject's name.
Description
Unique entity ID used to determine the center position of the search.
Vector specifying the center position of the search.
Radius of the search area.
Version 1.10
810
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
AIObjectType flags.
Description
AIObject type to search for (see
ScriptBindAI.cpp
and
Scripts/
AIAnchor.lua
for a complete list of AIObject types).
A combination of one or more of the following search filter flags:
•
AIFAF_VISIBLE_FROM_REQUESTER
– Requires whoever is requesting the object to also have a line of sight to it.
•
AIFAF_VISIBLE_TARGET
– Requires a line of sight between target and anchor.
•
AIFAF_INCLUDE_DEVALUED
– Include devalued objects.
•
AIFAF_INCLUDE_DISABLED
– Include disabled objects.
Position of the found object.
Direction of the found object.
returnPosition
(optional) returnDirection
(optional)
FindStandbySpotInShape
Syntax
AI.FindStandbySpotInShape(centerPos, targetPos, anchorType)
FindStandbySpotInSphere
Syntax
AI.FindStandbySpotInSphere(centerPos, targetPos, anchorType)
FreeSignal
Sends a signal to anyone in a specified radius around a position.
Syntax
AI.FreeSignal(signalType, signalText, position, radius [, entityID [,signalExtraData]])
Parameter
signalType signalText position radius entityID signalExtraData
Description
See
AI.Signal
.
See
AI.Signal
.
The center point ({x,y,z} coordinates) from which the signal is sent.
The inside radius of the area to which the signal is sent.
Optional. The ID of an entity that is a member of a group that should not receive the signal. Entities whose group ID is the value specified will not be sent the signal.
Optional. See
AI.Signal
.
Version 1.10
811
Lumberyard Developer Guide
ScriptBind Engine Functions
GetAIObjectPosition
Retrieves a specified AIObject's position.
Syntax
AI.GetAIObjectPosition(entityId | AIObjectName)
Returns AI Object position vector {x,y,z}.
Parameter
entityId |
AIObjectName
Description
Unique entity ID or AIObject name.
GetAnchor
Searches for the closest anchor of a specified type in an area around a specified entity. Once an anchor is found, it is devalued and can't be found again for a certain number of seconds (unless turned off in flags).
Syntax
AI.GetAnchor(entityId, radius, AIAnchorType, searchType [,returnPosition
[,returnDirection]])
Returns The found anchor's name.
Parameter
entityId radius
AIAnchorType searchType
(optional) returnPosition
(optional) returnDirection
Description
Unique entity ID used to determine the center position of the search.
Radius of the search area. Alternatively a search range can be specified
(min=minRad,max=maxRad).
Anchor type to search for. See
Scripts/AIAnchor.lua
for a complete list of anchor types available.
A combination of one or more of the following search filter flags:
•
AIANCHOR_NEAREST
– Nearest anchor of the specified type (default).
•
AIANCHOR_NEAREST_IN_FRONT
– Nearest anchor of the specified type inside the front cone of the entity.
•
AIANCHOR_NEAREST_FACING_AT
– Nearest anchor of the specified type that is oriented towards entity's attention target
•
AIANCHOR_RANDOM_IN_RANGE
– Random anchor of the specified type.
•
AIANCHOR_NEAREST_TO_REFPOINT
– Anchor of the specified type that is nearest to the entity's reference point.
Position of the found object.
Direction of the found object.
Version 1.10
812
Lumberyard Developer Guide
ScriptBind Engine Functions
GetAttentionTargetAIType
Retrieves the AI type (
AIOBJECT_*
) of a specified entity's attention target .
Syntax
AI.GetAttentionTargetAIType(entityId)
Returns Attention target's AI type, or
AIOBJECT_NONE
if no target.
Parameter
entityId
Description
The ID of the entity.
GetAttentionTargetDirection
Retrieves the direction of a specified entity's attention target.
Syntax
AI.GetAttentionTargetDirection(entityId, returnDir)
Returns Attention target's direction vector {x,y,z}, passed as a return value.
Parameter
entityId
Description
The ID of the entity.
GetAttentionTargetDistance
Retrieves the distance from a specified entity to its attention target.
Syntax
AI.GetAttentionTargetDistance(entityId)
Returns distance to the attention target.
Parameter
entityId
Description
The ID of the entity.
GetAttentionTargetEntity
Retrieves a specified entity's attention target entity (if it is a specified entity), or the owner entity of a dummy object's attention target (if there is an owner entity).
Syntax
AI.GetAttentionTargetEntity(ScriptHandle entityID)
Version 1.10
813
Returns Attention target's entity.
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
entityId
Description
The ID of the entity.
GetAttentionTargetOf
Retrieves a specified entity's attention target.
Syntax
AI.GetAttentionTargetOf(entityId)
Returns Name of attention target. Null if there is no target.
Parameter
entityId
Description
The ID of the entity.
GetAttentionTargetPosition
Retrieves the position of a specified entity's attention target.
Syntax
AI.GetAttentionTargetPosition(entityId, returnPos)
Returns Attention target 's position vector {x,y,z}, passed as a return value ().
Parameter
entityId
Description
The ID of the entity.
GetAttentionTargetThreat
Syntax
AI.GetAttentionTargetThreat(ScriptHandle entityID)
GetAttentionTargetType
Retrieves the type (
AITARGET_*
) of a specified entity's attention target.
Syntax
AI.GetAttentionTargetType(entityId)
Returns Attention target's type, or
AITARGET_NONE
if no target.
Version 1.10
814
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
entityId
Description
The ID of the entity.
GetAttentionTargetViewDirection
Retrieves the view direction of a specified entity's attention target.
Syntax
AI.GetAttentionTargetViewDirection(entityId, returnDir)
Returns Attention target's view direction vector {x,y,z}, passed as a return value.
Parameter
entityId
Description
The ID of the entity.
GetBeaconPosition
Gets the beacon position for a specified entity/object's group.
Syntax
AI.GetBeaconPosition(entityId | AIObjectName, returnPos)
Returns True if the beacon is found and the position set.
Parameter
entityId |
AIObjectName returnPos
Description
Unique entity ID or AI object name.
Beacon position vector {x,y,z}.
GetBehaviorBlackBoard
Retrieves a specified
AIActor
current behaviour's black board (a Lua table).
Syntax
AI.GetBehaviorBlackBoard(entity)
Returns black board – if there was one nil – Otherwise
Parameter
entityId or entityName.
Description
An
AIActor
identifier.
Version 1.10
815
Lumberyard Developer Guide
ScriptBind Engine Functions
GetBehaviorVariable
Returns a behavior variable for the specified actor.
Syntax
AI.GetBehaviorVariable(ScriptHandle entityId, const char* variableName)
GetBiasedDirection
Retrieves biased direction of certain point.
Syntax
AI.GetBiasedDirection(entityId)
Parameter
entityId
Description
The ID of the entity.
GetCurrentHideAnchor
Retrieves the name of the anchor that the entity currently is using for cover.
Syntax
AI.GetCurrentHideAnchor(entityId)
Parameter
entityId
Parameter
entityId
AIAnchorType maxDist
Description
The ID of the entity.
GetDirectAnchorPos
Retrieves the position of a cover point that a specified entity can use to directly attack its attention target.
Syntax
AI.GetDirectAttackPos(entityId, searchRange, minAttackRange)
Returns Point value, or none if no attack point is available.
Description
The ID of the entity.
Anchor type (see
Scripts/AIAnchor.lua
for a complete list of anchor types).
Maximum size of search range.
Version 1.10
816
Lumberyard Developer Guide
ScriptBind Engine Functions
GetDirLabelToPoint
Retrieves a direction label (front=0, back=1, left=2, right_3, above=4, -1=invalid) to the specified point.
Syntax
AI.GetDirLabelToPoint(entityId, point)
Parameter
entityId point
Description
The ID of the entity.
The point to evaluate.
GetEnclosingSpace
Returns the estimated surrounding navigable space in meters.
Syntax
AI.GetEnclosingSpace(entityId, Vec3 pos, float rad)
Parameter
entityId pos rad
Description
The ID of the entity.
Check position.
Check radius.
GetDistanceAlongPath
Retrieves the distance between a first and second entity, measured along the first entity's path.
Syntax
AI.GetDistanceAlongPath(entityId1, entityid2)
Returns Distance along a path. Value can be negative if the second entity is ahead along the path.
Parameter
entityId1 entityId2
Description
ID for the first entity.
ID for the second entity.
GetDistanceToClosestGroupMember
Syntax
AI.GetDistanceToClosestGroupMember(ScriptHandle entityId)
Version 1.10
817
Lumberyard Developer Guide
ScriptBind Engine Functions
GetEnclosingGenericShapeOfType
Retrieves the first shape of a certain type that encloses a specified point.
Syntax
AI.GetEnclosingGenericShapeOfType(position, type[, checkHeight])
Returns Shape name.
Parameter
position type checkHeight
(optional)
Description
Point to search for an enclosing shape.
Shape type to search for (uses anchor types).
Flag indicating whether or not to test for shape height. (default=false).
If set to true, the test checks the space between shape.aabb.min.z and shape.aabb.min.z+shape.height.
GetExtraPriority
Retrieves the extra priority value for a specified enemy entity.
Syntax
AI.GetExtraPriority(enemyEntityId)
Parameter
enemyEntityId.
Description
The ID of the entity.
GetFactionOf
Retrieves the faction of the specified entity.
Syntax
AI.GetFactionOf(ScriptHandle entityID)
Returns the faction of the specified entity.
Parameter
entityId
Description
The ID of the entity whose faction to return.
GetFormationLookingPoint
Retrieves the looking point position inside the formation.
Syntax
Version 1.10
818
Lumberyard Developer Guide
ScriptBind Engine Functions
AI.GetFormationLookingPoint(entityId)
Returns v3 – table with format {x,y,z} storing the looking point position
Parameter
entityId
Description
AI's entity.
GetFormationPointClass
Adds a follow-type node to a formation descriptor.
Syntax
AI.GetFormationPointClass(name, position)
Returns class of formation point (-1 if none found).
Parameter
name position
Description
Name of the formation descriptor.
Point index in the formation (1..N).
GetFormationPointPosition
Retrieves an entity's formation point position.
Syntax
AI.GetFormationPointPosition(entityId, pos)
Returns true if the formation point has been found.
Parameter
entityId pos
Description
The ID of the entity.
Return value for the position of the entity's formation point.
GetFormationPosition
Retrieves the relative position inside the formation.
Syntax
AI.GetFormationPosition(entityId)
Returns v3 – table with format {x,y,z} storing the relative position
Version 1.10
819
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
entityId
Description
AI's entity.
GetGroupAveragePosition
Retrieves the average position of a group's members.
Syntax
AI.GetGroupAveragePosition(entityId, properties, returnPos)
Returns the average position.
Parameter
entityId unitProperties
Description
Unique entity ID used to determine the group.
Binary mask of unit properties type for which the attack is requested, in the following form:
UPR_* + UPR* (UPR_COMBAT_GROUND + UPR_COMBAT_FLIGHT)
See
IAgent.h
for a definition of unit properties UPR_*.
GetGroupCount
Retrieves the member count of a specified entity's group.
Syntax
AI.GetGroupCount(entityId, flags, type)
Returns the count of members for the specified group.
Parameter
entityId flags type
Description
The entity or group ID.
A combination of one or more of the following flags:
•
GROUP_ALL
– Counts all agents in the group (default).
•
GROUP_ENABLED
– Counts enabled agents only (exclusive with all).
•
GROUP_MAX
– Include the maximum number of agents during the game
(can be combined with all or enabled).
The AI object type for which to filter. Counts only the AI objects of the type specified. This parameter cannot be used with the
GROUP_MAX
flag.
GetGroupMember
Returns entity that is at a specified index position in the specified group.
Version 1.10
820
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
AI.GetGroupMember(entityId|groupId, idx, flags, type)
Returns the script handler of the requested entity, or null if the requested index value is out of range.
Parameter
entityId|groupId idx flags type
Description
The entity ID or group ID.
Position in the index from 1 to n
.
A combination of one or more of the following flags:
•
GROUP_ALL
– Counts all agents in the group (default).
•
GROUP_ENABLED
– Counts enabled agents only (exclusive with all).
The AI object type for which to filter. Returns only the AI objects of the type specified. This parameter cannot be used with the
GROUP_MAX
flag..
GetGroupOf
Retrieves the group ID of a specified entity ID.
Syntax
AI.GetGroupOf(entityId)
Returns the group ID of the specified entity.
Parameter
entityId
Description
The ID of the entity whose group ID to return.
GetGroupScopeUserCount
Syntax
AI.GetGroupScopeUserCount(ScriptHandle entityIdHandle, const char* groupScopeName)
Returns the number of actors inside the group scope if greater than or equal to zero, or nil if an error occurs.
Parameter
entityId groupScopeName.
Description
The entity ID of the agent for whom you want to access the group scope.
The group scope name.
GetGroupScriptTable
Syntax
Version 1.10
821
Lumberyard Developer Guide
ScriptBind Engine Functions
AI.GetGroupScriptTable(int groupID)
GetGroupTarget
Retrieves the most threatening attention target among the AI agents in a specified entity's group. See
IAgent.h
for a definition of alert status.
Syntax
AI.GetGroupTarget(entityId [,bHostileOnly [,bLiveOnly]])
Parameter
entityId bHostileOnly
(optional) bLiveOnly (optional)
Description
Unique entity ID used to determine the group.
Flag indicating whether or not to include only hostile targets in group.
Flag indicating whether or not to include only live targets in group.
GetGroupTargetCount
Retrieves the number of attention targets among the AI agents in a specified entity's group.
Syntax
AI.GetGroupTargetCount(entityId [,bHostileOnly [,bLiveOnly]])
Parameter
entityId bHostileOnly
(optional) bLiveOnly (optional)
Description
Unique entity ID used to determine the group.
Flag indicating whether or not to include only hostile targets in group.
Flag indicating whether or not to include only live targets in group.
GetGroupTargetEntity
Syntax
AI.GetGroupTargetEntity(int groupID)
GetGroupTargetThreat
Syntax
AI.GetGroupTargetThreat(int groupID)
GetGroupTargetType
Syntax
Version 1.10
822
Lumberyard Developer Guide
ScriptBind Engine Functions
AI.GetGroupTargetType(int groupID)
GetLastUsedSmartObject
Retrieves the smart object last used by the user specified.
Syntax
AI.GetLastUsedSmartObject(userEntityId)
Returns nil if there is no last used smart object or if an error has occurred; otherwise, returns the script table of the entity that was the smart object last used by the user specified.
Parameter
userEntityId
Description
The entity ID of the user to query for the last used smart object.
GetLeader
Gets the name of a specified group leader.
Syntax
AI.GetLeader(groupID | entityID)
Returns the leader name.
Parameter
groupID entityID
Description
Unique group ID.
The ID of the entity.
GetMemoryFireType
Syntax
AI.GetMemoryFireType(entityId)
Returns the method that the puppet uses for firing at its memory target.
Parameter
entityId
Description
The ID of the entity.
GetNavigationType
Retrieves the navigation type at a specified entity's position.
Version 1.10
823
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
AI.GetNavigationType(entityId)
Returns Navigation type, such as
NAV_TRIANGULAR
,
NAV_WAYPOINT_HUMAN
,
NAV_ROAD
,
NAV_VOLUME
,
NAV_WAYPOINT_3DSURFACE
,
NAV_FLIGHT
,
NAV_SMARTOBJECT
. See the
IAISystem::ENavigationType definition for a complete list.
Parameter
entityId
Description
The ID of the entity.
GetNearestEntitiesOfType
Syntax
AI.GetNearestEntitiesOfType(entityId|objectname|position, AIObjectType, maxObjects,
returnList [,objectFilter [,radius]])
Returns the number of found entities.
Parameter
entityId | objectname
|position.
radius
AIObjectType maxObjects return list
(optional) objectFilter
Description
Unique entity ID, AI object name, or position used to pinpoint the center position of the search.
Radius of the search area.
AIObject type to search for (see
ScriptBindAI.cpp
and
Scripts/
AIAnchor.lua
for a complete list of AIObject types).
Maximum number of objects to find.
Lua table to hold the list of found entities (Lua handlers).
A combination of one or more of the following search filter flags:
•
AIOBJECTFILTER_SAMEFACTION
– Include only AI objects of the same species as the querying object.
•
AIOBJECTFILTER_SAMEGROUP
– Include only AI objects of the same group as the querying object (or with no group).
•
AIOBJECTFILTER_NOGROUP
– Include only AI objects with a Group ID of
AI_NOGROUP.
•
AIOBJECTFILTER_INCLUDEINACTIVE
– Include objects that are inactive.
GetNearestHidespot
Retrieves a specified entity's nearest hidepoint within a specified range.
Syntax
AI.GetNearestHidespot(entityId, rangeMin, rangeMax [, center])
Version 1.10
824
Lumberyard Developer Guide
ScriptBind Engine Functions
Returns Point position, if found.
Parameter
entityId rangeMin rangeMax centre (optional)
Description
The ID of the entity.
Minimum range of search area.
Maximum range of search area
Center point of the search area. If not specified, the entity's current position is used.
GetNearestPathOfTypeInRange
Retrieves the type of path nearest to a specified point of interest for a specified entity. Paths use the same types as anchors and are specified in the path properties. The function only returns paths that match the entity's navigation caps. Navigation type is also specified in the path properties.
Syntax
AI.GetNearestPathOfTypeInRange(entityId, pos, range, type [, devalue, useStartNode])
Parameter
entityId pos range type
Description
The ID of the entity.
Vector specifying to the point of interest.
Search range.
Type of path to search for.
devalue (optional) Time the returned path is marked as occupied.
useStartNode (optional) Flag indicating whether or not to look a path with any point inside the range (useStartNode=0) or one with a start node inside the range
(useStartNode=0).
GetNearestPointOnPath
Locates the point on a path nearest to a specified position.
Syntax
AI.GetNearestPointOnPath(entityId, pathname, vPos)
Parameter
entityId pathname vPos
Description
The ID of the entity.
Name of path.
Position to measure from.
Version 1.10
825
Lumberyard Developer Guide
ScriptBind Engine Functions
GetObjectBlackBoard
Retrieves a specified object's black board (a Lua table).
Syntax
AI.GetObjectBlackBoard(entity)
Returns black board – if there is one; otherwise, nil.
Parameter
entityId or entityName.
Description
An AI entity identifier.
GetObjectRadius
Retrieves the radius of a specified AI object.
Syntax
AI.GetObjectRadius(entityId)
Returns the radius size.
Parameter
entityId
Description
The ID of the entity.
GetParameter
Retrieves the value of an enumerated AI parameter for a specified entity.
Syntax
AI.GetParameter(entityId, paramEnum)
Returns the value of the parameter.
Parameter
entityId paramEnum
Description
The ID of the entity.
The index of the parameter to get. See
AI.ChangeParameter()
for a complete list.
GetPathLoop
Syntax
AI.GetPathLoop(entityId, pathname)
Version 1.10
826
Lumberyard Developer Guide
ScriptBind Engine Functions
Returns true if path is successfully looped.
Parameter
entityId pathname
Description
The ID of the entity.
Name of the path.
GetPathSegNoOnPath
Syntax
AI.GetPathSegNoOnPath(entityId, pathname, vPos)
Returns Segment ratio (0.0 start point, 100.0 end point).
Parameter
entityId pathname vPos
Description
The ID of the entity.
Name of path.
Position.
GetPeakThreatLevel
Syntax
AI.GetPeakThreatLevel(ScriptHandle entityID)
GetPeakThreatType
Syntax
AI.GetPeakThreatType(ScriptHandle entityID)
GetPointOnPathBySegNo
Syntax
AI.GetPointOnPathBySegNo(entityId, pathname, segNo)
Returns Point by segment ratio (0.0 start point, 100.0 end point).
Parameter
entityId pathname segNo
Description
The ID of the entity.
Name of path.
Segment ratio.
Version 1.10
827
Lumberyard Developer Guide
ScriptBind Engine Functions
GetPosturePriority
Sets the specified entity's posture priority.
Syntax
AI.GetPosturePriority(ScriptHandle entityId, const char* postureName)
GetPotentialTargetCount
Retrieves the total number of a specified entity's potential targets.
Syntax
AI.GetPotentialTargetCount(ScriptHandle entityID)
Parameter
entityId
Description
The ID of the entity.
GetPotentialTargetCountFromFaction
Retrieves the number of an entity's potential targets that belong to a specified faction.
Syntax
AI.GetPotentialTargetCountFromFaction(ScriptHandle entityID, const char* factionName)
Parameter
entityId name
Description
The ID of the entity.
Faction name.
GetPredictedPosAlongPath
Retrieves the predicted position of an AI agent along its path at a specified time.
Syntax
AI.GetPredictedPosAlongPath(entityId, time, retPos)
Returns True if successful.
Parameter
entityId time retPos
Description
The ID of the entity.
Time (in seconds) to predict position.
Return point value of the predicted position .
Version 1.10
828
Lumberyard Developer Guide
ScriptBind Engine Functions
GetPreviousBehaviorName
Syntax
AI.GetPreviousBehaviorName(ScriptHandle entityID)
GetPreviousPeakThreatLevel
Syntax
AI.GetPreviousPeakThreatLevel(ScriptHandle entityID)
GetPreviousPeakThreatType
Syntax
AI.GetPreviousPeakThreatType(ScriptHandle entityID)
GetProbableTargetPosition
Retrieves the probable target position of a specified entity.
Syntax
AI.GetProbableTargetPosition(entityId)
Parameter
entityId
Description
The ID of the entity.
GetRefPointDirection
Retrieves a specified entity's reference point direction.
Syntax
AI.GetRefPointDirection(entityId)
Returns a script vector (x,y,z) reference point direction.
Parameter
entityId
Description
The ID of the entity.
GetRefPointPosition
Retrieves a specified entity's reference point "world" position.
Syntax
Version 1.10
829
Lumberyard Developer Guide
ScriptBind Engine Functions
AI.GetRefPointPosition(entityId)
Returns a script vector (x,y,z) reference point position.
Parameter
entityId
Description
The ID of the entity.
GetRefShapeName
Retrieves the name of a specified entity's reference shape.
Syntax
AI.GetRefShapeName(entityId)
Returns a reference shape name.
Parameter
entityId
Description
The ID of the entity.
GetSoundPerceptionDescriptor
Retrieves information about how the specified entity perceives sound types.
Syntax
AI.GetSoundPerceptionDescriptor(entityId, soundType, descriptorTable)
Returns true if the information is successfully returned.
Parameter
entityId soundType descriptorTable
Description
Entity to get perception data on.
Type of sound stimulus to get data for.
Location to store retrieved data.
GetStance
Retrieves the specified entity's stance.
Syntax
AI.GetStance(entityId)
Returns entity stance (
STANCE_*
)
Version 1.10
830
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
entityId
Description
The ID of the entity.
GetSubTypeOf
Retrieves a specified entity's sub type.
Syntax
AI.GetSubTypeOf(entityId)
Returns the entity sub type (as defined in
IAgent.h
).
Parameter
entityId
Description
The ID of the entity.
GetTacticalPoints
Retrieves a point matching a description, related to a specified entity. Format of a point is: { x,y,z }.
Syntax
AI.GetTacticalPoints(entityId, tacPointSpec, point)
Returns true if a valid point is found; otherwise, false.
Parameter
entityId tacPointSpec.
point
Description
AI's entity.
A table specifying the points required.
Coordinates of the point found.
GetTargetSubType
Retrieves the subtype of a specified entity's current attention target.
Syntax
AI.GetTargetSubType(entityId)
Returns an attention target subtype. See
IAgent.h
for a list of target type definitions.
Parameter
entityId
Description
The ID of the entity.
Version 1.10
831
Lumberyard Developer Guide
ScriptBind Engine Functions
GetTargetType
Retrieves the type of a specified entity's current attention target.
Syntax
AI.GetTargetType(entityId)
Returns an attention target type, such as
AITARGET_NONE
,
AITARGET_MEMORY
,
AITARGET_BEACON
,
AITARGET_ENEMY
. See
IAgent.h
for a list of target type definitions.
Parameter
entityId
Description
The ID of the entity.
GetTotalLengthOfPath
Retrieves total length of the specified path.
Syntax
AI.GetTotalLengthOfPath(entityId, pathname)
Parameter
entityId pathname
Description
The ID of the entity.
Name of path.
GetTypeOf
Retrieves a specified entity's type.
Syntax
AI.GetTypeOf(entityId)
Returns the entity type (as defined in
IAgent.h
).
Parameter
entityId
Description
The ID of the entity.
GetUnitCount
Retrieves the number of units the leader knows about. The leader is identified based on the group ID of the entity.
Syntax
AI.GetUnitCount(entityId, unitProperties)
Version 1.10
832
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
entityId unitProperties
Description
The ID of the entity.
Binary mask of unit properties type for which the attack is requested, in the following form:
UPR_* + UPR* (UPR_COMBAT_GROUND + UPR_COMBAT_FLIGHT)
See
IAgent.h
for a definition of unit properties UPR_*.
GetUnitInRank
Retrieves the entity that holds the specified rank position in the specified group.
Syntax
AI.GetUnitInRank(groupID [,rank])
Returns entity script table of the ranked unit.
Parameter
groupID rank
Description
The ID of the group that contains the entity to retrieve.
The rank position of the entity to retrieve. If null or a value less than or equal to zero is specified, retrieves the entity with the highest rank in the entity. The value of the highest rank is 1.
GoTo
Allows the specified entity to move to a certain destination.
Syntax
AI.GoTo(entityId, vDestination)
Parameter
entityId vDestination.
.
Description
AI's entity.
Hostile
Determines whether or not two entities are hostile.
Syntax
AI.Hostile(entityId, entity2Id|AIObjectName)
Returns true if the entities are hostile.
Version 1.10
833
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
entityId entity2Id |
AIObjectName
Description
ID of the first AI entity.
ID of the second AI entity, or AIobject name.
IgnoreCurrentHideObject
Marks the current hide object as unreachable; it will be omitted from future hidespot selections.
Syntax
AI.IgnoreCurrentHideObject(entityId)
Parameter
entityId
Description
The ID of the entity.
IntersectsForbidden
Determines whether or not the specified line is in a forbidden region.
Syntax
AI.IntersectsForbidden(Vec3 start, Vec3 end)
Returns intersected position or end (if there is no intersection).
Parameter
start end
Description
Vector in format {x,y,z}.
Vector in format {x,y,z}.
IsAgentInAgentFOV
Determines whether or not one entity is in the field of view of another entity.
Syntax
AI.IsAgentInAgentFOV(entityId, entityId2)
Returns the first value true if the agent is within the entity FOV; the second value true if the agent is within the entity's primary FOV, or false if the agent is within the entity's secondary FOV.
Parameter
entityId entityId2.
Description
The AI entity whose FOV to check.
The entity ID of the agent.
Version 1.10
834
Lumberyard Developer Guide
ScriptBind Engine Functions
IsAgentInTargetFOV
Determines whether or not the entity is in the FOV of the attention target.
Syntax
AI.IsAgentInTargetFOV(entityId, fov)
Returns true if in the FOV of the attention target; otherwise, false.
Parameter
entityId fov
Description
The ID of the entity.
FOV of the enemy in degrees.
IsAimReady
Syntax
AI.IsAimReady(ScriptHandle entityIdHandle)
IsCoverCompromised
Syntax
AI.IsCoverCompromised(entityId)
Returns true if the cover has been compromised; otherwise, nil.
Parameter
entityId
Description
AI's entity.
IsEnabled
Checks that the entity is AI-enabled.
Syntax
AI.IsEnabled(entityId)
Parameter
entityId
Description
The ID of the entity.
IsFireEnabled
Determines whether or not the AI is allowed to fire or not.
Syntax
Version 1.10
835
Lumberyard Developer Guide
ScriptBind Engine Functions
AI.IsFireEnabled(entityId)
Returns true if AI is enabled to fire
Parameter
entityId
Description
The ID of the entity.
IsInCover
Determines whether or not the agent is using cover.
Syntax
AI.IsInCover(entityId)
IsLowHealthPauseActive
Syntax
AI.IsLowHealthPauseActive(ScriptHandle entityID)
IsLowOnAmmo
Syntax
AI.IsLowOnAmmo(entityId)
Parameter
entityId threshold
Description
AI's entity.
The ammo percentage threshold.
IsMoving
Determines whether or not the agent wants to move.
Syntax
AI.IsMoving(entityId)
Parameter
entityId
IsMovingInCover
Syntax
Description
The ID of the entity.
Version 1.10
836
Lumberyard Developer Guide
ScriptBind Engine Functions
AI.IsMovingInCover(entityId)
Returns true – Agent is moving in cover nil – if not
Parameter
entityId
Description
AI's entity.
IsMovingToCover
Determines whether or not the agent is running to cover.
Syntax
AI.IsMovingToCover(entityId)
Parameter
entityId
Description
AI's entity.
IsOutOfAmmo
Syntax
AI.IsOutOfAmmo(entityId)
Returns true if the specified entity is out of ammunition; otherwise, nil.
Parameter
entityId
Description
The ID of the AI entity.
IsPersonallyHostile
Syntax
AI.IsPersonallyHostile(ScriptHandle entityID, ScriptHandle hostileID)
IsPointInFlightRegion
Determines whether or not a specified point is in the flight region.
Syntax
AI.IsPointInFlightRegion(point)
Returns true if the point is in the flight region.
Version 1.10
837
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
point
Description
Vector in format {x,y,z}.
IsPointInsideGenericShape
Determines whether or not a point is inside a specified shape.
Syntax
AI.IsPointInsideGenericShape(position, shapeName[, checkHeight])
Parameter
position shapeName checkHeight
(optional)
Description
Position to check.
Name of the shape to test (returned by
AI.GetEnclosingGenericShapeOfType
).
Flag indicating whether or not to test for shape height. (default=false). If set to true, the test will check the space between shape.aabb.min.z and shape.aabb.min.z+shape.height.
IsPointInWaterRegion
Determines whether or not the point is in the water region.
Syntax
AI.IsPointInWaterRegion(point)
Returns a value that indicates water or ground level. Values greater than 0 mean there is water.
IsPunchableObjectValid
Determines whether or not a punchable object is valid.
Syntax
AI.IsPunchableObjectValid(userId, objectId, origPos)
Parameter
userId.
objectId.
origPos.
IsTakingCover
Syntax
Description
User ID.
Object ID.
Object position in the world.
Version 1.10
838
Lumberyard Developer Guide
ScriptBind Engine Functions
AI.IsTakingCover(entityId, [distanceThreshold])
Returns true if the specfied agent is either in cover or running to cover; otherwise, nil.
Parameter
entityId distanceThreshold.
Description
AI's entity.
(Optional) Distance over which an agent that is running to cover is considered to not yet have taken cover.
LoadBehaviors
Syntax
AI.LoadBehaviors(const char* folderName, const char* extension)
LogComment
Writes additional information to the log for debugging purposes.
Syntax
AI.LogComment(szMessage)
Parameter
szMessage
Description
The message to write to the log.
LogEvent
Writes event-driven information to the log that for debugging purposes. Events may occur on a perframe or a per AI update basis.
Syntax
AI.LogEvent(szMessage)
Parameter
szMessage
Description
The message to write to the log.
LogProgress
Writes progress messages to the log.
Syntax
AI.LogProgress(szMessage)
Version 1.10
839
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
szMessage
Description
The message to write to the log.
MeleePunchableObject
Syntax
AI.MeleePunchableObject(entityId, objectId, origPos)
Parameter
entityId objectId origPos
Description
The ID of the AI entity.
Object ID.
Position of the melee punchable object.
ModifySmartObjectStates
Adds or removes smart object states for a specified entity.
Syntax
AI.ModifySmartObjectStates(entityId, listStates)
Parameter
entityId listStates
Description
The ID of the entity.
The list of state names to be added or removed (such as "Closed, Locked",
"Open, Unlocked, Busy").
ParseTables
Syntax
AI.ParseTables(int firstTable, bool parseMovementAbility, IFunctionHandler* pH,
AIObjectParams& aiParams, bool& updateAlways)
Parameter
firstTable parseMovementAbility aiParams updateAlways
Description
Properties table.
True to parse movement ability, false otherwise.
AI parameters.
True to always update; false otherwise.
Version 1.10
840
Lumberyard Developer Guide
ScriptBind Engine Functions
PlayCommunication
Plays communication on the AI agent.
Syntax
AI.PlayCommunication(ScriptHandle entityId, const char* commName, const char* channelName,
float contextExpiry)
Parameter
entityId commName channelName
Description
The ID of the entity.
The name of the communication to play.
The name of the channel where the communication will play.
PlayReadabilitySound
Plays readability sound on the AI agent. This call does not do any filtering like playing readability using signals.
Syntax
AI.PlayReadabilitySound(entityId, soundName)
Parameter
entityId soundName stopPreviousSounds
(Optional) responseDelayMin
(Optional) repsonseDelayMax
(Optional)
Description
The ID of the entity.
The name of the readability sound signal to play.
True if any currently playing readability should be stopped in favor of this one.
Minimum (or exact, if no maximum) delay for the response readability to play.
Maximum delay for the response readability to play.
ProcessBalancedDamage
Processes balanced damage.
Syntax
AI.ProcessBalancedDamage(pShooterEntity, pTargetEntity, damage, damageType)
Parameter
pShooterEntity
Description
Shooter ID.
Version 1.10
841
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
pTargetEntity damage damageType
Description
Target ID.
Hit damage.
Hit damage type.
QueueBubbleMessage
Syntax
AI.QueueBubbleMessage(ScriptHandle entityID, const char* message)
RecComment
Records a comment with AI Debug Recorder. For information about the AI Debug Recorder, see Using the
AI Debug Recorder .
Syntax
AI.RecComment(szMessage)
Parameter
szMessage
Description
Message line to be displayed in Recorder view.
RegisterDamageRegion
Registers a spherical region that causes damage (so should be avoided in pathfinding). The owner entity position is used as the region center. The function can be called multiple times to update the region position.
Syntax
AI.RegisterDamageRegion(entityId, radius)
Parameter
entityId radius
Description
The ID of the entity.
The radius of the spherical region. If less than or equal to zero, the region is disabled.
RegisterInterestedActor
Registers the interested actor with the interest system. Any errors go to the error log.
Syntax
AI.RegisterInterestedActor(ScriptHandle entityId, float fInterestFilter, float
fAngleInDegrees)
Version 1.10
842
Lumberyard Developer Guide
ScriptBind Engine Functions
Returns true if a valid update was performed; otherwise, nil. Nil can be returned if the interest system is disabled or the parameters are not valid.
Parameter
entityId
Description
The ID of the AI entity.
RegisterInterestingEntity
Registers the specified entity with the interest system. Any errors go to the error log.
Syntax
AI.RegisterInterestingEntity(ScriptHandle entityId, float radius, float baseInterest, const
char* actionName, Vec3 offset, float pause, int shared)
Returns true if a valid update was performed; otherwise, nil. Nil can be returned if the interest system is disabled or the parameters are not valid.
Parameter
entityId
Description
The ID of the entity.
RegisterTacticalPointQuery
Retrieves a query ID for the specified tactical point query.
Syntax
AI.RegisterTacticalPointQuery(querySpecTable)
Returns > 0 – If the query was parsed successfully 0 – Otherwise
Parameter
querySpecTable
Description
Table specifying the query. For more information, see
RegisterTargetTrack
Registers an AI entity to use a specified target track configuration for target selection. The parameter ai_TargetTracking
must be set to '2'.
Syntax
AI.RegisterTargetTrack(entityId, configuration, targetLimit, classThreat)
Returns true if successfully registered.
Parameter
entityId
Description
The ID of the entity.
Version 1.10
843
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
configuration targetLimit classThreat
(optional)
Description
Target track configuration.
The number of agents who can target the AI at any specified time (0 for infinite).
Initial class threat value.
RemovePersonallyHostile
Syntax
AI.RemovePersonallyHostile(ScriptHandle entityID, ScriptHandle hostileID)
RequestAttack
In a group with a leader, allows the leader to issue a request for a group attack behavior against the enemy. After this request, the
Cleader
may create an attack leader action (
CLeaderAction_Attack_*
).
Syntax
AI.RequestAttack(entityId, unitProperties, attackTypeList [,duration])
Parameter
entityId unitProperties attackTypeList duration (optional)
Description
Unique entity ID used to determine the group leader.
Binary mask of unit properties type for which the attack is requested, in the following form:
UPR_* + UPR* (UPR_COMBAT_GROUND + UPR_COMBAT_FLIGHT)
See
IAgent.h
for a definition of unit properties
UPR_*
.
Lua table containing a prioritized list of preferred attack strategies (leader action subtypes). The list must be in the following format:
{LAS_*, LAS_*,..} (LAS_ATTACK_ROW,LAS_ATTACK_FLANK) which means that the first attempt will be an Attack_row action , and if that fails an attack_flank.
See
IAgent.h
for a definition of LeaderActionSubtype (
LAS_*
) action types.
Maximum duration in seconds (default = 0).
RequestToStopMovement
Syntax
AI.RequestToStopMovement(ScriptHandle entityId)
ResetAgentLookAtPos
Resets the specified entity's previous call to
AgentLookAtPos()
.
Version 1.10
844
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
AI.ResetAgentLookAtPos(entityId)
Parameter
entityId
Description
The ID of the entity.
ResetAgentState
Resets a particular aspect of the agent's state, such as "lean".
Syntax
AI.ResetAgentState(ScriptHandle entityId, const char * stateLabel)
Returns nil
Parameter
entityId stateLabel
Description
The ID of the AI entity.
String describing the state that must be reset to default.
ResetParameters
Resets all parameters for a specified entity.
Syntax
AI.ResetParameters(entityId, bProcessMovement, PropertiesTable, PropertiesInstanceTable)
Parameter Description
entityId bProcessMovement
The ID of the entity whose parameters you want to reset.
True to reset movement data; otherwise, false.
PropertiesTable
The Lua table that contains the entity's properties.
PropertiesInstanceTable
The Lua table that contains instance-specific entity properties.
ResetPersonallyHostiles
Syntax
AI.ResetPersonallyHostiles(ScriptHandle entityID, ScriptHandle hostileID)
ScaleFormation
Changes the scale factor of a specified entity's formation (if one exists).
Version 1.10
845
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
AI.ScaleFormation(entityId, scale)
Returns true if formation scaling was successful.
Parameter
entityId scale
Description
The ID of the entity.
Scale factor.
SequenceBehaviorReady
Syntax
AI.SequenceBehaviorReady(ScriptHandle entityId)
SequenceInterruptibleBehaviorLeft
Syntax
AI.SequenceInterruptibleBehaviorLeft(ScriptHandle entityId)
SequenceNonInterruptibleBehaviorLeft
Syntax
AI.SequenceNonInterruptibleBehaviorLeft(ScriptHandle entityId)
SetAlarmed
Sets the entity to be "perception alarmed".
Syntax
AI.SetAlarmed(entityId)
SetAnimationTag
Sets a mannequin animation tag.
Syntax
AI.SetAnimationTag(ScriptHandle entityID, const char* tagName)
Returns a default result code (in Lua: void).
Parameter
entityId
Description
The ID of the AI entity on which to set the animation tag.
Version 1.10
846
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
tagName
Description
The name of the animation tag that should be set (case insensitive).
SetAssesmentMultiplier
Sets the assesment multiplier factor for the specified AIObject type.
Syntax
AI.SetAssesmentMultiplier(AIObjectType, multiplier)
Parameter
AIObjectType multiplier
Description
Type of AIObject. See
ScriptBindAI.cpp
for a complete list of AIObject types.
Assesment multiplier factor.
SetAttentiontarget
Sets a new attention target.
Syntax
AI.SetAttentiontarget(entityId, targetId)
Parameter
entityId targetId
Description
The ID of the entity.
Target's entity ID.
SetBeaconPosition
Sets the beacon's position for the specified entity/object's group.
Syntax
AI.SetBeaconPosition(entityId | AIObjectName, pos)
Parameter
entityId |
AIObjectName pos
Description
Unique entity ID or AI object name.
Vector {x,y,z} where the beacon position will be set.
SetBehaviorTreeEvaluationEnabled
Syntax
Version 1.10
847
Lumberyard Developer Guide
ScriptBind Engine Functions
AI.SetBehaviorTreeEvaluationEnabled(ScriptHandle entityID, bool enable)
SetBehaviorVariable
Sets a behaviour variable for the specified actor.
Syntax
AI.SetBehaviorVariable(ScriptHandle entityId, const char* variableName, bool value)
SetCollisionAvoidanceRadiusIncrement
Syntax
AI.SetCollisionAvoidanceRadiusIncrement(ScriptHandle entityId, float radius)
SetContinuousMotion
Syntax
AI.SetContinuousMotion(ScriptHandle entityID, bool continuousMotion)
SetCoverCompromised
Syntax
AI.SetCoverCompromised(entityId)
Parameter
entityId
Description
The ID of the AI entity.
SetEntitySpeedRange
Syntax
AI.SetEntitySpeedRange(userEntityId, urgency, defaultSpeed, minSpeed, maxSpeed, stance =
all)
Returns true if the operation was successful and false otherwise
Parameter
minSpeed
Description
usedEntityId
The entity ID of the user for which its last used smart object is needed.
urgency
The integer value specifying the movement urgency (see
AgentMovementSpeeds::EAgentMovementUrgency
).
defaultSpeed
Floating point value that specfies the default speed.
Floating point value that specifies the minimum speed.
Version 1.10
848
Lumberyard Developer Guide
ScriptBind Engine Functions
SetExtraPriority
Sets a extra priority value to the specified enemy entity.
Syntax
AI.SetExtraPriority(enemyEntityId, increment)
Parameter
enemyEntityId float increment
Description
The ID of the entity.
Value to add to the target's priority.
SetFactionOf
Sets the faction to which the specified entity belongs.
Syntax
AI.SetFactionOf(ScriptHandle entityID, const char* factionName)
Parameter
entityId factionName
Description
The ID of the entity whose faction to return.
The name of the faction to assign to the specified entity.
SetFactionThreatMultiplier
Sets the threat multiplier factor for the specified species. A return value of 0 indicates that the species is not hostile to any other species.
Syntax
AI.SetFactionThreatMultiplier(nSpecies, multiplier)
SetFireMode
Sets fire mode immediately.
Syntax
AI.SetFireMode(entityId, mode)
Parameter
entityId firemode
Description
The ID of the entity.
New fire mode.
Version 1.10
849
Lumberyard Developer Guide
ScriptBind Engine Functions
SetFormationAngleThreshold
Sets the relative position inside the formation.
Syntax
AI.SetFormationAngleThreshold(entityId, fAngleThreshold)
Parameter
entityId fAngleThreshold
Description
The ID of the AI entity.
New leader orientation angle threshold in degrees.
SetFormationLookingPoint
Sets the relative looking point position inside the formation.
Syntax
AI.SetFormationLookingPoint(entityId, v3RelativePosition)
Parameter
entityId v3RelativePosition
Description
The ID of the AI entity.
Table with format {x,y,z} storing the new relative looking point.
SetFormationPosition
Sets the relative position inside the formation.
Syntax
AI.SetFormationPosition(entityId, v2RelativePosition)
Parameter
entityId v2RelativePosition
Description
The ID of the AI entity.
Table with format {x,y} storing the new relative position.
SetFormationUpdate
Sets the update flag for a specified entity's formation (if one exists). If this flag is false, the formation is no longer updated.
Syntax
AI.SetFormationUpdate(entityId, update)
Returns true if the request was successful.
Version 1.10
850
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
entityId update
Description
The ID of the entity.
True to update the flag; otherwise, false.
SetFormationUpdateSight
Sets a random angle rotation for a specified entity's formation sight directions.
Syntax
AI.SetFormationUpdateSight(entityId, range, minTime, maxTime)
Parameter
entityId range minTime (optional) maxTime (optional)
Description
The ID of the entity.
Angle of rotation (0,360) around the default sight direction.
Minimum timespan for changing the direction (default = 2).
Minimum timespan for changing the direction (default = minTime).
SetIgnorant
Sets the specified AI entity to ignore system signals, visual stimuli and sound stimuli.
Syntax
AI.SetIgnorant(entityId, ignorant)
Parameter
entityId ignorant
Description
The ID of the AI entity.
A flag indicating whether or not the entity ignores system signals. 0 specifies do not ignore; 1 specifies ignore.
SetInCover
Syntax
AI.SetInCover(entityId, bool inCover)
Parameter
entityId inCover
Description
The ID of the AI entity.
Specifies whether the entity should be set to be in cover or not.
Version 1.10
851
Lumberyard Developer Guide
ScriptBind Engine Functions
SetLeader
Sets a specified entity as the group leader. This action associates a
CLeader
object with the entity, creating it if one doesn't exist. Only one leader can be set per group.
Syntax
AI.SetLeader(entityID)
Returns true if successful.
Parameter
entityID
Description
Unique entity ID to set as leader.
SetMemoryFireType
Sets how the AI agent handles firing at its memory target.
Syntax
AI.SetMemoryFireType(entityId, type)
Parameter
entityId type
Description
The ID of the entity.
Memory fire type. Possible values from enum EMemoryFireType
in
IAgent.h
: eMFT_Disabled = 0, // Never allowed to fire at memory eMFT_UseCoverFireTime, // Can fire at memory using the
weapon's cover fire time eMFT_Always, // Always allowed to fire at memory
SetMovementContext
Sets the specified entity's movement context.
Syntax
AI.SetMovementContext(ScriptHandle entityId, int context)
Parameter
entityId context
Description
The ID of the entity.
context value .
SetPathAttributeToFollow
Sets the attribute of a specified entity's path.
Version 1.10
852
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
AI.SetPathAttributeToFollow(entityId, flag)
Parameter
entityId flag
Description
The ID of the entity.
Attribute to set.
SetPathToFollow
Sets the path for a specified entity to follow.
Syntax
AI.SetPathToFollow(entityId, pathName)
Parameter
entityId pathName
Description
The ID of the entity.
Name of the path to be followed.
SetPFBlockerRadius
Syntax
AI.SetPFBlockerRadius(entityId, blocker, radius)
Parameter
entityId
Description
The ID of the entity.
SetPointListToFollow
Sets a point list for a specified entity's path.
Syntax
AI.SetPointListToFollow(entityId, pointlist, howmanypoints, bspline [, navtype])
Parameter
entityId pointList howmanypoints
Description
The ID of the entity.
List of points for the entity to follow, expressed as a set of local vectors:
{{x=0.0, y=0.0, z=0.0},
.
Number of points in the list.
Version 1.10
853
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
bspline navtype
Description
Flag indicating whether or not the path line is recalculated using spline interpolation.
(Optional) Navigation type (default =
IAISystem::NAV_FLIGHT
).
SetPosturePriority
Sets the specified entity's posture priority.
Syntax
AI.SetPosturePriority(ScriptHandle entityId, const char* postureName, float priority)
SetPostures
Sets the specified entity's postures.
Syntax
AI.SetPostures(ScriptHandle entityId, SmartScriptTable postures)
Parameter
entityId postures
Description
The ID of the entity.
The table of postures.
SetRefPointAtDefensePos
Sets a specified entity's reference point position to an intermediate distance between the entity's attention target and a specified point.
Syntax
AI.SetRefPointAtDefensePos(entityId, point2defend, distance)
Parameter
entityId point2defend distance
Description
The ID of the entity.
Point to defend.
Maximum distance between reference point and point to defend.
SetRefPointDirection
Sets a specified entity's reference point direction.
Syntax
AI.SetRefPointDirection(vRefPointDir)
Version 1.10
854
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
vRefPointDir
Description
Direction as a (script)vector (x,y,z) value.
SetRefPointPosition
Sets a specified entity's reference point "world" position.
Syntax
AI.SetRefPointPosition(entityId, vRefPointPos)
Parameter
entityId vRefPointPos
Description
The ID of the entity.
World position as a (script)vector (x,y,z) value.
SetRefPointRadius
Sets a specified entity's reference point radius.
Syntax
AI.SetRefPointRadius(entityId, radius)
Parameter
entityId radius
Description
The ID of the entity.
The reference point radius.
SetRefpointToAnchor
Sets a reference point to an anchor.
Syntax
AI.SetRefpointToAnchor(entityId, rangeMin, rangeMax, findType, findMethod)
Parameter
entityId rangeMin rangeMax findType findMethod
Description
The ID of the AI entity.
Minimum range.
Maximum range.
Finding type.
Finding method.
Version 1.10
855
Lumberyard Developer Guide
ScriptBind Engine Functions
SetRefpointToPunchableObject
Sets the reference point to the punchable object.
Syntax
AI.SetRefpointToPunchableObject(entityId, range)
Parameter
entityId range
Description
The ID of the AI entity.
Range for the punchable object.
SetRefShapeName
Sets the name of a specified entity's reference shape.
Syntax
AI.SetRefShapeName(entityId, name)
Parameter
entityId name
Description
The ID of the entity.
Name of the reference shape.
SetSmartObjectState
Sets a single smart object state, replacing all other states.
Syntax
AI.SetSmartObjectState(entityId, stateName)
Parameter
entityId stateName
Description
The ID of the entity.
The name of the new state to set for the smart object (such as "Idle").
SetSoundPerceptionDescriptor
Sets information about how the specified entity perceives sound types.
Syntax
AI.SetSoundPerceptionDescriptor(entityId, soundType, descriptorTable)
Version 1.10
856
Lumberyard Developer Guide
ScriptBind Engine Functions
Returns True if information successfully saved.
Parameter
entityId soundType descriptorTable
Description
Entity to set perception data for.
Type of sound stimulus to set data for.
Perception data to saved.
SetSpeed
Sets the entity's current speed (urgency).
Syntax
AI.SetSpeed(entityId, urgency)
Parameter
entityId urgency
Description
AI's entity.
A float value that specifies the movement urgency (see
AgentMovementSpeeds::EAgentMovementUrgency
).
SetStance
Sets the specified entity's stance.
Syntax
AI.SetStance(entityId, stance)
Parameter
entityId stance
Description
The ID of the entity.
The stance value (
STANCE_*
).
SetTargetTrackClassThreat
Sets the class threat for a specified entity's target track.
Syntax
AI.SetTargetTrackClassThreat(entityId, classThreat)
Parameter
entityId
Description
The ID of the entity.
Version 1.10
857
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
classThreat
Description
New class threat value.
SetTempTargetPriority
Sets a specified entity's selection priority for a temporary target over other potential targets.
Syntax
AI.SetTempTargetPriority(entityId, priority)
Returns True if successfully updated.
Parameter
entityId priority
Description
The ID of the entity.
New priority value.
SetTerritoryShapeName
Sets the territory shape of the specified AI entity.
Syntax
AI.SetTerritoryShapeName(entityId, shapeName)
Parameter
entityId shapeName
Description
The ID of the entity.
Name of the shape to set.
SetUnitProperties
Sets the leader's knowledge about the unit's combat capabilities. The leader is identified based on the group ID of the entity.
Syntax
AI.SetUnitProperties(entityId, unitProperties)
Parameter
entityId unitProperties
Description
The ID of the entity.
Binary mask of unit properties in the following form:
UPR_* + UPR* (UPR_COMBAT_GROUND + UPR_COMBAT_FLIGHT)
See
IAgent.h
for a definition of the
UPR_*
unit properties.
Version 1.10
858
Lumberyard Developer Guide
ScriptBind Engine Functions
SetUseSecondaryVehicleWeapon
Enables or disables the AI object's ability to use the secondary weapon when firing from a vehicle gunner seat if possible.
Syntax
AI.SetUseSecondaryVehicleWeapon(entityId, bUseSecondary)
Parameter
entityId bUseSecondary
Description
The ID of the entity.
Specify true to use the secondary weapon; otherwise, false.
Signal
Adds a signal to the sender's signal queue even if another signal with same text is present.
Syntax
AI.Signal(signalFilter, signalType, signalText, senderId [, signalExtraData])
Parameter
signalFilter signalType signalText senderId signalExtraData
Description
The signal filter.
The signal type.
Signal text that is processed by the receivers, either in a Lua callback with the same name as the text or directly by the
CAIObject
.
The ID of the sender.
Optional. A Lua table containing additional data. It can contain the following data types:
• point
– A vector in the format {x,y,z}.
• point2
– A vector in the format {x,y,z}.
•
ObjectName
– A string.
• id
– An entity ID.
• fValue
– A float value.
• iValue
– An integer value.
• iValue2
– A second integer value.
SmartObjectEvent
Executes a smart action.
Syntax
AI.SmartObjectEvent(actionName, userEntityId, objectEntityId [, vRefPoint])
Version 1.10
859
Lumberyard Developer Guide
ScriptBind Engine Functions
Returns 0 if a smart object rule was not found or if a non-zero ID was inserted to execute the action.
Parameter
actionName usedEntityId objectEntityId vRefPoint
Description
The name of the smart action.
The entity ID of the user who wants to execute the smart action, or none if the user is unknown.
The entity ID of the object on which the smart action is to be executed, or none if the object is unknown.
Optional. The reference point to be used instead of the user's attention target position.
SoundEvent
Generates a sound event with the specified parameters in the AI system.
Syntax
AI.SoundEvent(position, radius, threat, interest, entityId)
Parameter
position radius threat interest entityId
Description
Origin of the sound event.
Area the sound event is heard in.
Sound event property.
Sound event property.
Unique entity ID that generates the sound event.
StopCommunication
Stops specified communication.
Syntax
AI.StopCommunication(ScriptHandle playID)
Parameter
playID
Description
The ID of the communication to stop.
ThrowGrenade
Throws a specified grenade at a target type without interrupting the fire mode.
Syntax
Version 1.10
860
Lumberyard Developer Guide
ScriptBind Engine Functions
AI.ThrowGrenade(entityId, grenadeType, regTargetType)
Parameter
entityId grenadeType regTargetType
Description
The ID of the entity.
Requested grenade type (see
ERequestedGrenadeType
).
The grenade target type ( see AI_REG_*
).
UnregisterInterestedActor
Unregisters the entity with the interest system. Any errors are recorded in the error log.
Syntax
AI.UnregisterInterestedActor(ScriptHandle entityId)
Parameter
entityId
Description
The ID of the entity.
UnregisterInterestingEntity
Unregisters the specified entity with the interest system. Any errors are recorded in the error log.
Syntax
AI.UnregisterInterestingEntity(ScriptHandle entityId)
Parameter
entityId
Description
The ID of the entity.
UnregisterTargetTrack
Unregisters an AI object from the target track manager. The parameter ai_TargetTracking
must be set to '2'.
Syntax
AI.UnregisterTargetTrack(entityId)
Returns true if successfully unregistered.
Parameter
entityId
Description
The ID of the entity.
Version 1.10
861
Parameter
entityId vPos
Lumberyard Developer Guide
ScriptBind Engine Functions
UpdateGlobalPerceptionScale
Syntax
AI.UpdateGlobalPerceptionScale(float visualScale, float audioScale)
UpdateTempTarget
Updates the position of the specified entity's temporary potential target.
Syntax
AI.UpdateTempTarget(entityId, vPos)
Returns true if successfully updated.
Description
The ID of the entity.
New position of the temporary target.
UpTargetPriority
Changes a specified entity's target priority value for a specified target, if the target is on the entity's target list.
Syntax
AI.UpTargetPriority(entityId, targetId, increment)
Parameter
entityId targetId increment
Description
The ID of the entity.
The entity ID of the target.
New value for the target priorty.
VisualEvent
Generates a visual event with the specified parameters in the AI system.
Syntax
AI.VisualEvent(entityId, targetId)
Parameter
entityId
Description
The ID of the entity that receives the visual event.
Version 1.10
862
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
targetId
Description
The ID of the visual target (that the entity is seeing).
Warning
Writes a warning message to the log about data or script errors.
Syntax
AI.Warning(szMessage)
Parameter
szMessage
Description
The message to write to the log.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists the entity related Lua script bind functions.
Activate
Activates or deactivates the entity.
Activate
ignores the update policy and forces an entity to activate or deactivate. All active entities are updated every frame.
Warning
Having too many active entities can affect performance.
Syntax
Entity.Activate(int bActive)
Parameters
Parameter
bActive
Description
Specify true to make the entity active; false to make it inactive.
ActivateOutput
Syntax
Entity.ActivateOutput()
ActivatePlayerPhysics
Syntax
Version 1.10
863
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.ActivatePlayerPhysics(bool bEnable)
AddConstraint
Syntax
Entity.AddConstraint()
AddImpulse
Apply an impulse to the entity. At least four parameters need to be provided for a linear impulse. For an additional angular impulse, at least seven parameters need to be provided.
Syntax
Entity.AddImpulse(ipart, position, direction, linearImpulse, linearImpulseScale,
angularAxis, angularImpulse, massScale)
Parameters
Parameter
ipart position
Description
The index of the part that receives the impulse.
The point (in world coordinates) where the impulse is applied. Set this to (0, 0, 0) to ignore it.
direction linearImpulse
The direction in which the impulse is applied.
The force of the linear impulse.
linearImpulseScale
Scaling of the linear impulse. (Default: 1.0) angularAxis
The axis on which the angular impulse is applied.
angularImpulse
The force of the angular impulse.
massScale
Mass scaling of the angular impulse. (Default: 1.0)
AttachChild
Syntax
Entity.AttachChild(ScriptHandle childEntityId, int flags)
AttachSurfaceEffect
Syntax
Entity.AttachSurfaceEffect(int nSlot, const char *effect, bool countPerUnit, const char
*form, const char *typ, float countScale, float sizeScale)
AuxAudioProxiesMoveWithEntity
Set whether AuxAudioProxies should move with the entity or not.
Version 1.10
864
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
Entity.AuxAudioProxiesMoveWithEntity(bool const bCanMoveWithEntity)
Returns:
nil
Parameters
Parameter
bCanMoveWithEntity
Description
Boolean parameter to enable or disable
AwakeCharacterPhysics
Syntax
Entity.AwakeCharacterPhysics(int nSlot,const char *sRootBoneName,int nAwake)
AwakeEnvironment
Syntax
Entity.AwakeEnvironment()
AwakePhysics
Syntax
Entity.AwakePhysics(int nAwake)
BreakToPieces
Breaks static geometry in slot 0 into sub objects and spawn them as particles or entities.
Syntax
Entity.BreakToPieces(int nSlot, int nPiecesSlot, float fExplodeImp, Vec3 vHitPt, Vec3
vHitImp, float fLifeTime, bool bSurfaceEffects)
CalcWorldAnglesFromRelativeDir
Syntax
Entity.CalcWorldAnglesFromRelativeDir(Vec3 dir)
CancelSubpipe
Syntax
Entity.CancelSubpipe()
Version 1.10
865
Lumberyard Developer Guide
ScriptBind Engine Functions
ChangeAttachmentMaterial
Syntax
Entity.ChangeAttachmentMaterial(const char *attachmentName, const char *materialName)
CharacterUpdateAlways
Syntax
Entity.CharacterUpdateAlways(int characterSlot, bool updateAlways)
CharacterUpdateOnRender
Syntax
Entity.CharacterUpdateOnRender(int characterSlot, bool bUpdateOnRender)
CheckCollisions
Syntax
Entity.CheckCollisions()
CheckShaderParamCallbacks
Check all the currently set shader param callbacks on the renderproxy with the current state of the entity.
Syntax
Entity.UpdateShaderParamCallback()
CloneMaterial
Replace material on the slot with a cloned version of the material. Cloned material can be freely changed uniquely for this entity.
Syntax
Entity.CloneMaterial(int slot)
Parameters
Parameter
slot sSubMaterialName
Description
ID of the slot on which to clone material.
If this is a non empty string this specific submaterial is cloned.
CopySlotTM
Copies the TM (Transformation Matrix) of the slot.
Version 1.10
866
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
Entity.CopySlotTM(int destSlot, int srcSlot, bool includeTranslation)
Parameters
Parameter
destSlot srcSlot includeTranslation
Description
Destination slot identifier.
Source slot identifier.
True to include the translation, false otherwise.
CountLinks
Counts all outgoing links of the entity.
Syntax
Entity.CountLinks()
Returns:
Number of outgoing links.
CreateAuxAudioProxy
Creates an additional AudioProxy managed by the EntityAudioProxy. The created AuxAudioProxy will move and rotate with the parent EntityAudioProxy.
Syntax
Entity.CreateAuxAudioProxy()
Returns:
Returns the ID of the additionally created AudioProxy.
CreateBoneAttachment
Syntax
Entity.CreateBoneAttachment(int characterSlot, const char *boneName, const char
*attachmentName)
CreateCameraComponent
Create a camera component for the entity. Allows the entity to serve as camera source for material assigned to the entity.
Syntax
Entity.CreateCameraComponent()
CreateDRSProxy
Creates a Dynamic Response System Proxy
Version 1.10
867
(optional) targetId
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
Entity.CreateDRSProxy()
Returns:
Returns the ID of the created proxy.
CreateLink
Creates a new outgoing link for this entity.
Syntax
Entity.CreateLink(const char *name)
Returns:
nothing
Parameters
Parameter
name
Description
Name of the link. Does not have to be unique among all the links of this entity. Multiple links with the same name can coexist.
If specified, the ID of the entity the link shall target. If not specified or 0 then the link will not target anything. Default value: 0
CreateRenderComponent
Create a render component object for the entity. Allows an entity to be rendered immediately without loading any assets.
Syntax
Entity.CreateRenderComponent()
CreateSkinAttachment
Syntax
Entity.CreateSkinAttachment(int characterSlot, const char *attachmentName)
Damage
Syntax
Entity.Damage()
DeleteParticleEmitter
Deletes particles emitter from 3dengine.
Syntax
Version 1.10
868
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.DeleteParticleEmitter(int slot)
Parameters
Parameter
slot
Description
slot number
DeleteThis
Deletes the current entity.
Syntax
Entity.DeleteThis()
DestroyAttachment
Syntax
Entity.DestroyAttachment(int characterSlot, const char *attachmentName)
DestroyPhysics
Syntax
Entity.DestroyPhysics()
DetachAll
Syntax
Entity.DetachAll()
DetachThis
Syntax
Entity.DetachThis()
DisableAnimationEvent
Syntax
Entity.DisableAnimationEvent(int nSlot,const char *sAnimation)
DrawSlot
Enables/Disables drawing of object or character at specified slot of the entity.
Syntax
Version 1.10
869
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.DrawSlot(int nSlot,int nEnable)
Parameters
Parameter
nSlot nEnable
Description
Slot identifier.
1-Enable drawing, 0-Disable drawing.
EnableBoneAnimation
Syntax
Entity.EnableBoneAnimation(int characterSlot, int layer, const char *boneName, bool status)
EnableBoneAnimationAll
Syntax
Entity.EnableBoneAnimationAll(int characterSlot, int layer, bool status)
EnableDecals
Enables decals.
Syntax
Entity.EnableDecals(int slot, bool enable)
EnableInheritXForm
Enables/Disable entity from inheriting transformation from the parent.
Syntax
Entity.EnableInheritXForm(bool bEnable)
EnableMaterialLayer
Syntax
Entity.EnableMaterialLayer(bool enable, int layer)
EnablePhysics
Syntax
Entity.EnablePhysics(bool bEnable)
EnableProceduralFacialAnimation
Syntax
Version 1.10
870
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.EnableProceduralFacialAnimation(bool enable)
ExecuteAudioTrigger
Execute the specified audio trigger and attach it to the entity. The created audio object will move and rotate with the entity.
Syntax
Entity.ExecuteAudioTrigger(ScriptHandle const hTriggerID, ScriptHandle const
hAudioProxyLocalID)
Returns:
nil
Parameters
Parameter
hTriggerID hAudioProxyLocalID
Description
the audio trigger ID handle
The ID of the
AuxAudioProxy
that is local to the
EntityAudioProxy
. To address the default
AuxAudioProxy
, pass
1
. To address all
AuxAudioProxy
instances, pass
0
.
FadeGlobalDensity
Sets the fade global density.
Syntax
Entity.FadeGlobalDensity(int nSlot, float fadeTime, float newGlobalDensity)
Parameters
Parameter
nSlot fadeTime newGlobalDensity
.
.
Description
nSlot identifier.
ForceCharacterUpdate
Syntax
Entity.ForceCharacterUpdate(int characterSlot, bool updateAlways)
ForwardTriggerEventsTo
Syntax
Entity.ForwardTriggerEventsTo(ScriptHandle entityId)
Version 1.10
871
Lumberyard Developer Guide
ScriptBind Engine Functions
FreeAllSlots
Delete all objects on every slot part of the entity.
Syntax
Entity.FreeAllSlots()
FreeSlot
Delete all objects from specified slot.
Syntax
Entity.FreeSlot(int nSlot)
Parameters
Parameter
nSlot
Description
Slot identifier.
GetAIName
Syntax
Entity.GetAIName()
GetAllAuxAudioProxiesID
Returns the ID used to address all AuxAudioProxy of the parent EntityAudioProxy.
Syntax
Entity.GetAllAuxAudioProxiesID()
Returns:
Returns the ID used to address all AuxAudioProxy of the parent EntityAudioProxy.
GetAngles
Gets the angle of the entity.
Syntax
Entity.GetAngles()
GetAnimationLength
Syntax
Entity.GetAnimationLength(int characterSlot, const char *animation)
GetAnimationTime
Syntax
Version 1.10
872
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.GetAnimationTime(int nSlot,int nLayer)
GetArchetype
Retrieve the archetype of the entity.
Syntax
Entity.GetArchetype()
Returns:
name of entity archetype, nil if no archetype.
GetAttachmentBone
Syntax
Entity.GetAttachmentBone(int characterSlot, const char *attachmentName)
GetAttachmentCGF
Syntax
Entity.GetAttachmentCGF(int characterSlot, const char *attachmentName)
GetBoneAngularVelocity
Syntax
Entity.GetBoneAngularVelocity(int characterSlot, const char *boneName)
GetBoneDir
Syntax
Entity.GetBoneDir()
GetBoneLocal
Syntax
Entity.GetBoneLocal(const char *boneName, Vec3 trgDir)
GetBoneNameFromTable
Syntax
Entity.GetBoneNameFromTable()
GetBonePos
Syntax
Entity.GetBonePos()
Version 1.10
873
Lumberyard Developer Guide
ScriptBind Engine Functions
GetBoneVelocity
Syntax
Entity.GetBoneVelocity(int characterSlot, const char *boneName)
GetCenterOfMassPos
Gets the position of the entity center of mass.
Syntax
Entity.GetCenterOfMassPos()
GetCharacter
Gets the character for the specified slot if there is any.
Syntax
Entity.GetCharacter(int nSlot)
GetChild
Syntax
Entity.GetChild(int nIndex)
GetChildCount
Syntax
Entity.GetChildCount()
GetCurAnimation
Syntax
Entity.GetCurAnimation()
GetDefaultAuxAudioProxyID
Returns the ID of the default AudioProxy of the parent EntityAudioProxy.
Syntax
Entity.GetDefaultAuxAudioProxyID()
Returns:
Returns the ID of the default AudioProxy of the parent EntityAudioProxy.
GetDirectionVector
Syntax
Version 1.10
874
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.GetDirectionVector()
GetDistance
Syntax
float Entity.GetDistance(entityId)
Returns:
The distance from entity specified with entityId/
GetEntitiesInContact
Syntax
Entity.GetEntitiesInContact()
GetEntityMaterial
Syntax
Entity.GetEntityMaterial()
GetExplosionImpulse
Syntax
Entity.GetExplosionImpulse()
GetExplosionObstruction
Syntax
Entity.GetExplosionObstruction()
GetFlags
Syntax
Entity.GetFlags()
GetFlagsExtended
Syntax
Entity.GetFlagsExtended()
GetGeomCachePrecachedTime
Gets time delta from current playback position to last ready to play frame.
Syntax
Version 1.10
875
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.GetGeomCachePrecachedTime()
GetGravity
Syntax
Entity.GetGravity()
GetHelperAngles
Syntax
Entity.GetHelperAngles()
GetHelperDir
Syntax
Entity.GetHelperDir()
GetHelperPos
Syntax
Entity.GetHelperPos()
GetLink
Returns the link at given index.
Syntax
Entity.GetLink()
Returns:
The script table of the entity that the i'th link is targeting or nil if the specified index is out of bounds.
Parameters
Parameter
ith
Description
The index of the link that shall be returned.
GetLinkName
Returns the name of the link that is targeting the entity with given ID.
Syntax
Entity.GetLinkName(ScriptHandle targetId)
Returns:
The name of the i'th link targeting given entity or nil if no such link exists.
Version 1.10
876
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameters
Parameter
targetId
(optional) ith
Description
ID of the entity for which the link name shall be looked up.
If specified, the i'th link that targets given entity.
Default value: 0 (first entity)
GetLinkTarget
Returns the ID of the entity that given link is targeting.
Syntax
Entity.GetLinkTarget(const char *name)
Returns:
The ID of the entity that the link is targeting or nil if no such link exists.
Parameters
Parameter
name
(optional) ith
Description
Name of the link.
If specified, the i'th link with given name for which to look up the targeted entity. Default value: 0
(first link with given name)
GetLocalAngles
Syntax
Vec3 Entity.GetLocalAngles(vAngles)
GetLocalBBox
Syntax
Entity.GetLocalBBox()
GetLocalPos
Syntax
Vec3 Entity.GetLocalPos()
GetLocalScale
Syntax
float Entity.GetLocalScale()
Version 1.10
877
Lumberyard Developer Guide
ScriptBind Engine Functions
GetLodRatio
Syntax
Entity.GetLodRatio()
GetMass
Syntax
Entity.GetMass()
GetMaterial
Syntax
Entity.GetMaterial()
GetMaterialFloat
Change material parameter.
Syntax
Entity.GetMaterialFloat(int slot,int nSubMtlId,const char *sParamName)
Returns:
Material parameter value.
Parameters
Parameter
slot nSubMtlId sParamName
Description
ID of the slot on which slot to change material.
Specify submaterial by Id.
Name of the material parameter.
GetMaterialVec3
Syntax
Entity.GetMaterialVec3(int slot,int nSubMtlId,const char *sParamName)
GetName
Syntax
Entity.GetName()
GetParent
Syntax
Version 1.10
878
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.GetParent()
GetParentSlot
Syntax
Entity.GetParentSlot(int child)
GetPhysicalStats
Some more physics related.
Syntax
Entity.GetPhysicalStats()
GetPos
Gets the position of the entity.
Syntax
Entity.GetPos()
GetProjectedWorldBBox
Syntax
Entity.GetProjectedWorldBBox()
GetRawId
Returns entityId in raw numeric format.
Syntax
Entity.GetRawId()
GetScale
Gets the scaling value for the entity.
Syntax
Entity.GetScale()
GetSlotAngles
Gets the slot angles.
Syntax
Entity.GetSlotAngles(int nSlot)
Version 1.10
879
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameters
Parameter
nSlot
Description
nSlot identifier.
GetSlotCount
Gets the count of the slots.
Syntax
Entity.GetSlotCount()
GetSlotHelperPos
Syntax
Entity.GetSlotHelperPos(int slot, const char *helperName, bool objectSpace)
GetSlotPos
Gets the slot position.
Syntax
Entity.GetSlotPos(int nSlot)
Parameters
Parameter
nSlot
Description
nSlot identifier.
GetSlotScale
Gets the slot scale amount.
Syntax
Entity.GetSlotScale(int nSlot)
Parameters
Parameter
nSlot
GetSlotWorldDir
Gets the World direction of the slot.
Syntax
Description
nSlot identifier.
Version 1.10
880
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.GetSlotWorldDir(int nSlot)
Parameters
Parameter
nSlot
GetSlotWorldPos
Gets the World position of the slot.
Syntax
Entity.GetSlotWorldPos(int nSlot)
Parameters
Parameter
nSlot
Description
Slot identifier.
Description
Slot identifier.
GetSpeed
Syntax
Entity.GetSpeed()
GetState
Syntax
Entity.GetState()
GetSubmergedVolume
Syntax
Entity.GetSubmergedVolume(int slot, Vec3 planeNormal, Vec3 planeOrigin)
GetTimeOfDayHour
Syntax
Entity.GetTimeOfDayHour()
Returns:
current time of day as a float value.
GetTimeSinceLastSeen
Syntax
Version 1.10
881
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.GetTimeSinceLastSeen()
GetTouchedPoint
Retrieves point of collision for rigid body.
Syntax
Entity.GetTouchedPoint()
GetTouchedSurfaceID
Syntax
Entity.GetTouchedSurfaceID()
GetTriggerBBox
Syntax
Entity.GetTriggerBBox()
GetUpdateRadius
Syntax
Entity.GetUpdateRadius()
GetVelocity
Syntax
Entity.GetVelocity()
GetVelocityEx
Syntax
Entity.GetVelocityEx()
GetViewDistanceMultiplier
Get the view distance multiplier.
Syntax
Entity.GetViewDistanceMultiplier()
GetVolume
Syntax
Entity.GetVolume(int slot)
Version 1.10
882
Lumberyard Developer Guide
ScriptBind Engine Functions
GetWorldAngles
Syntax
Vec3 Entity.GetWorldAngles(vAngles)
GetWorldBBox
Syntax
Entity.GetWorldBBox()
GetWorldBoundsCenter
Gets the world bbox center for the entity (defaults to entity position if no bbox present).
Syntax
Entity.GetWorldBoundsCenter()
GetWorldDir
Syntax
Vec3 Entity.GetWorldDir()
GetWorldPos
Syntax
Vec3 Entity.GetWorldPos()
GetWorldScale
Syntax
float Entity.GetWorldScale()
GotoState
Syntax
Entity.GotoState(const char *sState)
HasFlags
Syntax
Entity.HasFlags(int flags)
HasFlagsExtended
Syntax
Version 1.10
883
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.HasFlagsExtended(int flags)
Hide
Syntax
Entity.Hide()
HideAllAttachments
Syntax
Entity.HideAllAttachments(int characterSlot, bool hide, bool hideShadow)
HideAttachment
Syntax
Entity.HideAttachment(int characterSlot, const char *attachmentName, bool hide, bool
hideShadow)
HideAttachmentMaster
Syntax
Entity.HideAttachmentMaster(int characterSlot, bool hide)
IgnorePhysicsUpdatesOnSlot
Ignore physics when updating the position of a slot.
Syntax
Entity.IgnorePhysicsUpdatesOnSlot(int nSlot)
Parameters
Parameter
nSlot
Description
Slot identifier.
InsertSubpipe
Syntax
Entity.InsertSubpipe()
IntersectRay
Syntax
Entity.IntersectRay(int slot, Vec3 rayOrigin, Vec3 rayDir, float maxDistance)
Version 1.10
884
Lumberyard Developer Guide
ScriptBind Engine Functions
InvalidateTrigger
Syntax
Entity.InvalidateTrigger()
IsActive
Retrieve active status of entity.
Syntax
Entity.IsActive(bActivate)
Returns:
true - Entity is active. false - Entity is not active.
IsAnimationRunning
Syntax
Entity.IsAnimationRunning(int characterSlot, int layer)
Returns:
nil or not nil
Parameters
Parameter
characterSlot layer
Description
Index of the character slot.
Index of the animation layer.
IsColliding
Syntax
Entity.IsColliding()
IsEntityInside
Syntax
float Entity.IsEntityInside(entityId)
IsEntityInsideArea
Syntax
Entity.IsEntityInsideArea(int areaId, ScriptHandle entityId)
IsFromPool
Returns if the entity came from an entity pool.
Version 1.10
885
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
Entity.IsFromPool()
Returns:
true - Entity is from a pool. (Bookmarked) false - Entity is not from a pool. (Not bookmarked)
IsGeomCacheStreaming
Syntax
Entity.IsGeomCacheStreaming()
Returns:
true if geom cache is streaming.
IsHidden
Syntax
Entity.IsHidden()
IsInState
Syntax
Entity.IsInState(const char *sState)
IsPointInsideArea
Syntax
Entity.IsPointInsideArea(int areaId, Vec3 point)
IsSlotCharacter
Checks if the slot is a character.
Syntax
Entity.IsSlotCharacter(int slot)
Parameters
Parameter
slot
Description
Slot identifier.
IsSlotGeometry
Checks if the slot is a geometry.
Syntax
Entity.IsSlotGeometry(int slot)
Version 1.10
886
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameters
Parameter
slot
IsSlotLight
Checks if the slot is a light.
Syntax
Entity.IsSlotLight(int slot)
Parameters
Parameter
slot
Description
Slot identifier.
Description
Slot identifier.
IsSlotParticleEmitter
Checks if the slot is a particle emitter.
Syntax
Entity.IsSlotParticleEmitter(int slot)
Parameters
Parameter
slot
IsSlotValid
Checks if the slot is valid.
Syntax
Entity.IsSlotValid(int nSlot)
Parameters
Parameter
nSlot
IsUsingPipe
Syntax
Entity.IsUsingPipe()
Version 1.10
887
Description
Slot identifier.
Description
Slot identifier.
Lumberyard Developer Guide
ScriptBind Engine Functions
Returns:
True if the entity is running a goalpipe or has it inserted; otherwise, false.
KillTimer
Syntax
Entity.KillTimer()
LoadCharacter
Load CGF geometry into the entity slot.
Syntax
Entity.LoadCharacter(int nSlot,const char *sFilename)
Parameters
Parameter
nSlot sFilename
Description
Slot identifier.
CGF geometry file name.
LoadCloud
Loads the cloud XML file into the entity slot.
Syntax
Entity.LoadCloud(int nSlot, const char *sFilename)
Parameters
Parameter
nSlot sFilename
Description
Slot identifier.
Filename.
LoadFogVolume
Loads the fog volume XML file into the entity slot.
Syntax
Entity.LoadFogVolume(int nSlot, SmartScriptTable table)
Parameters
Parameter
nSlot table
Description
Slot identifier.
Table with fog volume properties.
Version 1.10
888
Lumberyard Developer Guide
ScriptBind Engine Functions
LoadGeomCache
Load geom cache into the entity slot.
Syntax
Entity.LoadGeomCache(int nSlot,const char *sFilename)
Parameters
Parameter
nSlot sFilename
Description
Slot identifier.
CAX file name.
LoadLight
Load CGF geometry into the entity slot.
Syntax
Entity.LoadLight(int nSlot,SmartScriptTable table)
Parameters
Parameter
nSlot table
Description
Slot identifier.
Table with all the light information.
LoadObject
Load CGF geometry into the entity slot.
Syntax
Entity.LoadObject(int nSlot,const char *sFilename)
Parameters
Parameter
nSlot sFilename
Description
Slot identifier.
CGF geometry file name.
LoadObjectLattice
Load lattice into the entity slot.
Syntax
Version 1.10
889
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.LoadObjectLattice(int nSlot)
LoadObjectWithFlags
Load CGF geometry into the entity slot.
Syntax
Entity.LoadObjectWithFlags(int nSlot,const char *sFilename, const int nFlags)
Parameters
Parameter
nSlot sFilename nFlags
Description
Slot identifier.
CGF geometry file name.
entity load flags
LoadParticleEffect
Loads CGF geometry into the entity slot.
Syntax
Entity.LoadParticleEffect(int nSlot, const char *sEffectName, SmartScriptTable table)
Parameters
Parameter
nSlot sEffectName
(optional) bPrime
(optional) fPulsePeriod
(optional) fScale
(optional) fCountScale
(optional) bScalePerUnit
(optional) bCountPerUnit
(optional) sAttachType
(optional) sAttachForm
Description
Slot identifier.
Name of the particle effect (Ex: "explosions/ rocket").
Whether effect starts fully primed to equilibrium state.
Time period between particle effect restarts.
Size scale to apply to particles
Count multiplier to apply to particles
Scale size by attachment extent
Scale count by attachment extent string for EGeomType string for EGeomForm
LoadSubObject
Load geometry of one CGF node into the entity slot.
Version 1.10
890
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
Entity.LoadSubObject(int nSlot,const char *sFilename,const char *sGeomName)
Parameters
Parameter
nSlot sFilename sGeomName
Description
Slot identifier.
CGF geometry file name.
Name of the node inside CGF geometry.
LoadVolumeObject
Loads volume object.
Syntax
Entity.LoadVolumeObject(int nSlot, const char* sFilename)
Parameters
Parameter
nSlot sFilename
Description
Slot identifier.
File name of the volume object.
LookAt
Orient the entity to look at a world space position.
Syntax
Entity.LookAt(Vec3 target, Vec3 axis, float angle)
Parameters
Parameter
target axis angle
Description
The position to look at.
The correction axis. The quat type is not supported.
The correction angle inradians. The quat type is not supported.
MultiplyWithSlotTM
Multiplies with the TM (Transformation Matrix) of the slot.
Syntax
Version 1.10
891
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.MultiplyWithSlotTM(int slot, Vec3 pos)
Parameters
Parameter
slot pos
Description
Slot identifier.
Position vector.
NetPresent
Syntax
Entity.NetPresent()
NoBulletForce
Syntax
Entity.NoBulletForce(bool state)
NoExplosionCollision
Syntax
Entity.NoExplosionCollision()
PassParamsToPipe
Syntax
Entity.PassParamsToPipe()
Physicalize
Create physical entity from the specified entity slot.
Syntax
Entity.Physicalize(int nSlot,int nPhysicsType,SmartScriptTable physicsParams)
Parameters
Parameter
nSlot nPhysicsType
Description
Slot identifier of the entity to physicalize. Specify -1 to use geometries from all slots.
Type of physical entity to create. For possible values, see the
nPhysicsType Keys
table later in this section.
Version 1.10
892
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
physicsParams
Description
Table with physicalization parameters. For more information, see the
physicsParams Table Keys
table later in this section.
nPhysicsType Keys
Physics Type
PE_AREA
PE_ARTICULATED
PE_LIVING
Meaning
Physical Area (Sphere,Box,Geometry or Shape).
Ragdolls or other articulated physical entities that consist of rigid bodies connected by joints.
Live physical entity that can move through the physical world and interact with it.
No physics.
PE_NONE
PE_PARTICLE
PE_RIGID
PE_ROPE
PE_SOFT
A physical particle entity that it has only mass and radius.
Rigid body physical entity. Can have infinite mass (specified by setting mass to 0).
A physical representation of a rope. The rope can hang freely or connect two physical entities.
A system of non-rigidly connected vertices that can interact with the environment. Used for soft body physics like cloth simulation.
PE_STATIC
A static, immovable physical entity.
PE_WHEELEDVEHICLE
Physical vehicle with wheels.
Note
For more information about physical entity types, see
.
physicsParams Table Keys
Physics
Parameter
Description
area density
This table must be set when Physics Type is
PE_AREA
. For more information, see the
Area
Table Keys
table later in this section.
Object density, only used if mass is not specified or -1.
Physical entity flags.
flags living mass particle
This table must be set when Physics Type is
PE_LIVING
. For more information, see the
Living Table Keys
table later in this section.
Object mass, only used if density is not specified or -1.
This table must be set when Physics Type is
PE_PARTICLE
. For more information, see the
Particle Table Keys
table later in this section.
partid
Index of the articulated body part to which the new physical entity will be attached.
Scale of character joint stiffness (multiplied with stiffness values specified from the exported model)
Version 1.10
893
Lumberyard Developer Guide
ScriptBind Engine Functions
Particle Table Keys
Particle Parameter Description
accel_lift
Acceleration that lifts particle with the current speed accel_thrust
Acceleration along direction of movement air_resistance gravity
The air resistance coefficient, F = kv constant_orientation
(0,1) Keep constant orientation
Gravity force vector to the air mass min_bounce_vel no_path_alignment no_roll
Particle mass
Minimal velocity at which particle bounces off the surface
(0,1) Do not align particle orientation to the movement path
(0,1) Do not roll particle on terrain no_spin radius single_contact
(0,1) Do not spin particle in air
Particle pseudo radius
(0,1) Calculate only one first contact thickness velocity water_gravity
Thickness when lying on a surface (if 0, the radius is used)
Velocity direction and magnitude vector
Gravity force vector when in the water.
water_resistance
Water resistance coefficient, F = kv
Living Table Keys
Living
Parameter
Description
air_resistance gravity head_radius height height_eye height_head height_pivot inertia mass max_climb_angle max_jump_angle
Air control coefficient 0..1, 1 - special value (total control of movement)
Vertical gravity magnitude
Radius of the head
Vertical offset of collision geometry center
Vertical offset of the camera
Vertical offset of the head
Offset from central ground position that is considered the entity center
Inertia coefficient, the greater the value, the less the inertia; 0 means no inertia.
Mass of the player (in kg)
Player cannot climb surface which slope is steeper than this angle (in radians)
Player is not allowed to jump towards ground if this angle is exceeded (in radians)
Version 1.10
894
Lumberyard Developer Guide
ScriptBind Engine Functions
Living
Parameter
Description
max_vel_ground min_fall_angle min_slide_angle size
Player cannot stand on surfaces that are moving faster than this (in radians)
Player starts falling when slope is steeper than this (in radians)
If surface slope is more than this angle, player starts sliding (in radians)
Collision cylinder dimensions vector (x,y,z).
Area Table Keys
Area
Parameter
box_max box_min falloff gravity height points
Description
radius type uniform
Max vector of bounding box, must be specified if type is
AREA_BOX
Min vector of bounding box, must be specified if type is
AREA_BOX
Ellipsoidal falloff dimensions; 0,0,0 specifies no falloff
Gravity vector inside the physical area
Height of the 2D area (
AREA_SHAPE
), relative to the minimal Z in the points table
A table that contains an indexed collection of vectors in local entity space that define the 2D shape of the area (
AREA_SHAPE
)
Radius of the area sphere; must be specified if type is AREA_SPHERE.
Type of the area, valid values are:
AREA_SPHERE
,
AREA_BOX
,
AREA_GEOMETRY
, or
AREA_SHAPE
Same direction in every point, or always point to the center.
PhysicalizeAttachment
Syntax
Entity.PhysicalizeAttachment(int characterSlot, const char* attachmentName, bool
physicalize)
PhysicalizeSlot
Syntax
Entity.PhysicalizeSlot(int slot, SmartScriptTable physicsParams)
PlayFacialAnimation
Syntax
Entity.PlayFacialAnimation(char* name, bool looping)
Version 1.10
895
Lumberyard Developer Guide
ScriptBind Engine Functions
PreLoadParticleEffect
Pre-loads a particle effect.
Syntax
Entity.PreLoadParticleEffect(const char *sEffectName)
Parameters
Parameter
sEffectName
Description
Name of the particle effect (Ex: "explosions/ rocket").
ProcessBroadcastEvent
Syntax
Entity.ProcessBroadcastEvent()
RagDollize
Syntax
Entity.RagDollize(int slot)
ReattachSoftEntityVtx
Syntax
Entity.ReattachSoftEntityVtx(ScriptHandle entityId, int partId)
RedirectAnimationToLayer0
Syntax
Entity.RedirectAnimationToLayer0(int characterSlot, bool redirect)
RegisterForAreaEvents
Registers the script proxy so that it receives area events for this entity.
Syntax
Entity.RegisterForAreaEvents(int enable)
Parameters
Parameter
enable
Description
Specify 0 to disable, or any other value to enable.
Version 1.10
896
Lumberyard Developer Guide
ScriptBind Engine Functions
RemoveAllLinks
Removes all links of an entity.
Syntax
Entity.RemoveAllLinks()
Returns:
nothing
RemoveAuxAudioProxy
Removes the
AuxAudioProxy
corresponding to the passed ID from the parent
EntityAudioProxy
.
Syntax
Entity.RemoveAuxAudioProxy(ScriptHandle const hAudioProxyLocalID)
Returns:
nil
Parameters
Parameter
hAudioProxyLocalID
Description
The ID of the
AuxAudioProxy
to be removed from the parent
EntityAudioProxy
.
RemoveDecals
Syntax
Entity.RemoveDecals()
RemoveLink
Removes an outgoing link from the entity.
Syntax
Entity.RemoveLink(const char *name)
Returns:
nothing
Parameters
Parameter
name
(optional) ith
Description
Name of the link to remove.
If specified, the
<i>
th link with the name specified that will be removed. Default value: 0 (first link with given name)
RenderAlways
Enables 'always render' on the render node, skipping any kind of culling.
Version 1.10
897
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
Entity.RenderAlways(int enable)
Parameters
Parameter
enable
Description
Specify 0 to disable, or any other value to enable.
RenderShadow
Syntax
Entity.RenderShadow()
ReplaceMaterial
Syntax
Entity.ReplaceMaterial(int slot, const char *name, const char *replacement)
ResetAnimation
Syntax
Entity.ResetAnimation(int characterSlot, int layer)
ResetAttachment
Syntax
Entity.ResetAttachment(int characterSlot, const char *attachmentName)
ResetMaterial
Syntax
Entity.ResetMaterial(int slot)
ResetPhysics
Syntax
Entity.ResetPhysics()
SelectPipe
Syntax
Entity.SelectPipe()
Version 1.10
898
Lumberyard Developer Guide
ScriptBind Engine Functions
SetAIName
Syntax
Entity.SetAIName()
SetAngles
Sets the angle of the entity.
Syntax
Entity.SetAngles(Ang3 vAngles)
Parameters
Parameter
vAngles
Description
Angle vector.
SetAnimateOffScreenShadow
Syntax
Entity.SetAnimateOffScreenShadow(bool bAnimateOffScreenShadow)
SetAnimationBlendOut
Syntax
Entity.SetAnimationBlendOut(int characterSlot, int layer, float blendOut)
SetAnimationEvent
Syntax
Entity.SetAnimationEvent(int nSlot,const char *sAnimation)
SetAnimationFlip
Syntax
Entity.SetAnimationFlip(int characterSlot, Vec3 flip)
SetAnimationKeyEvent
Syntax
Entity.SetAnimationKeyEvent(nSlot, sAnimation, nFrameID, sEvent)
Version 1.10
899
Lumberyard Developer Guide
ScriptBind Engine Functions
SetAnimationSpeed
Syntax
Entity.SetAnimationSpeed(int characterSlot, int layer, float speed)
SetAnimationTime
Syntax
Entity.SetAnimationTime(int nSlot,int nLayer,float fTime)
SetAttachmentAngles
Syntax
Entity.SetAttachmentAngles(int characterSlot, const char *attachmentName, Vec3 angles)
SetAttachmentCGF
Syntax
Entity.SetAttachmentCGF(int characterSlot, const char *attachmentName, const char*
filePath)
SetAttachmentDir
Syntax
Entity.SetAttachmentDir(int characterSlot, const char *attachmentName, Vec3 dir, bool
worldSpace)
SetAttachmentEffect
Syntax
Entity.SetAttachmentEffect(int characterSlot, const char *attachmentName, const char
*effectName, Vec3 offset, Vec3 dir, float scale, int flags)
SetAttachmentLight
Syntax
Entity.SetAttachmentLight(int characterSlot, const char *attachmentName, SmartScriptTable
lightTable, int flags)
SetAttachmentObject
Syntax
Entity.SetAttachmentObject(int characterSlot, const char *attachmentName, ScriptHandle
entityId, int slot, int flags)
Version 1.10
900
Lumberyard Developer Guide
ScriptBind Engine Functions
SetAttachmentPos
Syntax
Entity.SetAttachmentPos(int characterSlot, const char *attachmentName, Vec3 pos)
SetAudioEnvironmentID
Sets the ID of the audio environment that an entity will specify for the entities that it contains.
Syntax
Entity.SetAudioEnvironmentID(ScriptHandle const hAudioEnvironmentID)
Returns:
nil
Parameters
Parameter
hAudioEnvironmentID
Description
audio environment ID
SetAudioObstructionCalcType
Set the Audio Obstruction/Occlusion calculation type on the underlying
GameAudioObject
.
Syntax
Entity.SetAudioObstructionCalcType(int const nObstructionCalcType, ScriptHandle const
hAudioProxyLocalID)
Returns:
nil
Parameters
Parameter
nObstructionCalcType hAudioProxyLocalID
Description
Obstruction/Occlusion calculation type; Possible values: 0 - ignore Obstruction/Occlusion 1 - use single physics ray 2 - use multiple physics rays
(currently 5 per object)
The ID of the
AuxAudioProxy
that is local to the
EntityAudioProxy
. To address the default
AuxAudioProxy
, pass
1
. To address all
AuxAudioProxy
instances, pass
0
.
SetAudioProxyOffset
Set offset on the audio proxy attached to the entity.
Syntax
Entity.SetAudioProxyOffset(Vec3 const vOffset, ScriptHandle const hAudioProxyLocalID)
Version 1.10
901
Lumberyard Developer Guide
ScriptBind Engine Functions
Returns:
nil
Parameters
Parameter
vOffset hAudioProxyLocalID
Description
The offset vector
The ID of the
AuxAudioProxy
that is local to the
EntityAudioProxy
. To address the default
AuxAudioProxy
, pass
1
. To address all
AuxAudioProxy
instances, pass
0
.
SetAudioRtpcValue
Set the specified audio RTPC to the specified value on the current entity.
Syntax
Entity.SetAudioRtpcValue(ScriptHandle const hRtpcID, float const fValue, ScriptHandle const
hAudioProxyLocalID)
Returns:
nil
Parameters
Parameter
hRtpcID fValue hAudioProxyLocalID
Description
The audio RTPC ID handle
The RTPC value
The ID of the
AuxAudioProxy
that is local to the
EntityAudioProxy
. To address the default
AuxAudioProxy
, pass
1
. To address all
AuxAudioProxy
instances, pass
0
.
SetAudioSwitchState
Set the specified audio switch to the specified state on the current Entity.
Syntax
Entity.SetAudioSwitchState(ScriptHandle const hSwitchID, ScriptHandle const hSwitchStateID,
ScriptHandle const hAudioProxyLocalID)
Returns:
nil
Parameters
Parameter
hSwitchID hSwitchStateID
Description
The audio switch ID handle
The switch state ID handle
Version 1.10
902
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
hAudioProxyLocalID
Description
The ID of the
AuxAudioProxy
that is local to the
EntityAudioProxy
. To address the default
AuxAudioProxy
, pass
1
. To address all
AuxAudioProxy
instances, pass
0
.
SetCharacterPhysicParams
Syntax
Entity.SetCharacterPhysicParams()
SetCloudMovementProperties
Sets the cloud movement properties.
Syntax
Entity.SetCloudMovementProperties(int nSlot, SmartScriptTable table)
Parameters
Parameter
nSlot table
Description
Slot identifier.
Table property for the cloud movement.
SetColliderMode
Syntax
Entity.SetColliderMode(int mode)
SetCurrentAudioEnvironments
Sets the correct audio environment amounts based on the entity's position in the world.
Syntax
Entity.SetCurrentAudioEnvironments()
Returns:
nil
SetDefaultIdleAnimations
Syntax
Entity.SetDefaultIdleAnimations()
SetDirectionVector
Syntax
Version 1.10
903
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.SetDirectionVector(Vec3 dir)
SetEnvironmentFadeDistance
Sets the distance over which this entity fades the audio environment for all approaching entities.
Syntax
Entity.SetEnvironmentFadeDistance(float const fEnvironmentFadeDistance)
Returns:
nil
Parameters
Parameter
fEnvironmentFadeDistance
Description
The fade distance in meters.
SetFadeDistance
Sets the distance at which this entity executes fade calculations.
Syntax
Entity.SetFadeDistance(float const fFadeDistance)
Returns:
nil
Parameters
Parameter
fFadeDistance
Description
The fade distance in meters.
SetFlags
Mode: 0: or 1: and 2: xor
Syntax
Entity.SetFlags(int flags, int mode)
SetFlagsExtended
Mode: 0: or 1: and 2: xor
Syntax
Entity.SetFlagsExtended(int flags, int mode)
SetGeomCacheDrawing
Activates or deactivates geom cache drawing.
Version 1.10
904
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
Entity.SetGeomCacheDrawing(bool active)
SetGeomCacheParams
Sets geometry cache parameters.
Syntax
Entity.SetGeomCacheParams(bool looping, const char *standIn, const char *standInMaterial,
const char *firstFrameStandIn, const char* firstFrameStandInMaterial, const char*
lastFrameStandIn, const char* lastFrameStandInMaterial, float standInDistance, float
streamInDistance)
SetGeomCachePlaybackTime
Sets the playback time.
Syntax
Entity.SetGeomCachePlaybackTime(float time)
SetGeomCacheStreaming
Activates/deactivates geom cache streaming.
Syntax
Entity.SetGeomCacheStreaming(bool active, float time)
SetLightColorParams changes the color related params of an existing light.
Syntax
Entity.SetLightColorParams(int nSlot, Vec3 color, float specular_multiplier)
SetLinkTarget
Specifies the entity that an existing link shall target. Use this function to change the target of an existing link.
Syntax
Entity.SetLinkTarget(const char *name, ScriptHandle targetId)
Returns:
nothing
Parameters
Parameter
name
Description
Name of the link that shall target given entity.
Version 1.10
905
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
targetId
(optional) ith
Description
The ID of the entity the link shall target. Pass in
NULL_ENTITY to make the link no longer target an entity.
If specified, the
<i>
th link with given name that targets the specified entity. Default value: 0 (first link with given name)
SetLocalAngles
Syntax
Entity.SetLocalAngles(Ang3 vAngles)
SetLocalBBox
Syntax
Entity.SetLocalBBox(Vec3 vMin,Vec3 vMax)
SetLocalPos
Syntax
Entity.SetLocalPos(Vec3 vPos)
SetLocalScale
Syntax
Entity.SetLocalScale(float fScale)
SetLodRatio
Syntax
Entity.SetLodRatio()
SetMaterial
Syntax
Entity.SetMaterial()
SetMaterialFloat
Change material parameter.
Syntax
Entity.SetMaterialFloat(int slot,int nSubMtlId,const char *sParamName,float fValue)
Version 1.10
906
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameters
Parameter
slot nSubMtlId sParamName fValue
Description
ID of the slot on which to change material.
Specify sub-material by ID.
Name of the material parameter.
New material parameter value.
SetMaterialVec3
Syntax
Entity.SetMaterialVec3(int slot,int nSubMtlId,const char *sParamName,Vec3 fValue)
SetName
Syntax
Entity.SetName()
SetParentSlot
Syntax
Entity.SetParentSlot(int child, int parent)
SetPhysicParams
Syntax
Entity.SetPhysicParams()
SetPos
Sets the position of the entity.
Syntax
Entity.SetPos(Vec3 vPos)
Parameters
Parameter
vPos
Description
Position vector.
SetPublicParam
Sets a shader parameter.
Version 1.10
907
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
Entity.SetPublicParam()
Parameters
Parameter
paramName value
SetRegisterInSectors
Syntax
Entity.SetRegisterInSectors()
SetScale
Sets the scaling value for the entity.
Syntax
Entity.SetScale(float fScale)
Parameters
Parameter
fScale
Description
The name of the shader parameter.
The new value of the parameter.
Description
The scale amount.
SetScriptUpdateRate
Syntax
Entity.SetScriptUpdateRate(int nMillis)
SetSelfAsLightCasterException
Makes the entity render node a caster exception for the light loaded in nLightSlot
.
Syntax
Entity.SetSelfAsLightCasterException(int nLightSlot)
Parameters
Parameter
nLightSlot
Description
Slot where the light is loaded.
Version 1.10
908
Lumberyard Developer Guide
ScriptBind Engine Functions
SetSlotAngles
Sets the slot angles.
Syntax
Entity.SetSlotAngles(int nSlot, Ang3 v)
Parameters
Parameter
nSlot v
Description
nSlot identifier.
Angle to be set.
SetSlotHud3D
Setup flags for use as 3D HUD entity.
Syntax
Entity.SetSlotHud3D(int nSlot)
Parameters
Parameter
nSlot
SetSlotPos
Sets the slot position.
Syntax
Entity.SetSlotPos(int slot,Vec3 v)
Parameters
Parameter
slot v
Description
Slot identifier.
Description
slot identifier.
Position to be set.
SetSlotPosAndDir
Sets the slot position and direction.
Syntax
Entity.SetSlotPosAndDir(int nSlot, Vec3 pos, Vec3 dir)
Version 1.10
909
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameters
Parameter
nSlot pos dir
Description
nSlot identifier.
Position to be set.
Direction to be set.
SetSlotScale
Sets the slot scale amount.
Syntax
Entity.SetSlotScale(int nSlot,float fScale)
Parameters
Parameter
nSlot fScale
Description
Slot identifier.
Scale amount for the slot.
SetSlotWorldTM
Sets the World TM (transformation matrix) of the slot.
Syntax
Entity.SetSlotWorldTM(int nSlot, Vec3 pos, Vec3 dir)
Parameters
Parameter
nSlot pos dir
Description
Slot identifier.
Position vector.
Direction vector.
SetStateClientside
Syntax
Entity.SetStateClientside()
SetTimer
Syntax
Version 1.10
910
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.SetTimer()
SetTriggerBBox
Syntax
Entity.SetTriggerBBox(Vec3 vMin,Vec3 vMax)
SetUpdatePolicy
Changes the update policy for the entity. Update policy controls when an entity becomes active or inactive (for example, when visible or when in close proximity).
Note
Because all active entities are updated every frame, having too many active entities can affect performance.
Syntax
Entity.SetUpdatePolicy(int nUpdatePolicy)
Parameters
Parameter
nUpdatePolicy
Description
Update policy constant. See the following table for possible values.
nUpdatePolicy Possible Values
Update Policy
ENTITY_UPDATE_NEVER
Meaning
Never update this entity.
ENTITY_UPDATE_IN_RANGE
Activate entity when in specified radius.
ENTITY_UPDATE_POT_VISIBLE
Activate entity when potentially visible.
ENTITY_UPDATE_VISIBLE
Activate entity when visible in frustum.
ENTITY_UPDATE_PHYSICS
Activate entity when physics awakes, deactivate when physics go to sleep.
ENTITY_UPDATE_ALWAYS
Entity is always active and updated every frame.
Note
For update policies that require a radius, use SetUpdateRadius (p. 911)
.
SetUpdateRadius
Syntax
Entity.SetUpdateRadius()
Version 1.10
911
Lumberyard Developer Guide
ScriptBind Engine Functions
SetVelocity
Syntax
Entity.SetVelocity(Vec3 velocity)
SetVelocityEx
Syntax
Entity.SetVelocityEx(Vec3 velocity, Vec3 angularVelocity)
SetViewDistanceMultiplier
Set the view distance multiplier.
Syntax
Entity.SetViewDistanceMultiplier()
SetViewDistUnlimited
Syntax
Entity.SetViewDistUnlimited()
SetVolumeObjectMovementProperties
Sets the properties of the volume object movement.
Syntax
Entity.SetVolumeObjectMovementProperties(int nSlot, SmartScriptTable table)
Parameters
Parameter
nSlot table
Description
Slot identifier.
Table with volume object properties.
SetWorldAngles
Syntax
Entity.SetWorldAngles(Ang3 vAngles)
SetWorldPos
Syntax
Version 1.10
912
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.SetWorldPos(Vec3 vPos)
SetWorldScale
Syntax
Entity.SetWorldScale(float fScale)
StartAnimation
Syntax
Entity.StartAnimation()
StopAnimation
Syntax
Entity.StopAnimation(int characterSlot, int layer)
StopAudioTrigger
Stop the audio event generated by the trigger with the specified ID on this entity.
Syntax
Entity.StopAudioTrigger(ScriptHandle const hTriggerID, ScriptHandle const
hAudioProxyLocalID)
Returns:
nil
Parameters
Parameter
hTriggerID hAudioProxyLocalID
Description
The audio trigger ID handle
The ID of the
AuxAudioProxy
that is local to the
EntityAudioProxy
. To address the default
AuxAudioProxy
, pass
1
. To address all
AuxAudioProxy
instances, pass
0
.
ToGlobal
Syntax
Entity.ToGlobal(int slotId, Vec3 point)
ToLocal
Syntax
Version 1.10
913
Lumberyard Developer Guide
ScriptBind Engine Functions
Entity.ToLocal(int slotId, Vec3 point)
TriggerEvent
Syntax
Entity.TriggerEvent()
UnSeenFrames
Syntax
Entity.UnSeenFrames()
UpdateAreas
Syntax
Entity.UpdateAreas()
UpdateLightClipBounds
Update the clip bounds of the light from the linked entities.
Syntax
Entity.UpdateLightClipBounds(int nSlot)
Parameters
Parameter
nSlot
Description
Slot identifier.
UpdateSlotPhysics
Syntax
Entity.UpdateSlotPhysics(int slot)
VectorToGlobal
Syntax
Entity.VectorToGlobal(int slotId, Vec3 dir)
VectorToLocal
Syntax
Entity.VectorToLocal(int slotId, Vec3 dir)
Version 1.10
914
Lumberyard Developer Guide
ScriptBind Engine Functions
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ movie functions that can be called from Lua scripts.
AbortSequence
Aborts the specified sequence.
Syntax
Movie.AbortSequence(const char *sSequenceName)
Parameter
sSequenceName
PauseSequences
Pauses all the sequences.
Syntax
Movie.PauseSequences()
PlaySequence
Plays the specified sequence.
Syntax
Movie.PlaySequence(const char *sSequenceName)
Description
Sequence name.
Parameter
sSequenceName
ResumeSequences
Resume all the sequences.
Syntax
Movie.ResumeSequences()
StopAllCutScenes
Stops all the cut scenes.
Description
Sequence name.
Version 1.10
915
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
Movie.StopAllCutScenes()
StopAllSequences
Stops all the video sequences.
Syntax
Movie.StopAllSequences()
StopSequence
Stops the specified sequence.
Syntax
Movie.StopSequence(const char *sSequenceName)
Parameter
sSequenceName
Description
Sequence name.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ particle functions that you can call from Lua script.
Attach
Attaches an effect.
Syntax
Particle.Attach()
CreateDecal
Creates a decal with the specified parameters.
Syntax
Particle.CreateDecal(Vec3 pos, Vec3 normal, float size, float lifeTime, const char
*textureName)
Parameter
pos
Version 1.10
916
Description
The decal position vector.
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
normal size lifeTime textureName
Description
The decal normal vector.
The decal size, expressed as a float.
The decal lifetime, expressed as a float.
The name of the texture.
CreateEffect
Creates a particle effect.
Syntax
Particle.CreateEffect(const char *name, SmartScriptTable params)
Parameter
name params
Description
The name of the particle effect.
A
SmartScriptTable
of effect parameters.
CreateMatDecal
Creates a material decal.
Syntax
Particle.CreateMatDecal(Vec3 pos, Vec3 normal, float size, float lifeTime, const char
*materialName)
Parameter
pos normal size lifeTime materialName
DeleteEffect
Deletes the specified particle effect.
Syntax
Particle.DeleteEffect(const char *name)
Version 1.10
917
Description
The decal position vector.
The decal normal vector.
The decal size, expressed as a float.
The decal lifetime, expressed as a float.
The name of the material.
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
name
Detach
Detaches an effect.
Syntax
Particle.Detach()
IsEffectAvailable
Checks if the specified particle effect is available.
Syntax
Particle.IsEffectAvailable(const char *name)
Description
The name of the particle effect to delete.
Parameter
name
Description
The name of the particle effect to check for availability.
SpawnEffect
Spawns an effect.
Syntax
Particle.SpawnEffect(const char *effectName, Vec3 pos, Vec3 dir)
Parameter
effectName pos dir
Description
The name of the effect to spawn.
The position vector of the effect.
The direction vector of the effect.
SpawnEffectLine
Spawns an effect line.
Syntax
Particle.SpawnEffectLine(const char *effectName, Vec3 startPos, Vec3 endPos, Vec3 dir,
float scale, int slices)
Version 1.10
918
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
effectName startPos endPos dir scale slices
Description
The name of the effect.
The start position of the effect.
The end position of the effect.
The direction of the effect.
The scale value of the effect, expressed as a float.
The number of slices.
SpawnParticles
Spawns a particle effect.
Syntax
Particle.SpawnParticles(SmartScriptTable params, Vec3 pos, Vec3 dir)
Parameter
params pos dir
Description
A
SmartScriptTable
of particle effect parameters.
The position vector of the particle effect.
The direction vector of the particle effect.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ physics functions that you can call from Lua script.
RayTraceCheck
Checks if a ray segment intersects anything from its source to its destination.
Syntax
Physics.RayTraceCheck(Vec3 src,Vec3 dst,ScriptHandle skipEntityId1,ScriptHandle
skipEntityId2)
Parameter
src dst
Version 1.10
919
Description
The origin point of the ray segment.
The end point of the ray segment.
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
skipEntityId1 skipEntityId2
Description
Entity ID to skip when checking for intersection.
Entity ID to skip when checking for intersection.
RayWorldIntersection
Checks if a ray segment intersects anything from its source to its destination.
Syntax
Physics.RayWorldIntersection(Vec3 vPos, Vec3 vDir, int nMaxHits, int iEntTypes [,
skipEntityId1 [, skipEntityId2]])
Parameter
vPos vDir nMaxHits iEntTypes skipEntityId1 skipEntityId2
Description
The origin point of the ray.
The direction of the ray.
The maximum number of hits to return, sorted in nearest to farthest order.
A bitmask of physical entity types. The ray intersects only with entities that the mask specifies ( ent_all
,...).
Optional. An entity ID to skip when checking for intersection.
Optional. An entity ID to skip when checking for intersection.
RegisterExplosionCrack
Registers a new crack for a breakable object.
Syntax
Physics.RegisterExplosionCrack(const char *sGeometryFile,int nIdMaterial)
Parameter
sGeometryFile nMaterialId
RegisterExplosionShape
Registers a new explosion shape from static geometry.
Version 1.10
920
Description
The name of the static geometry file for the crack
(CGF).
The ID of the breakable material to which the crack is applied.
Lumberyard Developer Guide
ScriptBind Engine Functions
Note
RegisterExplosionShape
applies only physical forces; it does not apply any game related explosion damages.
Syntax
Physics.RegisterExplosionShape(RegisterExplosionShape(IFunctionHandler *pH,const char
*sGeometryFile,float fSize,int nIdMaterial,float fProbability,const char *sSplintersFile,
float fSplintersOffset, const char *sSplintersCloudEffect)
Parameter
sGeometryFile fSize nIdMaterial fProbability sSplintersFile fSplintersOffset sSplintersCloudEffect
SamplePhysEnvironment
Find the physical entities touched by a sphere.
Syntax
Physics.SamplePhysEnvironment(pt, r [, objtypes])
Description
The name of the static geometry file (CGF).
The scale for the static geometry.
The ID of the breakable material on which the shape is applied.
The preference ratio for using this shape instead of other registered shapes.
The name of a CGF file that contains additional non-physicalized splinters to place on cut surfaces.
The lower splinters position in relation to the upper one.
The particle effect when the splinters constraint breaks.
Parameter
pt r objtypes
Description
The center of the sphere.
The radius of the sphere.
Optional. The types of physical entities that the sphere touches.
SimulateExplosion
Simulates a physical explosion.
Note
SimulateExplosion
applies only physical forces; it does not apply any game related explosion damages.
Version 1.10
921
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
Physics.SimulateExplosion(SmartScriptTable explosionParams) explosionParams
is a
SmartScriptTable
whose elements are as follows:
explosionParams
Elements
Parameter
pos radius direction impulse_pos impulse_presure rmin rmax hole_size
Description
The epicenter of the explosion.
The radius of the explosion.
The direction of the explosion impulse.
The position of the explosion impulse. This value can be different from the epicenter of the explosion.
The pressure of the explosion impulse at the specified radius from the epicenter.
The minimal radius of the explosion. At this radius, full pressure is applied.
The maximum radius of the explosion. At this radius, the impulse pressure is close to zero.
The size of the hole that the explosion creates in breakable objects.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ script-related functions that you can call from Lua script.
DumpLoadedScripts
Dumps all loaded scripts.
Syntax
Script.DumpLoadedScripts()
KillTimer
Stops a timer set by the
Script.SetTimer
function.
Syntax
Script.KillTimer(ScriptHandle nTimerId)
Parameter
nTimerId
Version 1.10
922
Description
The ID of the timer returned by the
Script.SetTimer
function.
LoadScript
Loads the specified script.
Syntax
Script.LoadScript(scriptName)
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
scriptName
ReloadEntityScript
Reloads the specified entity script.
Syntax
Script.ReloadEntityScript(const char *className)
Description
The name of the script to load.
Parameter
className
ReloadScript
Reload the script.
Syntax
Script.ReloadScript(scriptName)
Description
Name of the entity script.
Parameter
scriptName
Description
The name of the script to reload.
ReloadScripts
Reloads all the scripts.
Syntax
Script.ReloadScripts()
SetTimer
Sets a script timer. When the timer expires,
SetTimer
calls the Lua function specified.
Syntax
Script.SetTimer(int nMilliseconds, HSCRIPTFUNCTION hFunc)
Version 1.10
923
Lumberyard Developer Guide
ScriptBind Engine Functions
Returns the ID assigned to the timer or nil if no ID was specified.
Parameter
nMilliseconds luaFunction
Description
Delay of the trigger in milliseconds.
The Lua function to call. If userData
is specified, luaFunction
must be in the format:
LuaCallback = function(userData,nTimerId)
-- function body end;
.
If userData
is not specified, luaFunction
must be in the format:
LuaCallback = function(nTimerId)
-- function body end; userData
Optional. Specifies a user defined table. If userData
is specified, the table is passed as the first argument of the callback function.
bUpdateDuringPause
Optional. The timer is updated and triggered even if the game is in pause mode.
SetTimerForFunction
Sets a timer for the specified function.
Syntax
Script.SetTimerForFunction(int nMilliseconds, const char *sFunctionName)
Returns the ID assigned to the timer, or nil if no ID was specified.
This function has the same parameters as the
SetTimer
function.
UnloadScript
Unloads the specified script.
Syntax
Script.UnloadScript(scriptName)
Parameter
scriptName
Description
The name of the script to unload.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Version 1.10
924
Lumberyard Developer Guide
ScriptBind Engine Functions
Lists C++ sound functions that can be called from Lua scripts.
GetAudioEnvironmentID
Get the audio environment
TAudioEnvironmentID
(wrapped into a
ScriptHandle
).
Syntax
Sound.GetAudioEnvironmentID(const char* const sEnvironmentName)
Returns:
ScriptHandle
with the
TAudioEnvironmentID
value, or nil if the sEnvironmentName
is not found.
Parameter
sEnvironmentName
Description
The unique name of an audio environment.
GetAudioRtpcID
Get the RTPC
TAudioControlID
(wrapped into a
ScriptHandle
).
Syntax
Sound.GetAudioRtpcID(const char* const sRtpcName)
Returns:
ScriptHandle
with the
TAudioControlID
value, or nil if the sRtpcName
is not found.
Parameter
sRtpcName
Description
The unique name of an audio RTPC.
GetAudioSwitchID
Get the switch
TAudioControlID
(wrapped into a
ScriptHandle
).
Syntax
Sound.GetAudioSwitchID(const char* const sSwitchName)
Returns:
ScriptHandle
with the
TAudioControlID
value, or nil if the sSwitchName
is not found.
Parameter
sSwitchName
Description
The unique name of an audio switch.
GetAudioSwitchStateID
Get the
SwitchState TAudioSwitchStatelID
(wrapped into a
ScriptHandle
).
Syntax
Version 1.10
925
Lumberyard Developer Guide
ScriptBind Engine Functions
Sound.GetAudioSwitchStateID(const ScriptHandle hSwitchID, const char* const
sSwitchStateName)
Returns:
ScriptHandle
with the
TAudioSwitchStateID
value, or nil if the sSwitchStateName
is not found.
Parameter
sSwitchStateName
Description
The unique name of an audio switch state.
GetAudioTriggerID
Get the trigger
TAudioControlID
(wrapped into a
ScriptHandle
).
Syntax
Sound.GetAudioTriggerID(const char* const sTriggerName)
Returns:
ScriptHandle
with the
TAudioControlID
value, or nil if the sTriggerName
is not found.
Parameter
sTriggerName
Description
The unique name of an audio trigger.
SetAudioRtpcValue
Globally sets the specified audio RTPC to the specified value.
Syntax
Sound.SetAudioRtpcValue( hRtpcID, fValue )
Returns:
nil
Parameter
hRtpcID fValue
Description
The audio RTPC ID handle.
The RTPC value.
CryLua is deprecated and will be removed in a future version of Lumberyard.
This class implements Lua script functions that expose system functionalities.
ActivatePortal
Activates or deactivates a portal.
Version 1.10
926
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
System.ActivatePortal(Vec3 vPos, bool bActivate, ScriptHandle nID)
Parameters
Parameter
vPos bActivate nID
Description
Position vector.
True to activate the portal, false to deactivate.
Entity identifier.
AddCCommand
Adds a C command to the system.
Syntax
System.AddCCommand(const char* sCCommandName, const char* sCommand, const char* sHelp)
Parameters
Parameter
sCCommandName sCommand sHelp
Description
C command name.
Command string.
Help for the command usage.
ApplicationTest
Test the application with the specified parameters.
Syntax
System.ApplicationTest(const char* pszParam)
Parameters
Parameter
pszParam
Description
Parameters.
Break
Breaks the application with a fatal error message.
Syntax
System.Break()
Version 1.10
927
Lumberyard Developer Guide
ScriptBind Engine Functions
BrowseURL
Browses a URL address.
Syntax
System.BrowseURL(const char* szURL)
Parameters
Parameter
szURL
Description
URL string.
CheckHeapValid
Checks the heap validity.
Syntax
System.CheckHeapValid(const char* name)
Parameters
Parameter
name
ClearConsole
Clears the console.
Syntax
System.ClearConsole()
ClearKeyState
Clear the key state.
Syntax
System.ClearKeyState()
CreateDownload
Syntax
System.CreateDownload()
DebugStats
Syntax
Version 1.10
928
Description
Name string. The default is
<noname>
.
Lumberyard Developer Guide
ScriptBind Engine Functions
System.DebugStats(bool cp)
DeformTerrain
Deforms the terrain.
Syntax
System.DeformTerrain()
DeformTerrainUsingMat
Deforms the terrain using material.
Syntax
System.DeformTerrainUsingMat()
Draw2DLine
Draws a 2D line.
Syntax
System.Draw2DLine(p1x, p1y, p2x, p2y, float r, float g, float b, float alpha)
Parameters
Parameter Description
p1x p1y p2x
X value of the start point of the line.
Y value of the start point of the line.
X value of the end point of the line.
p2y r g
Y value of the end point of the line.
Red component for the label color. Default is 1.
Green component for the label color. Default is 1.
b alpha
Blue component for the label color. Default is 1.
Alpha component for the label color. Default is 1.
DrawLabel
Draws a label with the specified parameter.
Syntax
System.DrawLabel(Vec3 vPos, float fSize, const char* text [, float r [, float g [, float b
[, float alpha]]]])
Version 1.10
929
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameters
Parameter
vPos fSize text r g b alpha
Description
Position vector.
Size for the label.
Text of the label.
Red component for the label colour. Default is 1.
Green component for the label colour. Default is 1.
Blue component for the label colour. Default is 1.
Alpha component for the label colour. Default is 1.
DrawLine
Draws a line.
Syntax
System.DrawLine(Vec3 p1, Vec3 p2, float r, float g, float b, float alpha)
Parameters
Parameter Description
p1
Start position of the line.
p2 r g
End position of the line.
Red component for the label color. Default is 1.
Green component for the label color. Default is 1.
b alpha
Blue component for the label color. Default is 1.
Alpha component for the label color. Default is 1.
DrawText
Draws text.
Syntax
System.DrawText(float x, float y, const char* text, const char* fontName, float size, float
r, float g, float b, float alpha)
Parameters
Parameter Description
x
X position for the text. The default is 0.
y
Y position for the text. The default is 0.
Version 1.10
930
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter Description
text fontName size
Text to be displayed. The default is an empty string.
Font name. The default is default
.
Text size. The default is 16.
r g b
Red component for the label color. The default is 1.
Green component for the label color. The default is 1.
Blue component for the label color. The default is 1.
alpha
Alpha component for the label color. The default is 1.
DumpMemoryCoverage
Dumps memory coverage.
Syntax
System.DumpMemoryCoverage()
This function is useful for investigating memory fragmentation. When
#System.DumpMemoryCoverage() is called from the console,
DumpMemoryCoverage
adds a line to the
MemoryCoverage.bmp
file, which is generated the first time there is a maximum line count.
DumpMemStats
Dumps memory statistics.
Syntax
System.DumpMemStats(bUseKB)
Parameters
Parameter
bUseKB
Description
True to use KB, false otherwise. The default is false.
DumpMMStats
Dumps the MM statistics.
Syntax
System.DumpMMStats()
DumpWinHeaps
Dumps windows heaps.
Version 1.10
931
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
System.DumpWinHeaps()
EnableOceanRendering
Enables/disables ocean rendering.
Syntax
System.EnableOceanRendering()
Parameters
Parameter
bOcean
Description
True to activate the ocean rendering, false to deactivate it.
EnumAAFormats
Enumerates multisample anti-aliasing formats.
Syntax
System.EnumAAFormats()
EnumDisplayFormats
Enumerates display formats.
Syntax
System.EnumDisplayFormats()
Error
Shows a message text with the error severity.
Syntax
System.Error(const char* sParam)
Parameters
Parameter
sParam
ExecuteCommand
Executes a command.
Syntax
Version 1.10
932
Description
Text to be logged. The default is an empty string.
Lumberyard Developer Guide
ScriptBind Engine Functions
System.ExecuteCommand(const char* szCmd)
Parameters
Parameter
szCmd
Description
Command string.
GetConfigSpec
Gets the config specification.
Syntax
System.GetConfigSpec()
GetCurrAsyncTime
Gets the current asynchronous time.
Syntax
System.GetCurrAsyncTime()
GetCurrTime
Gets the current time.
Syntax
System.GetCurrTime()
GetCVar
Gets the value of a console variable.
Syntax
System.GetCVar(const char* sCVarName)
Parameters
Parameter
sCVarName
Description
Name of the variable.
GetEntities
Returns a table with all the entities currently present in a level.
Syntax
System.GetEntities(Vec3 center, float radius)
Version 1.10
933
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameters
Parameter
center radius
Description
Center position vector for the area where to get entities. The default is (0, 0, 0).
Radius of the area. The default is 0.
GetEntitiesByClass
Gets all the entities of the specified class.
Syntax
System.GetEntitiesByClass(const char* EntityClass)
Parameters
Parameter
EntityClass
Description
Entity class name.
GetEntitiesInSphere
Gets all the entities contained into the specified sphere.
Syntax
System.GetEntitiesInSphere(Vec3 center, float radius)
Parameters
Parameter
center radius
Description
center position vector for the sphere where to look at entities.
Radius of the sphere.
GetEntitiesInSphereByClass
Gets all the entities contained into the specified sphere for the specific class name.
Syntax
System.GetEntitiesInSphereByClass(Vec3 center, float radius, const char* EntityClass)
Parameters
Parameter
center radius
Description
center position vector for the sphere where to look at entities.
Radius of the sphere.
Version 1.10
934
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
EntityClass
GetEntity
Gets an entity from its ID.
Syntax
System.GetEntity(entityId)
Parameters
Parameter
entityId
Description
Entity class name.
Description
Entity identifier (svtNumber or ScriptHandle).
GetEntityByName
Retrieve entity table for the first entity with specified name. If multiple entities with same name exist, first one found is returned.
Syntax
System.GetEntityByName(const char *sEntityName)
Parameters
Parameter
sEntityName
Description
Name of the entity to search.
GetEntityClass
Gets an entity class from its ID.
Syntax
System.GetEntityClass(entityId)
Parameters
Parameter
entityId
Description
Entity identifier (svtNumber or ScriptHandle).
GetEntityIdByName
Retrieve entity Id for the first entity with specified name. If multiple entities with same name exist, first one found is returned.
Syntax
Version 1.10
935
Lumberyard Developer Guide
ScriptBind Engine Functions
System.GetEntityIdByName(const char *sEntityName)
Parameters
Parameter
sEntityName
Description
Name of the entity to search.
GetFrameID
Gets the frame identifier.
Syntax
System.GetFrameID()
GetFrameTime
Gets the frame time.
Syntax
System.GetFrameTime()
GetHDRDynamicMultiplier
Gets the HDR dynamic multiplier.
Syntax
System.GetHDRDynamicMultiplier()
GetLocalOSTime
Gets the local operating system time.
Syntax
System.GetLocalOSTime()
GetNearestEntityByClass
Gets the nearest entity with the specified class.
Syntax
System.GetNearestEntityByClass(Vec3 center, float radius, const char *className)
Parameters
Parameter
center
Description
Center position vector for the area where to look at entities.
Version 1.10
936
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
radius className
Description
Radius of the sphere.
Entity class name.
GetOutdoorAmbientColor
Gets the outdoor ambient color.
Syntax
System.GetOutdoorAmbientColor()
GetPhysicalEntitiesInBox
Gets all the entities contained into the specified area.
Syntax
System.GetPhysicalEntitiesInBox(Vec3 center, float radius)
Parameters
Parameter
center radius
Description
Center position vector for the area where to look at entities.
Radius of the sphere.
GetPhysicalEntitiesInBoxByClass
Gets all the entities contained into the specified area for the specific class name.
Syntax
System.GetPhysicalEntitiesInBoxByClass(Vec3 center, float radius, const char *className)
Parameters
Parameter
center radius className
Description
Center position vector for the area where to look at entities.
Radius of the sphere.
Entity class name.
GetPostProcessFxParam
Gets a post processing effect parameter value.
Version 1.10
937
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
System.GetPostProcessFxParam(const char* pszEffectParam, value)
Parameters
Parameter
pszEffectParam value
Description
Parameter for the post processing effect.
Value for the parameter (float or string).
GetScreenFx
Gets a post processing effect parameter value.
Note
This is a convenience wrapper function for
GetPostProcessFxParam
.
Syntax
System.GetScreenFx(const char* pszEffectParam, value)
Parameters
Parameter
pszEffectParam value
Description
Parameter for the post processing effect.
Value for the parameter (float or string).
GetSkyColor
Retrieve color of the sky (outdoor ambient color).
Syntax
Vec3 System.GetSkyColor()
Returns:
Sky color as an
{x,y,z}
vector (x=r,y=g,z=b).
GetSkyHighlight
Retrieves sky highlighing parameters. See
for a description of the parameters.
Syntax
System.GetSkyHighlight(SmartScriptTable params)
GetSunColor
Retrieve color of the sun outdoors.
Syntax
Version 1.10
938
Lumberyard Developer Guide
ScriptBind Engine Functions
Vec3 System.GetSunColor()
Returns:
Sun Color as an
{x,y,z}
vector (x=r,y=g,z=b).
GetSurfaceTypeIdByName
Gets the surface type identifier by its name.
Syntax
System.GetSurfaceTypeIdByName(const char* surfaceName)
Parameters
Parameter
surfaceName
Description
Surface name.
GetSurfaceTypeNameById
Gets the surface type name by its identifier.
Syntax
System.GetSurfaceTypeNameById(int surfaceId)
Parameters
Parameter
surfaceId
Description
Surface identifier.
GetSystemMem
Gets the amount of the memory for the system.
Syntax
System.GetSystemMem()
GetTerrainElevation
Gets the terrain elevation of the specified position.
Syntax
System.GetTerrainElevation(Vec3 v3Pos)
Parameters
Parameter
v3Pos
Description
Position of the terraint to be checked.
Version 1.10
939
Lumberyard Developer Guide
ScriptBind Engine Functions
GetUserName
Gets the username on this machine.
Syntax
System.GetUserName()
GetViewCameraAngles
Gets the view camera angles.
Syntax
System.GetViewCameraAngles()
GetViewCameraDir
Gets the view camera direction.
Syntax
System.GetViewCameraDir()
GetViewCameraFov
Gets the view camera fov.
Syntax
System.GetViewCameraFov()
GetViewCameraPos
Gets the view camera position.
Syntax
System.GetViewCameraPos()
GetViewCameraUpDir
Gets the view camera up-direction.
Syntax
System.GetViewCameraUpDir()
GetWind
Gets the wind direction.
Syntax
System.SetWind()
Version 1.10
940
Lumberyard Developer Guide
ScriptBind Engine Functions
IsDevModeEnable
Checks if game is running in dev mode (cheat mode), which enables certain script function facilities (god mode, fly mode etc.).
Syntax
System.IsDevModeEnable()
IsEditing
Checks if the system is in pure editor mode - that is, not editor game mode.
Syntax
System.IsEditing()
IsEditor
Checks if the system is the editor.
Syntax
System.IsEditor()
IsHDRSupported
Checks if the HDR is supported.
Syntax
System.IsHDRSupported()
IsMultiplayer
Checks if the game is multiplayer.
Syntax
System.IsMultiplayer()
IsPointIndoors
Checks if a point is indoors.
Syntax
System.IsPointIndoors(Vec3 vPos)
Parameters
Parameter
vPos
Description
Position vector. The default is (0, 0, 0).
Version 1.10
941
Lumberyard Developer Guide
ScriptBind Engine Functions
IsPointVisible
Checks if the specified point is visible.
Syntax
System.IsPointVisible(Vec3 point)
Parameters
Parameter
point
Description
Point vector.
IsPS20Supported
Checks if the PS20 is supported.
Syntax
System.IsPS20Supported()
IsValidMapPos
Checks if the position is a valid map position.
Syntax
System.IsValidMapPos(Vec3 v)
Parameters
Parameter
v
Description
Position vector. The default is (0, 0, 0).
LoadFont
Loads a font.
Syntax
System.LoadFont(const char* pszName)
Parameters
Parameter
pszName
Description
Font name.
LoadLocalizationXml
Loads Excel exported XML file with text and dialog localization data.
Version 1.10
942
Lumberyard Developer Guide
ScriptBind Engine Functions
Syntax
System.LoadLocalizationXml(const char *filename)
Log
Logs a message to the log file and console.
Syntax
System.Log(const char* sText)
Parameters
Parameter
sText
Description
Text to be logged.
LogAlways
Logs data even if the verbosity setting is 0.
Syntax
System.LogAlways(const char* sText)
Parameters
Parameter
sText
LogToConsole
Logs a message to the console.
Syntax
System.LogToConsole(const char* sText)
Parameters
Parameter
sText
Description
Text to be logged.
Description
Text to be logged.
PrepareEntityFromPool
Prepares the given bookmarked entity from the pool, bringing it into existence.
Syntax
System.PrepareEntityFromPool(entityId)
Version 1.10
943
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameters
Parameter
entityId bPrepareNow
Description
Entity identifier (number or ScriptHandle).
(optional) When another entity preparation is already in progress, specifies whether the pooled entity should be prepared immediately instead of putting it in a queue.
ProjectToScreen
Projects to the screen (not guaranteed to work if used outside Renderer).
Syntax
System.ProjectToScreen(Vec3 vec)
Parameters
Parameter
vec
Description
Position vector.
Quit
Quits the program.
Syntax
System.Quit()
QuitInNSeconds
Quits the application in the specified number of seconds.
Syntax
System.QuitInNSeconds(float fInNSeconds)
Parameters
Parameter
fInNSeconds
Description
Number of seconds before quitting.
RayTraceCheck
Checks world and static objects.
Syntax
System.RayTraceCheck(Vec3 src, Vec3 dst, int skipId1, int skipId2)
Version 1.10
944
Lumberyard Developer Guide
ScriptBind Engine Functions
RayWorldIntersection
Shoots rays into the world.
Syntax
System.RayWorldIntersection(Vec3 vPos, Vec3 vDir, int nMaxHits, int iEntTypes)
Parameters
Parameter
vPos vDir nMaxHits iEntTypes
Description
Position vector. The default is (0, 0, 0).
Direction vector. The default is (0, 0, 0).
Maximum number of hits.
RemoveEntity
Removes the specified entity.
Syntax
System.RemoveEntity(ScriptHandle entityId)
Parameters
Parameter
entityId
Description
Entity identifier.
ResetPoolEntity
Resets the entity's bookmarked, which frees memory.
Syntax
System.ResetPoolEntity(entityId)
Parameters
Parameter
entityId
Description
Entity identifier (svtnumber or ScriptHandle).
ReturnEntityToPool
Syntax
System.ReturnEntityToPool(entityId)
Version 1.10
945
Lumberyard Developer Guide
ScriptBind Engine Functions
Returns:
the bookmarked entity to the pool, destroying it.
Parameters
Parameter
entityId
Description
Entity identifier (svtnumber or ScriptHandle).
SaveConfiguration
Saves the configuration.
Syntax
System.SaveConfiguration()
ScanDirectory
Scans a directory.
Syntax
System.ScanDirectory(const char* pszFolderName, int nScanMode)
Parameters
Parameter
pszFolderName nScanMode
Description
Folder name.
Scan mode for the folder. Can be:
SCANDIR_ALL
(0),
SCANDIR_FILES
(1), or
SCANDIR_SUBDIRS
(2).
ScreenToTexture
Syntax
System.ScreenToTexture()
SetBudget
Sets system budget.
Syntax
System.SetBudget(int sysMemLimitInMB, int videoMemLimitInMB, float frameTimeLimitInMS,
int soundChannelsPlayingLimit, int soundMemLimitInMB, int soundCPULimitInPercent, int
numDrawCallsLimit)
Parameters
Parameter
sysMemLimitInMB
Description
Limit of the amount of system memory in MB. The default is 512.
Version 1.10
946
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameter
videoMemLimitInMB frameTimeLimitInMS soundChannelsPlayingLimit soundMemLimitInMB soundCPULimitInPercent numDrawCallsLimit
Description
Limit of the amount of video memory in MB. The default is 256.
Limit of the frame time in MS. The default is 50.0f.
Limit of the number of sound channels playing. The default is 64.
Limit of the sound memory in MB. The default is 64.
Limit of the sound CPU usage in percent. The default is 5.
Limit of the number of draw calls. The default is 2000.
SetConsoleImage
Sets the console image.
Syntax
System.SetConsoleImage(const char* pszName, bool bRemoveCurrent)
Parameters
Parameter
pszName bRemoveCurrent
Description
The name of the texture image.
True to remove the current image; otherwise false.
SetCVar
Sets the value of a console variable.
Syntax
System.SetCVar(const char* sCVarName, value)
Parameters
Parameter
sCVarName value
Description
Name of the variable.
Value of the variable (float or string).
SetGammaDelta
Sets the gamma/delta value.
Syntax
System.SetGammaDelta(float fDelta)
Version 1.10
947
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameters
Parameter
fDelta
SetOutdoorAmbientColor
Sets the outdoor ambient color.
Syntax
System.GetOutdoorAmbientColor(v3Color)
Parameters
Parameter
v3Color
Description
Delta value. The default is 0.
Description
Outdoor ambient color value.
SetPostProcessFxParam
Sets a post processing effect parameter value.
Syntax
System.SetPostProcessFxParam(const char* pszEffectParam, value)
Parameters
Parameter
pszEffectParam value
Description
Parameter for the post processing effect.
Value for the parameter ( svtNumber
, svtObject
, or svtString
).
SetScissor
Sets the scissoring screen area.
Syntax
System.SetScissor(float x, float y, float w, float h)
SetScreenFx
Sets a post processing effect parameter value.
Note
This is a convenience wrapper function for
SetPostProcessFxParam
.
Syntax
System.SetScreenFx(pszEffectParam, value)
Version 1.10
948
Lumberyard Developer Guide
ScriptBind Engine Functions
Parameters
Parameter
pszEffectParam value
Description
Parameter for the post processing effect.
Value for the parameter ( svtNumber
, svtObject
, or svtString
).
SetSkyColor
Set color of the sky (outdoors ambient color).
Syntax
System.SetSkyColor(Vec3 vColor)
Parameters
Parameter
vColor
Description
Sky Color as an
{x,y,z}
vector (x=r,y=g,z=b).
SetSkyHighlight
Set sky highlighing parameters.
Syntax
System.SetSkyHighlight(SmartScriptTable params)
Parameters
Parameter
params
Description
Table with sky highlighting parameters.
Params Table Parameters
Highlight Parameter
color direction pos size
SetSunColor
Set the color of the sun, only relevant outdoors.
Syntax
Version 1.10
949
Description
Sky highlight color
Direction of the sky highlight in world space.
Position of the sky highlight in world space.
Sky highlight scale.
Lumberyard Developer Guide
ScriptBind Engine Functions
System.SetSunColor(Vec3 vColor)
Parameters
Parameter
vColor
Description
Sun color as an
{x,y,z}
vector (x=r,y=g,z=b).
SetViewCameraFov
Sets the view camera fov.
Syntax
System.SetViewCameraFov(float fov)
SetVolumetricFogModifiers
Sets the volumetric fog modifiers.
Syntax
System.SetVolumetricFogModifiers(float gobalDensityModifier, float
atmosphereHeightModifier)
Parameters
Parameter
gobalDensityModifier atmosphereHeightModifier
Description
Modifier for the global density.
Modifier for the atmosphere height.
SetWaterVolumeOffset
SetWaterLevel
is not supported by the 3D engine for now.
Syntax
System.SetWaterVolumeOffset()
SetWind
Sets the wind direction.
Syntax
System.SetWind(Vec3 vWind)
Parameters
Parameter
vWind
Description
Wind direction. The default value is (0, 0, 0).
Version 1.10
950
Lumberyard Developer Guide
ScriptBind Engine Functions
ShowConsole
Shows or hides the console.
Syntax
System.ShowConsole(int nParam)
Parameters
Parameter
nParam
Description
1 to show the console, 0 to hide. The default is 0.
ShowDebugger
Shows the debugger.
Syntax
System.ShowDebugger()
SpawnEntity
Spawns an entity.
Syntax
System.SpawnEntity(SmartScriptTable params)
Parameters
Parameter
params
Description
Entity parameters.
ViewDistanceGet
Gets the view distance.
Syntax
System.ViewDistanceSet()
ViewDistanceSet
Sets the view distance.
Syntax
System.ViewDistanceSet(float fViewDist)
Version 1.10
951
Lumberyard Developer Guide
ScriptBind Action Functions
Parameters
Parameter
fViewDist
Description
View distance.
Warning
Shows a message text with the warning severity.
Syntax
System.Warning(const char* sParam)
Parameters
Parameter
sParam
Description
The text to be logged. The default value is an empty string.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ action functions that can be called from Lua scripts.
Topics
•
•
ScriptBind_ActionMapManager (p. 966)
•
ScriptBind_ActorSystem (p. 968)
•
ScriptBind_GameStatistics (p. 969)
•
•
•
ScriptBind_ItemSystem (p. 974)
•
•
•
•
ScriptBind_VehicleSeat (p. 996)
•
ScriptBind_VehicleSystem (p. 997)
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists the action related Lua script bind functions. When parameters are present, the data types indicated in the signatures reflect those of the underlying C++ function.
Version 1.10
952
Lumberyard Developer Guide
ScriptBind Action Functions
ActivateEffect
Activates the effect specified.
Syntax
Action.ActivateEffect(const char * name)
Parameter
name
Description
Specifies the effect to activate.
ActivateExtensionForGameObject
Activates a specified extension for a game object.
Syntax
Action.ActivateExtensionForGameObject(ScriptHandle entityId, const char *extension, bool
activate)
Parameter
entityId extension activate
Description
The identifier of the entity.
The name of the extension.
Specify true
to activate the extension or false
to deactivate it.
AddAngleSignal
Adds an angle for the signal.
Syntax
Action.AddAngleSignal(ScriptHandle entityId, float fAngle, float fFlexibleBoundary, const
char *sSignal)
Parameter
entityId fAngle fFlexibleBoundary sSignal
AddRangeSignal
Adds a range for the signal.
Description
The identifier of the entity.
The angle value.
The size of the flexible boundary.
The string for the signal.
Version 1.10
953
Lumberyard Developer Guide
ScriptBind Action Functions
Syntax
Action.AddRangeSignal(ScriptHandle entityId, float fRadius, float fFlexibleBoundary, const
char *sSignal)
Parameter
entityId fRadius fFlexibleBoundary sSignal
Description
The identifier of the entity.
The adius of the range area.
Flexible boundary size.
String for signal.
AddTargetRangeSignal
Adds a target range signal that has the parameters specified.
Syntax
Action.AddTargetRangeSignal(ScriptHandle entityId, ScriptHandle targetId, float fRadius,
float fFlexibleBoundary, const char *sSignal)
Parameter
entityId targetId fRadius fFlexibleBoundary sSignal
Description
The identifier of the entity.
The identifier of the target.
The radius of the range area.
The size of the flexible boundary.
The string for the signal.
BanPlayer
Bans a specified player.
Syntax
Action.BanPlayer(ScriptHandle entityId, const char* message)
Parameter
entityId message
BindGameObjectToNetwork
Binds a specifed game object to the network.
Version 1.10
954
Description
The identifier of the entity.
The message for the ban.
Lumberyard Developer Guide
ScriptBind Action Functions
Syntax
Action.BindGameObjectToNetwork(ScriptHandle entityId)
Parameter
entityId
CacheItemGeometry
Caches an item geometry.
Syntax
Action.CacheItemGeometry(const char *itemName)
Description
The identifier of the entity to bind to the network.
Parameter
itemName
CacheItemSound
Caches an item sound.
Syntax
Action.CacheItemSound(const char *itemName)
Description
The string name of the item.
Parameter
itemName
ClearEntityTags
Clears the tag for the specified entity.
Syntax
Action.ClearEntityTags(ScriptHandle entityId)
Description
The string name of the item.
Parameter
entityId
ClearStaticTag
Clears the specified static tag for the specified entity.
Version 1.10
955
Description
The identifier of the entity.
Lumberyard Developer Guide
ScriptBind Action Functions
Syntax
Action.ClearStaticTag(ScriptHandle entityId, const char *staticId)
Parameter
entityId staticId
ConnectToServer
Connects to the server specified.
Syntax
Action.ConnectToServer(char* server)
Description
The identifier of the entity.
The identifier of the static tag.
Parameter
server
Description
String that specifies the server to connect to.
CreateGameObjectForEntity
Creates a game object for the entity ID specified.
Syntax
Action.CreateGameObjectForEntity(ScriptHandle entityId)
Parameter
entityId
Description
The identifier of the entity.
DestroyRangeSignaling
Removes range signaling.
Syntax
Action.DestroyRangeSignaling(ScriptHandle entityId)
Parameter
entityId
DisableSignalTimer
Disables the signal timer.
Description
The identifier of the entity.
Version 1.10
956
Lumberyard Developer Guide
ScriptBind Action Functions
Syntax
Action.DisableSignalTimer(ScriptHandle entityId, const char *sText)
Parameter
entityId sText
Description
The identifier of the entity.
The text for the signal.
DontSyncPhysics
Instructs the engine to not synchronize physics for the specified entity.
Syntax
Action.DontSyncPhysics(ScriptHandle entityId)
Parameter
entityId
Description
The identifier of the entity.
EnableRangeSignaling
Enables or disables range signaling for the specified entity.
Syntax
Action.EnableRangeSignaling(ScriptHandle entityId, bool bEnable)
Parameter
entityId bEnable
Description
The identifier of the entity.
Enable or disable range signaling.
EnableSignalTimer
Enables the signal timer.
Syntax
Action.EnableSignalTimer(ScriptHandle entityId, const char *sText)
Parameter
entityId
Version 1.10
957
Description
The identifier of the entity.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
sText
Description
The text for the signal.
ForceGameObjectUpdate
Forces the game object to be updated.
Syntax
Action.ForceGameObjectUpdate(ScriptHandle entityId, bool force)
Parameter
entityId force
GetClassName
Returns the class name, if available, for specified classId
.
Syntax
Action.GetClassName(int classId)
GetPlayerList
Retrieves the current players list.
Syntax
Action.GetPlayerList()
GetServer
Gets the server that corresponds to the number specified.
Syntax
Action.GetServer(int number)
Description
The identifier of the entity.
Specify true
to force the update; specify false otherwise.
Parameter
number
GetServerTime
Gets the current time on the server.
Description
The number of the server.
Version 1.10
958
Lumberyard Developer Guide
ScriptBind Action Functions
Syntax
Action.GetServerTime()
GetWaterInfo
Gets information about the water at the position specified.
Syntax
Action.GetWaterInfo(Vec3 pos)
Parameter
pos
Description
The position for which information will be returned.
HasAI
Returns true
if the entity has an AI object associated with it and has been registered with the AI System
Syntax
Action.HasAI(ScriptHandle entityId)
IsChannelOnHold
Checks if the channel specified is on hold.
Syntax
Action.IsChannelOnHold(int channelId)
Parameter
channelId
IsChannelSpecial
Returns true
if the channel is special.
Syntax
Action.IsChannelSpecial()
IsClient
Returns true
if the current script runs on a client.
Syntax
Version 1.10
959
Description
The identifier of the channel.
Lumberyard Developer Guide
ScriptBind Action Functions
Action.IsClient()
IsGameObjectProbablyVisible
Returns true
if the specifed object is likely visible.
Syntax
Action.IsGameObjectProbablyVisible(ScriptHandle gameObject)
Parameter
gameObject
Description
The game object to check for likely visibilty.
IsGameStarted
Returns true
if the game has started.
Syntax
Action.IsGameStarted()
IsImmersivenessEnabled
Returns true
if immersive multiplayer is enabled.
Syntax
Action.IsImmersivenessEnabled()
IsRMIServer
Returns true
if the current script is running on an RMI (Remote Method Invocation) server.
Syntax
Action.IsRMIServer()
IsServer
Returns true
if the current script runs on a server.
Syntax
Action.IsServer()
LoadXML
Loads XML data from the file specified. For more information, see Using the Lua XML Loader (p. 769)
.
Syntax
Version 1.10
960
Lumberyard Developer Guide
ScriptBind Action Functions
Action.LoadXML(const char * definitionFile, const char * dataFile)
Parameter
definitionFile dataFile
Description
Name of an XML file that declares the kind of data that is included in dataFile
.
The name of the XML file that contains the Lua data described in definitionFile
.
PauseGame
Puts the game into pause mode.
Syntax
Action.PauseGame(bool pause)
Parameter
pause
Description
Specify true
to set the game in pause mode.
Specify false
to resume the game.
Persistent2DText
Adds persistent 2D text.
Syntax
Action.Persistent2DText(const char* text, float size, Vec3 color, const char* name, float
timeout)
Parameter
text size color name timeout
Description
The text to be displayed.
The size of the 2D text.
The color of the 2D text.
The name assigned to the 2D text.
The timeout for the 2D text.
PersistentArrow
Adds a persistent arrow to the world.
Syntax
Action.PersistentArrow(Vec3 pos, float radius, Vec3 dir, Vec3 color, const char* name,
float timeout)
Version 1.10
961
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
pos radius dir color name timeout
Description
The position of the arrow.
The radius of the arrow.
The direction of the arrow.
The color of the arrow.
The name assigned to the arrow.
The timeout for the arrow.
PersistentEntityTag
Adds a persistent entity tag.
Syntax
Action.PersistentEntityTag(ScriptHandle entityId, const char *text)
Parameter
entityId text
Description
The identifier of the entity.
The text for the entity tag.
PersistentLine
Adds a persistent line to the world.
Syntax
Action.PersistentLine(Vec3 start, Vec3 end, Vec3 color, const char* name, float timeout)
Parameter
start end color name timeout
PersistentSphere
Adds a persistent sphere to the world.
Syntax
Version 1.10
962
Description
The starting position of the line.
The ending position of the line.
The color of the line.
The name assigned to the line.
The timeout for the line.
Lumberyard Developer Guide
ScriptBind Action Functions
Action.PersistentSphere(Vec3 pos, float radius, Vec3 color, const char* name, float
timeout)
Parameter
pos radius color name timeout
PreLoadADB
Use this function to pre-cache ADB files.
Syntax
Action.PreLoadADB(const char* adbFileName)
Description
The position of the sphere.
The radius of the sphere.
The color of the sphere.
The name assigned to the sphere.
The timeout for the sphere.
Parameter
adbFileName
Description
The path and filename of the animation ADB file which is to be pre-loaded.
RefreshPings
Refreshes pings for all servers.
Syntax
Action.RefreshPings()
RegisterWithAI
Registers the entity to the AI system and creates an AI object associated with it.
Syntax
Action.RegisterWithAI()
ResetRangeSignaling
Resets range signaling.
Syntax
Action.ResetRangeSignaling(ScriptHandle entityId)
Version 1.10
963
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
entityId
Description
The identifier of the entity.
ResetSignalTimer
Resets the rate for the signal timer.
Syntax
Action.ResetSignalTimer(ScriptHandle entityId, const char *sText)
Parameter
entityId sText
Description
The identifier of the entity.
Th text for the signal.
ResetToNormalCamera
Resets the camera to the last valid view stored.
Syntax
Action.ResetToNormalCamera()
SaveXML
Saves the specified XML data to the file system.
Syntax
Action.SaveXML(const char * definitionFile, const char * dataFile, SmartScriptTable
dataTable)
Parameter
definitionFile dataFile dataTable
SendGameplayEvent
Sends an event for the gameplay.
Syntax
Description
Name of an XML file that declares the kind of data that is included in dataFile
. For more information, see
The name of the XML file that contains the Lua data described in definitionFile
.
The name of the data table.
Version 1.10
964
Lumberyard Developer Guide
ScriptBind Action Functions
Action.SendGameplayEvent(ScriptHandle entityId, int event)
Parameter
entityId event
Description
The identifier of the entity.
The integer of the event.
SetAimQueryMode
Sets the aim query mode for the AI proxy. By default, the AI proxy queries the movement controller if the character is aiming. You can override this behavior by using a different keyword for the mode
parameter.
Syntax
Action.SetAimQueryMode(ScriptHandle entityId, int mode)
Parameter
entityId mode
Description
The identifier of the entity.
Specifies one of the following values:
QueryAimFromMovementController
(the default),
OverriddenAndAiming
, or
OverriddenAndNotAiming
SetNetworkParent
Sets the network parent.
Syntax
Action.SetNetworkParent(ScriptHandle entityId, ScriptHandle parentId)
Parameter
entityId parentID
Description
The identifier of the entity.
The identifier of the parent network.
SetSignalTimerRate
Sets the rate for the signal timer.
Syntax
Action.SetSignalTimerRate(ScriptHandle entityId, const char *sText, float fRateMin, float
fRateMax)
Parameter
entityId
Version 1.10
965
Description
The identifier of the entity.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
sText fRateMin fRateMax
Description
The text for the signal.
The minimum rate for the signal timer.
The maximum rate for the signal timer.
SetViewCamera
Saves the previous valid view and overrides it with the current camera settings.
Syntax
Action.SetViewCamera()
CryLua is deprecated and will be removed in a future version of Lumberyard.
The action map manager provides a high-level interface to handle input controls inside a game. An action map is a set of key or button mappings for a particular game mode (such as controlling a helicopter). For more information, see
Controller Devices and Game Input (p. 496)
.
EnableActionFilter
Enables or disables a specified action filter. An action filter allows actions like moveleft
or moveright
to succeed or fail. For more information, see
Syntax
ActionMapManager.EnableActionFilter( name, enable )
Parameter
name enable
Description
The name of the filter.
Specify true
to enable the filter, or false
to disable it.
EnableActionMap
Enables or disables an action map.
Syntax
ActionMapManager.EnableActionMap(const char *name, bool enable)
Parameter
name
Version 1.10
966
Description
The name of the action map to enable or disable.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
enable
Description
Specify true
to enable the action map, or false
to disable it.
EnableActionMapManager
Enables or disables the action map manager.
Syntax
ActionMapManager.EnableActionMapManager( enable, resetStateOnDisable )
Parameter
enable resetStateOnDisable
Description
Enables or disables the action map manager.
Specify true
to enable the action map manager, or false
to disable it.
Resets the action states when the action map manager is disabled.
GetDefaultActionEntity
Retrieves the currently set default action entity.
Syntax
ActionMapManager.GetDefaultActionEntity()
InitActionMaps
Initializes the action maps and filters found in the file specified.
Syntax
ActionMapManager.InitActionMaps( path )
Parameter
path
IsFilterEnabled
Queries whether the filter specfied is currently enabled.
Syntax
ActionMapManager.IsFilterEnabled( filterName )
Version 1.10
967
Description
The XML file path.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
filterName
Description
The name of the filter whose status to check.
LoadControllerLayoutFile
Loads the given controller layout into the action map manager.
Syntax
ActionMapManager.LoadControllerLayoutFile( layoutName )
Parameter
layoutName
LoadFromXML
Loads information from an XML file.
Syntax
ActionMapManager.LoadFromXML(const char *name)
Description
The name of the layout.
Parameter
name
Description
The name of the XML file to load.
SetDefaultActionEntity
Sets a new default action entity. The action map manager assigns new action maps to the action entity that you set as the default.
Syntax
ActionMapManager.SetDefaultActionEntity( id, updateAll )
Parameter
id updateAll
Description
Specifies the
EntityId
of the action entity that is to become the default.
Updates all existing action map assignments.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Version 1.10
968
Lumberyard Developer Guide
ScriptBind Action Functions
Lists C++ actor system functions that can be called from Lua scripts.
CreateActor
Creates an actor.
Syntax
ActorSystem.CreateActor(ScriptHandle channelId, SmartScriptTable actorParams)
Parameter
channelId actorParams
Description
Identifier for the network channel.
Parameters for the actor.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ game statistics functions that can be called from Lua script.
AddGameElement
Adds a game element to specified scope.
Syntax
GameStatistics.AddGameElement(scopeID, elementID, locatorID, locatorValue [, table])
Parameter
scopeID elementID locatorID locatorValue table
BindTracker
Syntax
GameStatistics.BindTracker(name, tracker)
Parameter
name
Description
The identifier of the scope.
The identifier of the element to be added.
The identifier of the locator.
The value of the locator.
Optional. The table of the element.
Version 1.10
969
Description
The name of the tracker to bind.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
tracker
Description
The
IStatsTracker*
to be bound.
CurrentScope
Returns the ID of current scope, or
-1
if the stack is empty.
Syntax
GameStatistics.CurrentScope()
Event
Syntax
GameStatistics.Event()
PopGameScope
Removes the scope from the top of the stack.
Syntax
GameStatistics.PopGameScope([checkScopeId])
Parameter
checkScopeId
Description
Optional. The identifier of the scope to be removed from the top of the stack.
PushGameScope
Pushes a scope on top of the stack.
Syntax
GameStatistics.PushGameScope(scopeID)
Parameter
scopeID
Description
The identifier of the scope to be placed on top of the stack.
RemoveGameElement
Removes the element that has the supplied parameter values from the specified scope.
Syntax
Version 1.10
970
Lumberyard Developer Guide
ScriptBind Action Functions
GameStatistics.RemoveGameElement(scopeID, elementID, locatorID, locatorValue)
Parameter
scopeID elementID locatorID locatorValue
StateValue
Syntax
GameStatistics.StateValue()
UnbindTracker
Syntax
GameStatistics.UnbindTracker(name, tracker)
Description
The identifier of the scope.
The identifier of the element to be removed.
The identifier of the locator.
The value of the locator.
Parameter
name tracker
Description
The name of the tracker to unbind.
The
IStatsTracker*
to unbind.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ game token functions that can be called from Lua script.
DumpAllTokens
Dump all game tokens with their values to the log.
Syntax
GameToken.DumpAllTokens()
GetToken
Gets the value of a game token.
Syntax
Version 1.10
971
Lumberyard Developer Guide
ScriptBind Action Functions
GameToken.GetToken(const char *sTokenName)
Parameter
sTokenName
Description
The name of the token whose value to get.
SetToken
Sets the value of a game token.
Syntax
GameToken.SetToken(const char* tokenName, any tokenValue)
Parameter
tokenName tokenValue
Description
The name of the token.
The value to set.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ inventory managment functions that you can call from Lua script.
Clear
Clears the inventory.
Syntax
Inventory.Clear()
Destroy
Destroys the inventory.
Syntax
Inventory.Destroy()
Dump
Dumps the inventory.
Syntax
Inventory.Dump()
Version 1.10
972
Lumberyard Developer Guide
ScriptBind Action Functions
GetAmmoCapacity
Gets the capacity for the specified ammunition.
Syntax
Inventory.GetAmmoCapacity(const char *ammoName)
Parameter
ammoName
GetAmmoCount
Gets the amount of the specified ammunition name.
Syntax
Inventory.GetAmmoCount(const char *ammoName)
Description
The name of the ammunition.
Parameter
ammoName
Description
The name of the ammunition.
GetCurrentItem
Gets the current item.
Syntax
Inventory.GetCurrentItem()
GetCurrentItemId
Gets the identifier of the current item.
Syntax
Inventory.GetCurrentItemId()
GetGrenadeWeaponByClass
Gets grenade weapon by class name.
Syntax
Inventory.GetGrenadeWeaponByClass(const char *className)
Parameter
className
Version 1.10
973
Description
The name of the class.
Lumberyard Developer Guide
ScriptBind Action Functions
GetItemByClass
Gets item by class name.
Syntax
Inventory.GetItemByClass(const char *className)
Parameter
className
Description
The name of the class.
HasAccessory
Checks if the inventory contains the specified accessory.
Syntax
Inventory.HasAccessory(const char *accessoryName)
Parameter
accessoryName
Description
The name of the accessory.
SetAmmoCount
Sets the amount of the specified ammunition.
Syntax
Inventory.SetAmmoCount(const char *ammoName, int count)
Parameter
ammoName count
Description
The name of the ammunition.
The count of the ammunition.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ functions for actor items and items in packs that you can call from Lua script.
GetPackItemByIndex
Gets a pack item from its index.
Syntax
Version 1.10
974
Lumberyard Developer Guide
ScriptBind Action Functions
ItemSystem.GetPackItemByIndex(const char *packName, int index)
Parameter
packName index
GetPackNumItems
Get the number of items in the specified pack.
Syntax
ItemSystem.GetPackNumItems(const char* packName)
Description
The name of the pack.
The index of the item to retrieve.
Parameter
packName
Description
The name of the pack whose item count to retrieve.
GetPackPrimaryItem
Gets the primary item of the specified pack.
Syntax
ItemSystem.GetPackPrimaryItem(const char *packName)
Parameter
packName
Description
The name of the pack whose primary item to retrieve.
GiveItem
Gives the specified item.
Syntax
ItemSystem.GiveItem(const char *itemName)
Parameter
itemName
GiveItemPack
Gives the item pack specified to the actor specified .
Version 1.10
975
Description
The name of the item.
Lumberyard Developer Guide
ScriptBind Action Functions
Syntax
ItemSystem.GiveItemPack(ScriptHandle actorId, const char *packName)
Parameter
actorId packName
Reset
Resets the item system.
Syntax
ItemSystem.Reset()
SerializePlayerLTLInfo
Serializes player level to level (LTL) information.
Syntax
ItemSystem.SerializePlayerLTLInfo(bool reading)
Description
The actor identifier.
The name of the pack.
Parameter
reading
Description
Boolean value.
SetActorItem
Sets an actor item.
Syntax
ItemSystem.SetActorItem(ScriptHandle actorId, ScriptHandle itemId, bool keepHistory)
Parameter
actorId itemId keepHistory
SetActorItemByName
Sets an actor item by name.
Description
The actor identifier.
The item identifier.
True to keep the history; otherwise, false.
Version 1.10
976
Lumberyard Developer Guide
ScriptBind Action Functions
Syntax
ItemSystem.SetActorItemByName(ScriptHandle actorId, const char *name, bool keepHistory)
Parameter
actorId name keepHistory
Description
The actor identifier.
The name of the actor item.
True to keep the history; otherwise, false.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ network functions that you can call from Lua script.
Expose
Syntax
Network.Expose()
CryLua is deprecated and will be removed in a future version of Lumberyard.
CallFunction
Calls a function of the UI flash asset or the UIEventSystem.
Syntax
UIAction.CallFunction(elementName, instanceID, functionName, [arg1], [arg2], [...])
Parameter
elementName instanceID functionName args
Version 1.10
977
Description
The UI element name as defined in the XML or
UIEventSystem
name as defined in a
.cpp
file.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances. If used on
UIEventSystem
, no instance ID is ignored.
Function or event name.
List of arguments (optional).
Lumberyard Developer Guide
ScriptBind Action Functions
DisableAction
Disables the UI Action.
Syntax
UIAction.DisableAction(actionName)
Description
UI Action name.
Parameter
actionName
EnableAction
Enables the UI Action.
Syntax
UIAction.EnableAction(actionName)
Parameter
actionName
Description
UI Action name.
EndAction
Ends a UI Action. This can be only used within a
UIAction
Lua script!
Syntax
UIAction.EndAction(table, disable, arguments)
Parameter
table disable arguments
GetAlpha
Get move clip alpha value.
Syntax
UIAction.GetAlpha(elementName, instanceID, mcName)
Description
Must be self
.
If true, this action is disabled when it terminates.
The arguments to return from this action.
Parameter
elementName
Version 1.10
978
Description
The UI element name as defined in the XML.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
instanceID
Description
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
mcName
GetArray
Returns a table with values of the array.
Syntax
UIAction.GetArray(elementName, instanceID, arrayName)
Parameter
elementName instanceID arrayName
GetPos
Get movie clip position.
Syntax
UIAction.GetPos(elementName, instanceID, mcName)
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
Array name as defined in the XML.
Parameter
elementName instanceID
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
mcName
GetRotation
Get movie clip rotation.
Syntax
UIAction.GetRotation(elementName, instanceID, mcName)
Version 1.10
979
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
elementName instanceID mcName
GetScale
Get movie clip scale.
Syntax
UIAction.GetScale(elementName, instanceID, mcName)
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created). '-1' for all instances
The movie clip name as defined in the XML.
Parameter
elementName instanceID
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
mcName
GetVariable
Gets a variable of the UI flash asset.
Syntax
UIAction.GetVariable(elementName, instanceID, varName)
Parameter
elementName instanceID
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
Variable name as defined in the XML.
varName
GotoAndPlay
Call
GotoAndPlay
on a movie clip.
Syntax
Version 1.10
980
Lumberyard Developer Guide
ScriptBind Action Functions
UIAction.GotoAndPlay(elementName, instanceID, mcName, frameNum)
Parameter
elementName instanceID
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
The frame number.
mcName frameNum
GotoAndPlayFrameName
Call
GotoAndPlay
on a movie clip by frame name.
Syntax
UIAction.GotoAndPlayFrameName(elementName, instanceID, mcName, frameName)
Parameter
elementName instanceID
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
The name of the frame.
mcName frameName
GotoAndStop
Call GotoAndStop on a movie clip.
Syntax
UIAction.GotoAndStop(elementName, instanceID, mcName, frameNum)
Parameter
elementName instanceID mcName frameNum
Version 1.10
981
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
The frame number.
Lumberyard Developer Guide
ScriptBind Action Functions
GotoAndStopFrameName
Call GotoAndStop on a movie clip by frame name.
Syntax
UIAction.GotoAndStopFrameName(elementName, instanceID, mcName, frameName)
Parameter
elementName instanceID mcName frameName
HideElement
Hide the UI flash asset.
Syntax
UIAction.HideElement(elementName, instanceID)
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
The name of the frame.
Parameter
elementName instanceID
IsVisible
Get movie clip visible state.
Syntax
UIAction.IsVisible(elementName, instanceID, mcName)
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
Parameter
elementName instanceID
Version 1.10
982
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
mcName
Description
The movie clip name as defined in the XML.
RegisterActionListener
Register a callback function for a
UIAction
event. The callback function must have form:
CallbackName(actionName, eventName, argTable)
Syntax
UIAction.RegisterActionListener(table, actionName, eventName, callbackFunctionName)
Parameter
table actionName eventName callbackFunctionName
Description
The script that receives the callback (can be self to refer the current script).
The UI action name.
The name of the event that is fired from the UI action (can be
OnStart
or
OnEnd
)
Warning
If an empty string is specified, all events will be received.
The name of the script function that will receive the callback.
RegisterElementListener
Register a callback function for a
UIElement
event. The callback function must have form:
CallbackName(elementName, instanceId, eventName, argTable)
Syntax
UIAction.RegisterElementListener(table, elementName, instanceID, eventName,
callbackFunctionName)
Parameter
table elementName instanceID eventName
Version 1.10
983
Description
The script that receives the callback (can be self to refer the current script).
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The name of the event that is fired from the UI element. If an empty string is specified, all events will be received.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
callbackFunctionName
Description
name of the script function that will receive the callback.
RegisterEventSystemListener
Register a callback function for a
UIEventSystem
event. The callback function must have form:
CallbackName(actionName, eventName, argTable)
Syntax
UIAction.RegisterEventSystemListener(table, eventSystem, eventName, callbackFunctionName)
Parameter
table eventSystem eventName callbackFunctionName
ReloadElement
Reloads the UI flash asset.
Syntax
UIAction.ReloadElement(elementName, instanceID)
Description
The script that receives the callback (can be self to refer the current script).
The UI event system name.
The name of the event that is fired from
UIEventSystem
. If an empty string is specified, all events will be received.
name of the script function that will receive the callback.
Parameter
elementName instanceID
RequestHide
Send the fade out signal to the UI flash asset.
Syntax
UIAction.RequestHide(elementName, instanceID)
Version 1.10
984
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
elementName instanceID
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
SetAlpha
Set movie clip alpha value.
Syntax
UIAction.SetAlpha(elementName, instanceID, mcName, fAlpha)
Parameter
elementName instanceID
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
Alpha value (0-1).
mcName fAlpha
SetArray
Sets an array of the UI flash asset.
Syntax
UIAction.SetArray(elementName, instanceID, arrayName, values)
Parameter
elementName instanceID arrayName values
SetPos
Set movie clip position.
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The array name as defined in the XML.
Table of values for the array.
Version 1.10
985
Lumberyard Developer Guide
ScriptBind Action Functions
Syntax
UIAction.SetPos(elementName, instanceID, mcName, vPos)
Parameter
elementName instanceID
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
position.
mcName vPos
SetRotation
Set movie clip rotation.
Syntax
UIAction.SetRotation(elementName, instanceID, mcName, vRotation)
Parameter
elementName instanceID mcName vRotation
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
The rotation.
SetScale
Set movie clip scale.
Syntax
UIAction.SetScale(elementName, instanceID, mcName, vScale)
Parameter
elementName instanceID mcName
Version 1.10
986
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
vScale
Description
scale.
SetVariable
Sets a variable of the UI flash asset.
Syntax
UIAction.SetVariable(elementName, instanceID, varName, value)
Parameter
elementName instanceID
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
Variable name as defined in the XML.
Value to set.
varName value
SetVisible
Set movie clip visible state.
Syntax
UIAction.SetVisible(elementName, instanceID, mcName, bVisible)
Parameter
elementName instanceID mcName bVisible
ShowElement
Displays the UI flash asset.
Syntax
UIAction.ShowElement(elementName, instanceID)
Version 1.10
987
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
The movie clip name as defined in the XML.
visible.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
elementName instanceID
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
StartAction
Starts a UI Action.
Syntax
UIAction.StartAction(actionName, arguments)
Parameter
actionName arguments
UnloadElement
Unloads the UI flash asset.
Syntax
UIAction.UnloadElement(elementName, instanceID)
Description
UI Action name.
The arguments to pass to this action.
Parameter
elementName instanceID
Description
The UI element name as defined in the XML.
The ID of the instance (if an instance with the specified ID does not exist, it will be created).
-1 specifies all instances.
UnregisterActionListener
Unregister callback functions for a UIAction event.
Syntax
UIAction.UnregisterActionListener(table, callbackFunctionName)
Parameter
table
Version 1.10
988
Description
The script that receives the callback (can be self to refer the current script).
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
callbackFunctionName
Description
The name of the script function that receives the callback. If "" is specified, all callbacks for this script will be removed.
UnregisterElementListener
Unregister callback functions for a UIElement event.
Syntax
UIAction.UnregisterElementListener(table, callbackFunctionName)
Parameter
table callbackFunctionName
Description
The script that receives the callback (can be self to refer the current script).
The name of the script function that receives the callback. If "" is specified, all callbacks for this script will be removed.
UnregisterEventSystemListener
Unregister callback functions for a UIEventSystem event.
Syntax
UIAction.UnregisterEventSystemListener(table, callbackFunctionName)
Parameter
table callbackFunctionName
Description
The script that receives the callback (can be self to refer the current script).
The name of the script function that receives the callback. If "" is specfied, all callbacks for this script will be removed.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ vehicle system functions that you can call from Lua script.
AddSeat
Adds a seat to the vehicle.
Version 1.10
989
Lumberyard Developer Guide
ScriptBind Action Functions
Syntax
Vehicle.AddSeat(SmartScriptTable paramsTable)
Parameter
paramsTable
Description
The seat parameters in
SmartScriptTable
format.
ChangeSeat
Makes the actor change the seat inside the vehicle.
Syntax
Vehicle.ChangeSeat(ScriptHandle actorHandle, int seatId, bool isAnimationEnabled)
Parameter
actorHandle seatId isAnimationEnabled
Destroy
Destroys the vehicle.
Syntax
Vehicle.Destroy()
DisableEngine
Disables or enables the engine of the vehicle.
Syntax
Vehicle.DisableEngine(bool disable)
Description
The actor identifier.
The seat identifier.
True if animation is enabled; otherwise, false.
Parameter
disable
EnableMovement
Enables or disables the movement of the vehicle.
Syntax
Version 1.10
990
Description
True to disable the engine; false to enable.
Lumberyard Developer Guide
ScriptBind Action Functions
Vehicle.EnableMovement(bool enable)
Parameter
enable
Description
True to enable movement; false to disable.
EnterVehicle
Makes the specified actor enter the vehicle.
Syntax
Vehicle.EnterVehicle(ScriptHandle actorHandle, int seatId, bool isAnimationEnabled)
Parameter
actorHandle seatId isAnimationEnabled
ExitVehicle
Makes the actor leave the vehicle.
Syntax
Vehicle.ExitVehicle(ScriptHandle actorHandle)
Description
The actor identifier.
The seat identifier.
True if animation is enabled; otherwise, false.
Parameter
actorHandle
Description
The actor identifier.
GetComponentDamageRatio
Gets the damage ratio of the specified component.
Syntax
Vehicle.GetComponentDamageRatio(const char* pComponentName)
Parameter
pComponentName
GetHelperDir
Gets the helper direction.
Description
The name of the component.
Version 1.10
991
Lumberyard Developer Guide
ScriptBind Action Functions
Syntax
Vehicle.GetHelperDir(const char* name, bool isInVehicleSpace)
Parameter
name isInVehicleSpace
Description
The name of the helper.
True if the helper is in the vehicle space; otherwise, false.
GetHelperPos
Gets the helper position.
Syntax
Vehicle.GetHelperPos(const char* name, bool isInVehicleSpace)
Parameter
name isInVehicleSpace
Description
The name of the helper.
True if the helper is in the vehicle space; otherwise, false.
GetHelperWorldPos
Gets the helper position in the world coordinates.
Syntax
Vehicle.GetHelperWorldPos(const char* name)
Parameter
name
Description
The name of the helper.
GetSeatForPassenger
Returns a vehicle seat ID for the specified passenger.
Syntax
Vehicle.GetSeatForPassenger(ScriptHandle passengerId)
Parameter
passengerId
Version 1.10
992
Description
The passenger ID.
Lumberyard Developer Guide
ScriptBind Action Functions
GetVehicle
Gets the vehicle identifier.
Syntax
Vehicle.GetVehicle()
HasHelper
Checks if the vehicle has the specified helper.
Syntax
Vehicle.HasHelper(const char* name)
Parameter
name
IsDestroyed
Checks if the vehicle is destroyed.
Syntax
Vehicle.IsDestroyed()
IsInsideRadius
Checks if the vehicle is inside the specified radius.
Syntax
Vehicle.IsInsideRadius(Vec3 pos, float radius)
Description
The name of the helper.
Parameter
pos radius
IsUsable
Checks if the vehicle is usable by the user.
Syntax
Vehicle.IsUsable(ScriptHandle userHandle)
Version 1.10
993
Description
The {x,y,z} position vector.
The radius, expressed as a float.
Lumberyard Developer Guide
ScriptBind Action Functions
Parameter
userHandle
MultiplyWithWorldTM
Multiplies with the world transformation matrix.
Syntax
Vehicle.MultiplyWithWorldTM(Vec3 pos)
Description
The user identifier.
Parameter
pos
Description
The {x,y,z} position vector.
OnHit
Triggers an event that occurs after the vehicle is hit.
Syntax
Vehicle.OnHit(ScriptHandle targetId, ScriptHandle shooterId, float damage, Vec3 position,
float radius, int hitTypeId, bool explosion)
Parameter
targetId shooterId damage position radius hitTypeId explosion
Description
The target identifier.
The shooter identifier.
The amount of damage, expressed as a float.
The {x,y,z} position vector.
Radius of the hit, expressed as a float.
The type of damage, expressed as an integer.
True if the hit causes an explosion, otherwise false.
OnSpawnComplete
Calls back into the game code for when vehicle spawn has been completed.
Syntax
Vehicle.OnSpawnComplete()
OnUsed
Triggers an event when the user uses the specified vehicle.
Version 1.10
994
Lumberyard Developer Guide
ScriptBind Action Functions
Syntax
Vehicle.OnUsed(ScriptHandle userHandle, int index)
Parameter
userHandle index
Description
The user identifier.
The seat identifier.
ProcessPassengerDamage
Processes passenger damages.
Syntax
Vehicle.ProcessPassengerDamage(ScriptHandle passengerId, float actorHealth, float damage,
int hitTypeId, bool explosion)
Parameter
passengerId actorHealth damage hitTypeId explosion
Description
The passenger identifier.
The health of the actor.
The amount of damage.
The type of damage.
True if there is an explosion; otherwise, false.
Reset
Resets the vehicle.
Syntax
Vehicle.Reset()
ResetSlotGeometry
Syntax
Vehicle.ResetSlotGeometry(int slot, const char* filename, const char* geometry)
Parameter
slot filename geometry
Version 1.10
995
Description
The number of the slot.
The filename.
The slot geometry.
Lumberyard Developer Guide
ScriptBind Action Functions
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ vehicle seat functions that you can call from Lua script.
GetPassengerId
Gets the passenger identifier.
Syntax
VehicleSeat.GetPassengerId()
GetVehicleSeat
Gets the vehicle seat identifier.
Syntax
VehicleSeat.GetVehicleSeat()
GetWeaponCount
Gets the number of weapons available on this seat.
Syntax
VehicleSeat.GetWeaponCount()
GetWeaponId
Gets the weapon identifier.
Syntax
VehicleSeat.GetWeaponId(int weaponIndex)
Parameter
weaponIndex
IsDriver
Checks if the seat is the driver seat.
Syntax
VehicleSeat.IsDriver()
Description
Weapon identifier.
Version 1.10
996
Lumberyard Developer Guide
ScriptBind Action Functions
IsFree
Checks if the seat is free.
Syntax
VehicleSeat.IsFree(ScriptHandle actorHandle)
Parameter
actorHandle
Description
Passenger identifier.
IsGunner
Checks if the seat is the gunner seat.
Syntax
VehicleSeat.IsGunner()
Reset
Resets the vehicle seat.
Syntax
VehicleSeat.Reset()
SetAIWeapon
Sets the weapon artificial intelligence.
Syntax
VehicleSeat.SetAIWeapon(ScriptHandle weaponHandle)
Parameter
weaponHandle
Description
Weapon identifier.
CryLua is deprecated and will be removed in a future version of Lumberyard.
Lists C++ vehicle system functions that you can call from Lua script.
GetOptionalScript
Get an (optional) script for the named vehicle.
Version 1.10
997
Lumberyard Developer Guide
ScriptBind_Boids
Syntax
VehicleSystem.GetOptionalScript(char* vehicleName)
GetVehicleImplementations
Get a table of all implemented vehicles.
Syntax
VehicleSystem.GetVehicleImplementations()
ReloadSystem
Reloads the vehicle system with default values.
Syntax
VehicleSystem.ReloadSystem()
SetTpvDistance
Distance of camera in third person view.
Syntax
VehicleSystem.SetTpvDistance(float distance)
SetTpvHeight
Height of camera in third person view.
Syntax
VehicleSystem.SetTpvHeight(float height)
CryLua is deprecated and will be removed in a future version of Lumberyard.
These functions create simulated flocks of bird-like objects ( boids ) or other animals and control their behavior.
Syntax
Checks if the boid can be picked up.
Boids.CanPickup(flockEntity, boidEntity)
Version 1.10
998
Lumberyard Developer Guide
ScriptBind_Boids
Parameter
flockEntity boidEntity
Creates a bugs flock and binds it to the given entity.
Syntax
Boids.CreateBugsFlock(entity,paramsTable)
Description
Valid entity table containing flock.
Valid entity table containing boid.
Parameter
entity paramTable
Description
Valid entity table.
Table with parameters for flock (see sample scripts).
Creates a fish flock and binds it to the given entity.
Syntax
Boids.CreateFishFlock(entity,paramsTable)
Parameter
entity paramTable
Creates a flock of boids and binds it to the given entity.
Syntax
Boids.CreateFlock(entity,paramsTable)
Description
Valid entity table.
Table with parameters for flock (see sample scripts).
Parameter
entity nType
Description
Valid entity table.
The type of flock. Possible values are
Boids.FLOCK_BIRDS
,
Boids.FLOCK_FISH
, or
Boids.FLOCK_BUGS
.
Version 1.10
999
Lumberyard Developer Guide
ScriptBind_Boids
Parameter
paramTable
Description
Table with parameters for flock (see sample scripts).
Enables or disables a flock in the entity.
Syntax
Boids.EnableFlock(entity,paramsTable)
Parameter
entity bEnable
Description
Valid entity table containing flock.
Specify true to enable the flock; false to disable.
Gets the appropriate localized UI message for the specified flock.
Syntax
Boids.GetUsableMessage(flockEntity)
Parameter
flockEntity
Event that occurs on boid hit.
Syntax
Boids.OnBoidHit(flockEntity,boidEntity,hit)
Description
Valid entity table containing flock.
Parameter
flockEntity boidEntity hit
Forwards the appropriate pickup action to the boid object.
Version 1.10
1000
Description
Valid entity table containing flock.
Valid entity table containing boid.
Valid entity table containing hit information.
Lumberyard Developer Guide
ScriptBind_Boids
Syntax
Boids.OnPickup(flockEntity, boidEntity, bPickup, fThrowSpeed)
Parameter
flockEntity boidEntity bPickup fThrowSpeed
Description
Valid entity table containing flock.
Valid entity table containing boid.
Pickup, or drop or throw.
Specifies the throw speed. By default, a value greater than 5.f kills the boid. This has no effect on the pickup action.
Sets the one time attraction point for the boids.
Syntax
Boids.SetAttractionPoint(entity,paramsTable)
Parameter
entity point
Sets the parameters of the flock for the specified entity.
Syntax
Boids.SetFlockParams(entity, paramsTable)
Description
Valid entity table containing flock.
The one time attraction point.
Parameter
entity paramTable
Description
Valid entity table containing flock.
Table with parameters for flock (see sample scripts).
Specifies the percentage of boid objects that are rendered in flocks. You can use this to enable flocks gradually.
Syntax
Version 1.10
1001
Lumberyard Developer Guide
Integrating Lua and C++
Boids.SetFlockPercentEnabled(entity, paramsTable)
Parameter
entity nPercent
Description
Valid entity table containing flock.
Possible values are from 0 through 100. If 0, no boids are rendered; if 100, all boids are rendered.
CryLua is deprecated and will be removed in a future version of Lumberyard.
The CryScript system abstracts a Lua virtual machine for use by the other systems and the game code. It includes the following functionality:
• calling script functions
• exposing C++-based variables and functions to scripts
• creating script tables stored in virtual machine memory
The CryScript system is based on Lua 5. More information on the Lua language can be found at http:// www.lua.org
.
A global script table can be retrieved by calling
IScriptSystem::GetGlobalValue()
. The IScriptTable is used to represent all script tables/variables.
To expose C++ functions and variables to scripts, you'll need to implement a new class. The easiest way is to derive the
CScriptableBase
class, which provides most of the functionality.
To expose constant values to scripts, use the
IScriptSystem::SetGlobalValue()
. For example, to expose a constant named MTL_LAYER_FROZEN to our scripts, use the following code: gEnv->pScriptSystem->SetGlobalValue("MTL_LAYER_FROZEN", MTL_LAYER_FROZEN);
To expose C++ functions to scripts, implement a new class derives from
CScriptableBase
, as shown in the following example.
classCScriptBind_Game :
publicCScriptableBase
{
Version 1.10
1002
Lumberyard Developer Guide
Exposing C++ Functions and Values public:
CScriptBind_Game( ISystem* pSystem );
virtual ~CScriptBind_Game() {}
intGameLog(IFunctionHandler* pH, char* pText);
};
Add the following code inside the class constructor:
Init(pSystem->GetIScriptSystem(), pSystem);
SetGlobalName("Game");
#undef SCRIPT_REG_CLASSNAME
#define SCRIPT_REG_CLASSNAME &CScriptBind_Game::
SCRIPT_REG_TEMPLFUNC(GameLog, "text");
In a Lua script, you can access your new ScriptBind function as follows:
Game.GameLog("a message")
Version 1.10
1003
Lumberyard Developer Guide
Tutorial: Getting Started with Multiplayer
GridMate is Lumberyard's networking subsystem. GridMate is designed for efficient bandwidth usage and low-latency communications. You can synchronize objects over the network with GridMate's replica framework. GridMate's session management integrates with major online console services and lets you handle peer-to-peer and client-server topologies with host migration. GridMate also supports in-game achievements, leaderboards, and cloud-based saved games through third-party social services such as
Xbox Live, PlayStation Network, and Steam. For an example of how to set up a multiplayer project, see
Multiplayer Sample in the Amazon Lumberyard User Guide .
This section discusses the various components of, and setup requirements for, your Amazon Lumberyard game networking environment. For information about a diagnostic tool for networking, see
.
Topics
•
Tutorial: Getting Started with Multiplayer (p. 1004)
•
•
Using Lumberyard Networking (p. 1051)
•
CryNetwork Backward Compatibility (p. 1074)
This tutorial walks you through the steps to create a simple multiplayer game test level. These steps include binding an entity to the network and connecting a client to the host. At the end of the tutorial, you should have a level with a simple network bound entity that is ready for a multiplayer game.
This tutorial guides you through the following tasks:
• Create a level and add in new entities.
• Bind an entity’s transform component to the network.
• Connect a client to the server and verify network replication.
Version 1.10
1004
Lumberyard Developer Guide
Prerequisites
This tutorial assumes the following:
• You have installed Amazon Lumberyard.
• You have created a game project.
• Your game project has the
Multiplayer
gem and the
User Login: Default
gem enabled. You can enable these gems in Lumberyard's Project Configurator .
Note
This tutorial uses Visual Studio 2013, but you can also use Visual Studio 2015.
Your first step is to create a level and prepare a simple sphere and box shape so that you can test
Lumberyard's networking features.
To create a level, sphere, and box
1. In the Lumberyard Project Configurator, choose a project that has the Multiplayer Gem enabled, and then click
Set as default
.
2. Open Lumberyard Editor, create a level, and give it a name.
3. In the Lumberyard Editor viewport, right-click and select
Create new component entity
.
4. With the entity selected, use the
Entity Inspector
to name the entity
CameraEntity
.
5. Click
Add Component
.
6. Select
Game
,
Camera
to assign a camera component to the entity.
Version 1.10
1005
Lumberyard Developer Guide
Step 1: Creating a Level and Adding a Sphere and a Box
7. In the Lumberyard Editor viewport, right-click and select
Create new component entity
.
8. With the entity selected, use the
Entity Inspector
to name the entity
SphereEntity
.
9. Click
Add Component
,
Shape
,
Sphere Shape
.
10. In
Entity Inspector
, click
Add Component
,
Rendering
,
Static Mesh
to assign a static mesh component to
SphereEntity
.
11. In
Entity Inspector
, under
Static Mesh
, click the
…
next to
Static asset
.
12. In the
Preview
window, click
Objects
,
default
, and choose
primitive_sphere.cgf
.
13. Click
Open
.
14. In the Lumberyard Editor viewport, right-click and select
Create new component entity
.
15. With the entity selected, use the
Entity Inspector
to name the entity
BoxEntity
.
16. Click
Add Component
,
Shape
,
Box Shape
.
17. In
Entity Inspector
, click
Add Component
,
Rendering
,
Static Mesh
to assign a static mesh component to
BoxEntity
.
18. In
Entity Inspector
, under
Static Mesh
, click the
…
next to
Static asset
.
19. In the
Preview
window, click
Objects
,
default
, and choose
primitive_cube.cgf
.
20. Click
Open
.
Version 1.10
1006
Lumberyard Developer Guide
Step 1: Creating a Level and Adding a Sphere and a Box
Version 1.10
1007
Lumberyard Developer Guide
Step 1: Creating a Level and Adding a Sphere and a Box
21. Select the
SphereEntity
. In
Entity Inspector
, click
Add Component
,
Physics
,
Physics
.
22. In
Entity Inspector
, under
Physics
, click the
+
next to
Behavior
.
23. In the
Class to create
dialog box, choose
Rigid Body
to attach rigid body physics to the component.
24. Select the
BoxEntity
, and follow the same steps to attach rigid body physics to it.
25. In the viewport, move the sphere and box entities above the plane so that they have room to fall.
Version 1.10
1008
Lumberyard Developer Guide
Step 2: Binding Sphere Transform
Components to the Network
26. In
Entity Inspector
, set
Physics, At Rest Initially
to
false
to allow the sphere and box to begin simulating after the level is loaded.
You now have two simple component entities with physics in the level that you created.
After you create the initial level with the sphere and the box, you bind the sphere’s transform component to the network. This allows clients to replicate the sphere and see changes over the network.
To bind the sphere’s transform to the network
• Select the sphere entity. In
Entity Inspector
, click
Add Component
,
Network
,
Network Binding
to add a
NetBinding
component to it. This allows the host to replicate the transform component of the sphere to all clients.
Version 1.10
1009
Lumberyard Developer Guide
Step 3: Connecting a Client to the Server
You have now created a server authoritative sphere entity.
This step shows you how to connect a client to the server instance and then observe your networked sphere in action.
To connect a client game to the host game
1. Choose
File
,
Export to Engine
, or press
Ctrl+E
to export your level.
2. Run the game launcher from the
Bin
directory that you are using. If you are using Visual Studio
2013, the directory is
\dev\Bin64vc120\
. If you are using Visual Studio 2015, the path is
\dev
\Bin64vc140\
. The name of your launcher is
<your-game-project-name>
WindowsLauncher.exe
.
3. Press the
`
key (above the
TAB
key) to open the console.
4. Run the command map
<MultiplayerTutorial>
where
<MultiplayerTutorial>
is the name of the level to load.
Version 1.10
1010
Lumberyard Developer Guide
Step 3: Connecting a Client to the Server
5. Press the
`
key to open the console. Run the command mphost
to make your client host a network session.
6. Use the launcher to open another game and press the
`
key to open the console.
7. Run the command
sv_port 0
to set the client port to
0
and the ephemeral port.
Note
On a single computer, only one process is allowed to bind to a particular port. Therefore, to run more than one game process on the same computer (as in this multiplayer sample), you must use ephemeral ports. The sv_port
CVar defines the UDP port on the local machine for the multiplayer sample, and the setting of
0
specifies the ephemeral port. This allows two clients on the same computer to talk to each other.
Version 1.10
1011
Lumberyard Developer Guide
Related Tasks and Tutorials
8. Run the command mpjoin
to join to the host game. You should see the sphere synchronized by location on the client. However, the box will be desynchronized and have different locations on the client and host.
Congratulations! You have successfully created a simple networked level. You can now use the Network
Binding component to synchronize transforms of entities and connect clients to servers.
You have created a simple networking sample to see the effects of networking in Lumberyard. Now visit the following links to see what else you can add to your game:
•
Configuring the Multiplayer Sample for Amazon GameLift (p. 1012)
• Tutorial: Overview of GameLift
• Tutorial: Overview of Cloud Canvas
To prepare the multiplayer sample for use with Amazon GameLift, follow the required procedures for server-side and client-side configuration.
On the server side, overwrite the
GridMate::OnSessionStarted()
handler. In the handler, synchronize the session state and load the corresponding map if the CVAR sv_map
is set in the
Multiplayer::Utils::SynchronizeSessionState()
function.
The following example shows code for server-side configuration.
void GameManager::OnSessionCreated(GridMate::GridSession* session)
{
m_gameSession = session;
if (m_gameSession)
{
if (m_gameSession->IsHost())
{
if (gEnv->IsDedicated())
{
Multiplayer::Utils::SynchronizeSessionState(m_gameSession);
}
}
Version 1.10
1012
Lumberyard Developer Guide
Configuring the Multiplayer Sample for Amazon GameLift
}
}
On the client side, you must configure the following CVARs: sv_port sv_map gamelift_aws_access_key gamelift_aws_secret_key gamelift_fleet_id
or gamelift_alias_id gamelift_end_point gamelift_playerid
You can set these CVARs with a console command or with the multiplayer sample user interface.
To use CVARs to set the client side configuration, type the following console command.
+sv_port 33435 +gamelift_fleet_id
<fleet>
+gamelift_aws_access_key
<aws access key>
+gamelift_aws_secret_key
<aws secret key>
To use the multiplayer sample user interface to configure Amazon GameLift
1. By default, the multiplayer sample loads the
Game Lobby
map. To add or modify the CVARs, click
Amazon GameLift
.
2. Click
Connect
.
Version 1.10
1013
Lumberyard Developer Guide
Configuring the Multiplayer Sample for Amazon GameLift
3. Specify the
Server Name
and the
Map
( sv_map
) to load.
4. To join automatically, click
Create Server
. To search active sessions and select a session to join, click
Refresh
, and then click
Join
.
Version 1.10
1014
Lumberyard Developer Guide
Configuring the Multiplayer Sample for Amazon GameLift
To create a Amazon GameLift package, complete the following steps.
To create a Amazon GameLift package
1. Before you create a Amazon GameLift package, do the following:
• Compile game assets
• Build the Lumberyard executable
2. Run the following commands to create the Amazon GameLift package: mkdir GameLiftPackageWindows cp -r MultiplayerSample_pc_Paks_Dedicated/* GameLiftPackageWindows/ cp -r Bin64vc120.Dedicated/* GameLiftPackageWindows/
3. Upload your build and create a fleet from the Amazon GameLift console. For more information, see
Uploading Your Game to Amazon GameLift .
Amazon GameLift uses the OpenSSL-based secure socket driver to create a secured connection. However, instead of verifying the server, the secure socket driver can verify the client.
To enable a secured connection, make the following change to the game.cfg
file: gm_netsec_enable = 1
Version 1.10
1015
Lumberyard Developer Guide
Overview
If client verification is needed, make the following change to the game.cfg
file: gm_netsec_verify_client = 1
Note
By default, the certificate and private key are loaded from the multiplayersample.cert.pem
file
(shared by the certificate and CA root) and from the multiplayersample.key.pem
file. To specific different files, use the gm_netsec_certificate
and gm_netsec_private_key
CVARs.
Lumberyard enables multiplayer functionality through the following software layers:
• AZFramework
• Netbinding
• GridMate
• Replica
• Session
• Carrier
• Driver
These layers are illustrated in the following diagram.
Version 1.10
1016
Lumberyard Developer Guide
NetBinding
The network binding API of the AzFramework library provides a way for components to synchronize their state over the network. The API is implemented on top of GridMate replicas. A special
NetBindingComponent
is responsible for the actual binding process, so entities that need to be synchronized need to have a
NetBindingComponent
added to them. When a game enters a multiplayer session, the
NetBindingComponent
collects replica chunks from the
NetBindables
on the entity, and adds them to a replica master.
Version 1.10
1017
Lumberyard Developer Guide
GridMate
GridMate is a multiplatform library that enables you to easily add online features to your games. The
GridMate API library has two general categories: network synchronization and online platforms. Each
API is designed to be modular and extensible. Services can be enabled independently of each other, and different implementations can be provided for each API. Optional features are implemented as plugins for ease of customization. GridMate is built on top of Lumberyard’s AzCore library. Service APIs are implemented using EBuses (AzCore’s implementation of signal/slots) to improve modularity and extensibility. All GridMate allocations are piped through two specific allocators:
GridMateAllocatorMP is used for allocations from the network synchronization APIs.
GridMateAllocator
is used for all other allocations, such as those from the online platform APIs and core system allocations. GridMate also supports debugging through AzCore’s Driller framework. All network and replication events are reported and can be captured for logging and debugging purposes.
GridMate uses a single-master replication model. For each replica, one node in the session owns the master copy, and everyone else has a proxy copy. Replicas can be individually migrated from node to node at any time.
At the core of GridMate's replication model is the replica. Replicas, along with the chunks, datasets and
RPCs that make up the replica, provide a mechanism for capturing and propagating the game state.
Replicas also serve as the point of interaction for external game systems. Replicas can be owned by any node in the network and can be migrated to whichever node that can process them most efficiently.
Each node in the replication network runs a local instance of replica manager. As a node establishes connections to other nodes, it adds them to the replica manager as peers. This builds out its replication network.
One important design element of GridMate replicas is the broadcast nature of the system. Many replication systems allow users to specify replication targets directly, either per replica or per update.
This attempt to enable bandwidth optimizations is error prone and puts the implementation burden on gameplay programmers who are often less familiar with network desynchronization issues. Instead,
GridMate's approach follows the rule “when something happens, it happens for everyone”.
The session service is responsible for managing and maintaining the connectivity required to other members in a game session. GridMate’s session service consists of a simple matchmaking API to facilitate integration with existing matchmaking services, and a session implementation that supports three topologies: P2P full mesh, client/server and a hybrid mode that consists of a full mesh network connected to a client/server network. Host migration is available when using full mesh topology. Host migration is a multi-step process that begins as nodes lose connectivity to the session host. The first step is host election: as nodes disconnect from the host, they broadcast a request for a new host election, and go through a serious of voting rounds, until a majority is reached or the election process times out. The new host(s) then starts the migration process, dropping problematic connections and migrating replicas until the session is stable again before resuming normal operations. During this time the connection graph can be very unstable, and a variety of steps are taken to improve success rate.
GridMate’s carrier implementation provides reliable and unreliable messaging. Messages are sent over a channel. Each channel represents an independent stream of messages. Reliable and unreliable messages can be sent over the same channel. Within a channel, message delivery is always ordered, and out-of-order unreliable messages are always discarded. GridMate supports multiple channels to
Version 1.10
1018
Lumberyard Developer Guide
Other GridMate Features compartmentalize the effect of packet losses and reordering. GridMate provides separate dedicated channels for replication and voice chat traffic. To minimize impact to and from the game thread, the current carrier implementation performs network sends and receives from a separate IO thread.
Decoupling sends and receives into separate threads and incorporating epoll/IOCP is planned. The carrier
API provides hooks for congestion control, connection handshakes and network simulators. Users can use the default implementations in GridMate or provide their own custom implementations.
The driver is the interface for the lowest level of the transport layer. Lumberyard ships with several driver implementations:
SocketDriver
is a generic socket driver that supports BSD/WinSock/Posix sockets on the corresponding platforms. The
SecureSocketDriver
supports encrypted communication through the
DTLS protocol by using OpenSSL.
Other GridMate features include:
•
Online Service
- Provides essential user information used by the other APIs.
•
Achievements
- An API for in-game achievements support.
•
Leaderboards
- An API for leaderboard support.
•
Online Storage
- An API for online storage support.
Lumberyard has a backwards compatibility layer for the deprecated legacy networking system called
"CryNetwork". This layer is mostly encapsulated inside the CryNetwork library and exposed through the
INetwork
interface. The layer is intended only for projects that were built using CryNetwork so that you can transition them to Lumberyard's network technology (NetBinding components and GridMate).
Because the CryNetwork backward compatibility API layer uses CPU and bandwidth inefficiently, we strongly recommend that you do not build or release multiplayer games using it.
Topics
•
Networking Architecture (p. 1019)
•
•
•
•
•
Lumberyard provides a network layer that supports a wide variety of game types on multiple platforms and does not restrict game developers to using any particular network topology. You are able to create games using three network topologies: P2P full mesh, client/server, and a hybrid mode that consists of a full mesh network connected to a client/server network. You can create gameplay objects that are server authoritative, and gameplay objects that are client authoritative.
Version 1.10
1019
Lumberyard Developer Guide
Networking Architecture
In this discussion, peer and host have the following meanings:
Peer
- A network node that is participating in a game session.
Host
- A special kind of a peer that manages the game session. The host can run on one of the game clients or be a dedicated server.
Synchronization of the states of various networked game objects is achieved through the GridMate replication model. One important design element is the concept of a horizon
. GridMate does not maintain a full graph of the replication network at each node. Instead, each node is only aware of the peers that it has a direct connection to; everything else is considered the "horizon". Nodes keep track of which replica updates are arriving from which peer (upstream) only for purposes of routing, so they know where to forward upstream requests and, in the case of hub nodes, where to send them downstream.
Basically, if a node receives a request for a replica it doesn’t own, it forwards it upstream.
The following diagram shows the major components of the GridMate architecture and their relationships.
Version 1.10
1020
Lumberyard Developer Guide
Networking Architecture
For more information, see the following pages.
Version 1.10
1021
Lumberyard Developer Guide
Carrier
•
•
•
•
•
Carrier is GridMate's messaging API. GridMate's reliable UDP implementation supports both reliable and unreliable messages. There is no out-of-order delivery. Out-of-order messages are queued if sent reliably, or discarded if sent unreliably.
The carrier sends messages through channels. The purpose of channels is to separate unrelated traffic, such as game state and voice chat. Message ordering is not enforced across channels.
The carrier API also provides hooks for congestion control and traffic simulation.
Messages can be sent on different channels and have different priorities. Message ordering is always maintained between messages with the same priority sent on the same channel.
Channels provide a way to separate unrelated messages so that their ordering does not affect one other. When messages arrive out of order, they are either discarded or queued (and therefore delayed) depending on their reliability. Using different channels prevents unrelated messages from being unnecessarily dropped or delayed. For example, object replication traffic and voice chat traffic can be sent on different channels, so a missing reliable message for object replication would not cause voice chat data to be dropped, and vice versa.
You can customize the following classes to implement your own networking features:
•
Driver
- Carrier defers actual network operations to the driver, so different implementations can be provided for different platforms. This abstraction makes it possible to use platform-specific protocols from service providers such as Steam or XboxLive. The default implementation uses UDP and supports
IPv4 and IPv6.
•
Simulator
- If a network simulator is present, the carrier passes all inbound and outbound traffic through it so different network conditions can be simulated. One simulator instance can be supplied per carrier instance. The default implementation can simulate different patterns for inbound and/or outbound latency, bandwidth caps, packet loss and packet reordering.
•
Traffic Control
- The traffic control module has two primary functions: provide network statistics and congestion control. Whenever messages are sent or received, they are passed along to the traffic control module so it can update its statistics, and also so it can provide feedback to limit the amount of data being sent. It also decides if messages should be considered lost and resent by the carrier.
CarrierDesc
is the carrier descriptor. When you create a carrier, you use the
CarrierDesc
structure to specify the parameters for the current session.
CarrierDesc Parameters
The following parameters can be supplied during carrier initialization:
Version 1.10
1022
Lumberyard Developer Guide
Carrier
Parameter
m_address m_connectionTimeoutMS
Data Type Description
* const char unsigned int
Specifies the local communication address to which the driver will bind. A value of 0 specifies any address. The default is nullptr
.
When a disconnection is detected, specifies the threshold at which all other connections are checked using
m_connectionTimeoutMS * m_connectionEvaluationThreshold
to see if they are also failing because of a network failure.
The default is
0.5f
.
Determines the time to allow for a connection attempt. The default is 5000 milliseconds.
Packet loss percentage threshold. Possible values are from
0.0 to 1.0, where 1.0 is 100 percent. The connection will be dropped after packet loss exceeds the value specified. The default is
0.3f
.
m_driver
* class Driver m_driverIsCrossPlatform bool m_driverIsFullPackets bool unsigned int m_driverSendBufferSize m_familyType unsigned int int
Specifies the RTT ( round-trip time ) threshold in milliseconds.
The connection is dropped when the measured RTT is greater than the value specified. The default is
500.0f
.
Specifies a custom driver implementation. The default is nullptr
.
Specifies whether the driver maintains cross-platform compatibility. When true, the default driver drops to the most restrictive MTU ( maximum transmission unit ) across all supported platforms. The default is false
.
Specifies whether the driver ignores MTU limits. This parameter applies only to socket drivers and local area networks. An internet packet is usually around 1500 bytes. A value of true
enables a maximum packet size of 64 KB. These big packets fail on the Internet but typically do not on local networks. The default is false
.
Specifies the size of the internal receive buffer that the driver uses. A value of 0 specifies the default buffer size. This parameter can be used only if m_driver == null
. The default is
0
.
Specifies the size of the internal send buffer that the driver uses. A value of 0 specifies the default buffer size. This parameter can be used only if m_driver == null
. The default is
0
.
Specifies whether the carrier drops connections when traffic conditions are bad. The default is true
.
Note
This parameter should be set to false
only when debugging.
Specifies the protocol family that the driver uses. A value of
0 specifies the default family.
Version 1.10
1023
Lumberyard Developer Guide
Carrier
Parameter
m_port m_securityData m_simulator m_threadCpuID
*
Data Type Description
unsigned int const char class
Simulator *
Specifies the local communication port to which the driver binds. A value of
0
specifies the port assigned by the system.
Specifies a pointer to a string with security data. For example, on XBox One, this value is the security template name. The default is nullptr
.
Optionally specifies a simulator through which all network messages are filtered. When specified, the carrier passes all inbound and outbound traffic through the specified simulator so that different network conditions can be simulated. You can specify one simulator instance per carrier instance.
int m_threadInstantResponse bool
Restricts the carrier thread to a specific CPU core. The values that can be specified are platform dependent. A value of
-1 specifies no restriction. The default is
-1
.
Specifies whether IO events wake up the carrier thread immediately. The default is false
.
Note
Setting this value to true
typically uses more bandwidth because messages (especially small messages) are grouped less efficiently.
m_threadPriority m_threadUpdateTimeMS m_trafficControl m_version int int
Specifies the thread priority for the carrier thread. The values that can be specified are platform dependent. A value of
-100000
inherits the priority from calling thread. The default is
-100000
.
Specifies, in milliseconds, how often the carrier thread is updated. This parameter is ignored if m_threadInstantResponse
is true. Possible values are from
through
100
. In general, the time interval should be higher
0 than 10 milliseconds. Otherwise, it is more efficient to set m_threadInstantResponse
to true
. The default is 30 milliseconds.
* class
TrafficControl
Specifies a custom traffic control implementation that controls traffic flow to all connections and that handles issues like network congestion.
VersionType Specifies the version of Carrier API that is being used. Carriers with mismatching version numbers are not allowed to connect to each other. The default is
1
.
Topics
•
Carrier Message Structure (p. 1024)
•
The TCP Stream Driver (p. 1025)
This topic describes the message structure used by the
CarrierImpl
networking class found in the
Carrier.cpp
file in the GridMate source code.
Version 1.10
1024
Lumberyard Developer Guide
Carrier
In the following sections, values in parentheses indicate the field's length in bits. For fields with variable length, the value indicates the minimum length.
Datagram Format
The overall datagram has the following structure.
DgramID (16) | Msg1 (64+) | Msg2 (24+) | ...
Message Format
The following diagram shows the possible message fields. Only the first two fields are present in every message header. All the other fields are sent only as necessary. In general,
ChannelId
and
NumChunks
are rarely sent.
SeqNum
and
RelSeqNum
are usually sent once per datagram.
Flags (8) | Length (16) | ChannelId (8) | NumChunks (16) | SeqNum (16) | RelSeqNum (16) |
Payload (0+)
System Messages
Carrier system messages include
ACK
and
ClockSync
.
ACK
The ACK system message is used to ACK any received messages and to keep the connection alive. When there is no activity, an ACK containing only the first two fields is sent, otherwise, the actual fields sent vary depending on the pattern being ack'ed. At the very least,
LastToAck
is sent. If the sequence acke'd contains gaps, a variable-length bit set is used; otherwise, the first sequence number being ack'ed is included. These possible message formats are shown in the following diagram.
MsgId (8) | Flags (8)
MsgId (8) | Flags (8) | LastToAck (16) | AckHistoryBits (1+)
MsgId (8) | Flags (8) | LastToAck (16) | (FirstToAck (16)
ClockSync
A
ClockSync
message is sent about once per second to keep all the clocks in the session in sync. The message format is as follows.
MsgId (8) | Time (32)
Starting with Lumberyard version 1.10, the GridMate library offers a TCP socket driver in addition to its existing UDP driver. Unlike UDP, the TCP protocol uses direct connections, which require a listening port and established server endpoint that clients can use. The GridMate library also adds an event bus that detects stream connect and disconnect events for TCP.
TCP Socket Driver Classes
The TCP socket driver has four public classes in the GridMate namespace that handle TCP packet traffic.
GridMate::StreamSocketDriver
This socket driver has methods that handle TCP connections.
Version 1.10
1025
Lumberyard Developer Guide
Carrier
Stream Socket Methods
Action Method
Establish a direct connection to a listening server
ResultCode ConnectTo(const
SocketDriverAddressPtr& addr)
Break an established TCP connection
ResultCode DisconnectFrom(const
SocketDriverAddressPtr& addr);
Start accepting connections to the server
ResultCode StartListen(AZ::s32 backlog);
Stop the server from accepting connections
ResultCode StopListen();
Note
This call does not shut down the driver. You can start monitoring after the call.
Poll the number of established connections
AZ::u32 GetNumberOfConnections() const;
Query whether a remote address endpoint is connected bool IsConnectedTo(const SocketDriverAddressPtr& to) const;
Query whether the driver is actively listening for new connections bool IsListening() const;
GridMate::StreamSocketDriverEventsBus
The socket driver event bus has methods that detect connection and disconnection events.
Stream Socket Events Bus Methods
Callback that occurs when
The socket driver establishes a connection
The socket driver detects a removed connection
Method
virtual void OnConnectionEstablished(const
SocketDriverAddress& address); virtual void OnConnectionDisconnected(const
SocketDriverAddress& address);
GridMate::StreamSecureSocketDriver
The secure stream socket driver has the following method that initializes cryptographic data for the driver. It calls the
Initialize()
method before setting up the key and/or certificate.
ResultCode InitializeSecurity(AZ::s32 familyType, const char* address, AZ::u32 port,
AZ::u32 receiveBufferSize, AZ::u32 sendBufferSize, StreamSecureSocketDriverDesc& desc);
GridMate::StreamSecureSocketDriver::StreamSecureSocketDriverDesc
The secure stream socket driver requires a description structure to set up the cryptographic key, certificates, and options. The description structure has the following members.
Member
const char* m_privateKeyPEM;
Description
A base64 encoded PEM format private key that is used on the server only.
Version 1.10
1026
Lumberyard Developer Guide
Marshalling
Member
const char* m_certificatePEM; const char* m_certificateAuthorityPEM; bool m_authenticateClient;
Description
A base64 encoded PEM format certificate. This public certificate encrypts the Transport Layer Security (TLS) handshake.
A base64 encoded PEM format CA root certificate.
Ensures that both the client and server authenticate the PEM certificate. This setting is made on the server. The default is false; only the server is authenticated by default.
Security
You can optionally use the OpenSSL library with the TCP socket driver to support encryption of all streamed network traffic between server and clients. In Lumberyard, this security feature is currently available only for the Windows and Linux platforms. The TCP socket driver implements these security features in the
GridMate::StreamSecureSocketDriver
class.
Set up server-side cryptographic keys and certificates as in the following example.
GridMate::StreamSecureSocketDriver server;
GridMate::StreamSecureSocketDriver::StreamSecureSocketDriverDesc desc; desc.m_certificatePEM = myCertPEM; desc.m_privateKeyPEM = myPrivateKeyPEM; const AZ::u16 port = 5555; server.InitializeSecurity(GridMate::Driver::BSD_AF_INET, nullptr, port, 1024*64, 1024 * 64,
desc);
The
InitializeSecurity()
method is used instead of the
Initialize()
method from the stream socket driver. You can also enable client-side certificate authentication in the secure driver description. The default is server side only.
Client-side setup is similar to the server side but does not require a private key, as in the following code example.
GridMate::StreamSecureSocketDriver client;
GridMate::StreamSecureSocketDriver::StreamSecureSocketDriverDesc desc; desc.m_certificateAuthorityPEM = myPublicCertPEM; client.InitializeSecurity(GridMate::Driver::BSD_AF_INET, nullptr, 0, 1024 * 64, 1024 * 64,
desc);
For more information about cryptographic key and security certificate options, see
For more information about using the TCP stream driver, see Using the TCP Stream Driver (p. 1070)
.
Data is written to the network using
WriteBuffer
, and data received is read using
ReadBuffer
. Each buffer specifies the endianness used.
All data marshalling, whether for a
DataSet
or RPC, is written using a specialization of the
Marshaler type. There are a number of pre-defined marshalers for fundamental types ( int32
, uint16
, bool
, float
, etc), as well as other common types like containers and bitfields.
Version 1.10
1027
Lumberyard Developer Guide
Marshalling
Marshalers and read/write buffers have a close relationship. A marshaler reads or writes its data types from or to the buffer. If the type is a complex type like a class or container, then that marshaler marshals each of its fields with nested marshalers. The nested invocation of marshaler types continues until a fundamental type is written to the buffer with the endianness of the network. Additional custom marshalers can be implemented to support custom types or to perform domain-based compression.
Default marshalers are implemented through template specialization .
The base
Marshaler
class in GridMate follows.
namespace GridMate
{
template<typename T>
class Marshaler
{
public:
void Marshal(WriteBuffer& wb, const T& value);
void Unmarshal(T& value, ReadBuffer& rb);
};
}
If a
Marshaler
instance is not specified with the data set or RPC declaration, the template specialization is used.
Implementation of the default marshaler for AZCore's
Vector3
math type can be found in
Code/
Framework/GridMate/GridMate/Serialize/MathMarshal.h
: namespace GridMate
{
template<>
class Marshaler<AZ::Vector3>
{
public:
typedef AZ::Vector3 DataType;
static const AZStd::size_t
MarshalSize
= sizeof(float) * 3;
void Marshal(
WriteBuffer
& wb, const AZ::Vector3& vec) const
{
Marshaler<float> marshaler;
marshaler.Marshal(wb, vec.GetX());
marshaler.Marshal(wb, vec.GetY());
marshaler.Marshal(wb, vec.GetZ());
}
void Unmarshal(AZ::Vector3& vec, ReadBuffer& rb) const
{
float x, y, z;
Marshaler<float> marshaler;
marshaler.Unmarshal(x, rb);
marshaler.Unmarshal(y, rb);
marshaler.Unmarshal(z, rb);
vec.Set(x, y, z);
}
};
}
Notice the declaration of
MarshalSize
above.
WriteBuffer
supports the concept of markers. A marker is a placeholder that can be inserted into the buffer, so its value can be filled after additional data is written to the buffer. This is useful for prepending a length field in front of the actual data. Markers require that the data that is inserted be of fixed length, and
MarshalSize
is used to query this length.
Therefore, marshalers that write data to the marker need to declare a valid
MarshalSize
.
Version 1.10
1028
Lumberyard Developer Guide
Marshalling
Write Buffers
Write buffers are backed by the following three types of allocation schemes:
Dynamic
– Dynamically allocated and automatically grown
Static
– Fixed size, allocated on the stack
Static In Place
– Uses another buffer as its backing store
By default, the write
function uses the default marshaler for the data type, but you can override the marshaler to create a custom marshaler.
There are two ways to write a type to a network buffer:
1) The following example uses the default marshaler for the type passed into
Write()
. In this example, the float marshaler is used.
WriteBuffer wb; wb.Write(1.0f);
2) The following example uses the
HalfMarshaler
, which compresses the float by half.
WriteBuffer wb; wb.Write(1.0f, HalfMarshaler());
Read Buffers
Read buffers have built-in overflow detection and do not read any data fields after the end of the buffer has been reached. You can check this by looking at the return value of the
Read
method. Note that if data isn’t read for a given value, then the value is left uninitialized.
GridMate includes the following predefined marshalers:
Fundamental C++ Types
Floating point
float double
Misc Unsigned Signed
char AZ::u8 bool enum
(specify marshaled size by inheriting enum from a type)
AZ::u16
AZ::u32
AZ::u64
AZ::s8
AZ::s16
AZ::s32
AZ::s64
Container Types
Sequence Associative
vector map
Explicit Marshalers
ContainerMarshaler
Version 1.10
1029
Lumberyard Developer Guide
Marshalling
Sequence Associative
list set string
Explicit Marshalers
MapContainerMarshaler unordered_map unordered_set
(Use these marshalers when the subtypes of the container require a nondefault marshaler) multimap multiset
Utility Types
Name
ConversionMarshaler<SerializedType,
OriginalType>
AZ::Crc32
AZStd::bitset
AZStd::pair
AZ::Aabb
AZStd::chrono::duration
GridMate::UnionDataSet
Description
Performs static casts between
SerializedType
(type on the wire) and
OriginalType
(type declared in user code).
A
CRC32
value.
A class for arbitrary flags.
A std
pair class. Implicitly used by the map, unordered_map, and multimap marshalers.
An axis aligned bounding box.
A time duration in 32 bit milliseconds.
A type safe tagged union designed for network transmission.
Compression Types
Name
Float16Marshaler
HalfMarshaler
IntegerQuantizationMarshaler<Min,
Max, Bytes>
Description
Compresses a float32
to float16
.
Compresses a float to half precision.
Quantizes an integer in the range [
Min
,
Max
] to the number of bytes specified in
Bytes
.
Creating a custom data marshaler is as simple as specializing the
GridMate::Marshaler
type, and implementing the expected
Marshal
and
Unmarshal
methods. If the data written is constant size, adding the member
MarshalSize
allows you to use the marshaler in scenarios where fixed sizes are required
(such as markers).
Fixed Size Custom Marshaler
The following is an example of a fixed size custom marshaler.
Version 1.10
1030
Lumberyard Developer Guide
Sessions namespace GridMate
{
template<>
class Marshaler<MyClass>
{
public:
static const AZStd::size_t MarshalSize = sizeof(m_field1) + sizeof(m_field2);
void Marshal(GridMate::WriteBuffer& wb, const MyClass& value) const
{
wb.Write(value.m_field1);
wb.Write(value.m_field2);
}
void Unmarshal(MyClass& value, ReadBuffer& rb) const
{
rb.Read(value.m_field1);
rb.Read(value.m_field2);
}
};
}
GridMate session service provides session connectivity and management. Both hub-and-spoke (client/ server) and P2P full-mesh topologies are supported.
You can also create multiple sessions for each GridMate instance. Each session creates its own carrier and replica manager instances, so there is no interaction between sessions. GridMate sessions support host migration when running in P2P mode.
Topics
•
Starting and Stopping the Session Service (p. 1031)
•
•
Searching for a Session (p. 1034)
•
•
Reacting to Session Events (p. 1037)
The session service is responsible for hosting or joining sessions and is represented by the
GridMate::SessionService
abstract class.
When a session service is created, a descriptor class derived from
GridMate::SessionServiceDesc
is passed in as a constructor argument.
The implementations of
GridMate::SessionService
that are included with the base Lumberyard engine are as follows.
Implementation Descriptor Description
Sessions hosted over a local area network.
Starting a Session Service
Only one session service can be present per
GridMate::IGridMate
instance.
Version 1.10
1031
Lumberyard Developer Guide
Sessions
Note
Attempting to register multiple session services causes an assert and overrides any previously registered session services.
You have two ways to start a session service:
• Create a session service object and register it with GridMate.
• Register an existing session service object with GridMate.
Starting Method
GridMate::RegisterService()
Details
Creates a session service object and registers it with
GridMate::IGridMate
.
Registers an existing session service object with
GridMate::IGridMate
.
Stopping a Session Service
The method for stopping the session service depends on how the session service was started.
Starting Method Stopping Method Details
The session service is stopped when
GridMate::IGridMate
is destroyed by using the
GridMate::GridMateDestroy()
method.
The session is service is stopped and memory freed when
GridMate::UnregisterService() is called.
Examples
The following examples assume that GridMate has been initialized.
Starting and Stopping with GridMate::StartGridMateService
The following example uses
GridMate::StartGridMateService
.
void MyClass::StartSessionService()
{
IGridMate* gridMate = gEnv->pNetwork->GetGridMate();
if(gridMate)
{
// The session service is started and will be stopped when IGridMate is destroyed.
GridMate::SessionServiceDesc desc;
GridMate::StartGridMateService<GridMate::LANSessionService>(gridMate, desc);
}
}
Starting and Stopping with GridMate::RegisterService() and GridMate::UnregisterService()
The following example uses
GridMate::RegisterService()
and
GridMate::UnregisterService()
.
void MyClass::StartSessionService()
Version 1.10
1032
Lumberyard Developer Guide
Sessions
{
IGridMate* gridMate = gEnv->pNetwork->GetGridMate()
GridMate::SessionService* sessionService = nullptr;
if(gridMate)
{
GridMate::SessionServiceDesc desc;
sessionService = aznew GridMate::LANSessionService(desc);
gridMate->RegisterService(sessionService);
}
return sessionService;
} void MyClass::StopSessionService(GridMate::SessionService* sessionService)
{
IGridMate* gridMate = gEnv->pNetwork->GetGridMate()
if(gridMate)
{
// Unregister the session service and free the session service pointer.
gridMate->UnregisterService(sessionService);
}
}
A session can be hosted by calling
IGridMate::HostSession()
after the session service has been started.
The session settings and configuration are set in the
GridMate::SessionParams
argument, which acts as a base class for certain implementations of
GridMate::SessionService.
Implementation of
GridMate::SessionService
GridMate::LANSessionService
Implementation of
GridMate::SessionParams
GridMate::LANSessionParams
GridMate::SessionParams
The following table shows the supported parameters in
GridMate::SessionParams
.
Parameter
m_localMember m_topology m_numPublicSlots
Required Default
Yes
No
Yes
Description
This is not required for a LAN session, only for consoles.
ST_PEER_TO_PEER ST_CLIENT_SERVER
: A client is only connected to the server.
ST_PEER_TO_PEER
: A client is connected to all other clients.
10000 The time without a response, in seconds, after which a peer is disconnected.
The maximum number of players that can join the session.
GridMate::LANSessionParams
GridMate::LANSessionParams
has the following additional parameter.
Version 1.10
1033
Lumberyard Developer Guide
Sessions
Parameter
m_port
Required
No
Default
0
Description
The port to monitor for search requests from other clients.
If 0, this session is hidden to searches. Otherwise, the port number falls in the range from 1 through 65536.
Events
The following table describes GridMate session service events.
Event
OnSessionCreated
OnMemberJoined
OnMemberLeaving
Description
A new session has just been created.
A player has joined the session.
A player has left the session.
Examples
The following example hosts a session. The example assumes that GridMate has been initialized and a session service registered.
bool MyClass::HostSession()
{
GridMate::IGridMate* gridMate = gEnv->pNetwork->GetGridMate();
if(gridMate)
{
GridMate::LANSessionParams params;
params.m_topology = Gridmate:ST_CLIENT_SERVER;
params.m_numPublicSlots = 10;
params.m_port = 10000;
params.m_flags = 0;
params.m_localMember = gridMate->GetOnlineService()->GetUser();
GridMate::Session session = gridMate->HostSession(¶ms,
GridMate::CarrierDesc());
if(session != nullptr)
{
// Failed to create the session..
return true;
}
}
return false;
}
You search for a session by calling
GridMate::StartGridSearch()
after the session service has been started. The session settings and configuration are set in the
GridMate::SearchParams
, which acts as a base class for certain implementations of
GridMate::SessionService
.
Version 1.10
1034
Lumberyard Developer Guide
Sessions
Implementation of
GridMate::SessionService
GridMate::LANSessionService
Implementation of
GridMate::SearchParams
GridMate::LANSearchParams
GridMate::SearchParams
The following table shows the supported parameters in
GridMate::SearchParams
.
Parameter
m_localMember m_maxSessions m_timeOutMs m_version
Required
Yes
No
No
No
Default
8
2000
1
GridMate::LANSearchParams
GridMate::LANSessionParams
has the following additional parameters.
Parameter
m_serverAddress m_serverPort
Required
No
Yes
Default Description
Empty The address of a server to search for. If empty, a broadcast address is used.
The port that game servers monitor for searches.
1000 The interval, in milliseconds, between search broadcast requests.
Search Results
When a search is complete, the
OnGridSearchComplete()
event is called. The results are found in the
GridMate::GridSearch
argument.
GridMate::GridSearch
contains an array of search results.
To query the size of the array, use
GridMate::GridSearch::NumResults()
.
To query individual results, use
GridMate::GridSearch::GetResult()
.
The
GridMate::SearchInfo
object contains more details about the session (for example, the number of used and free player slots) and can be used when
.
Events
The following table describes GridMate session search events.
Event Description
OnGridSearchStart
A grid search has started.
Version 1.10
1035
Event Description
Lumberyard Developer Guide
Sessions
Examples
The following example searches for all available sessions. The example assumes that GridMate has been initialized, a session service has been registered, and the class
MyClass
is listening for session events.
void MyClass::StartSearch()
{
GridMate::IGridMate* gridMate = gEnv->pNetwork->GetGridMate();
if(gridMate)
{
GridMate::LANSearchParams params;
params.m_serverPort = 20000;
params.m_localMember = gridMate->GetOnlineService()->GetUser();
gridMate->StartGridSearch(¶ms);
}
} void MyClass::OnGridSearchComplete(GridMate::GridSearch* search)
{
if(search->GetNumResults() > 0)
{
// Found sessions that match the specified criteria
}
}
You have two ways to join a session:
• By
Searching for a Session (p. 1034)
and using a
GridMate::SearchInfo
object from the results.
• Directly to an existing game session by using a
GridMate::SessionIdIffo
object.
Regardless of the method, a session is joined using one of the overloaded
IGridMate::JoinSession() functions after the session service has been started.
Note
The argument
GridMate::JoinParams
currently has no supported parameters.
Events
The following table describes GridMate session join events.
Event
OnSessionJoined
OnMemberJoined
OnMemberLeaving
Description
The client has been successfully added to the session.
A player has joined the session.
A player has left the session.
Version 1.10
1036
Lumberyard Developer Guide
Sessions
Example
The following example joins a session that has been found as the result of a session search.
void MyClass::OnGridSearchComplete(const GridMate::GridSearch* search)
{
GridMate::IGridMate* gridMate = gEnv->pNetwork->GetGridMate();
if(gridMate)
{
if(search->GetNumResults() > 0)
{
GridMate::Session* session = gridMate->JoinSession(search->GetResult(0),
GridMate::JoinParams(), GridMate::CarrierDesc());
}
}
} void MyClass:OnSessionJoined(GridMate::GridSession* session)
{
// Joined the session successfully
}
Much of the session functionality is asynchronous because functions can be called, but the response is often not immediately available. For example, messages may be slowed by network transfer time, server processing, or the required response time.
The
in Lumberyard is an event bus system that can send out events when asynchronous session functions are complete. This topic shows you how to set up your application to use the event bus and to connect and disconnect from it.
Setup
Your application must derive a class from
GridMate::SessionEventBus::Handler
. This class must contain certain overridden session events. However, not all events need to be implemented. An example follows.
class MyClass : public GridMate::SessionEventBus::Handler
{
public:
void OnSessionJoined(GridMate::GridSession* session) override;
void OnMemberJoined(GridMate::GridSession* session, GridMate::GridMember* member)
override;
void OnMemberLeaving(GridMate::GridSession* session, GridMate::GridMember* member)
override;
};
Connect
The following example shows how to connect to the session event bus and start receiving session events.
void MyClass::Init()
{
GridMate::IGridMate* gridMate = gEnv->pNetwork->GetGridMate();
if(gridMate)
{
GridMate::SessionEventBus::Handler::BusConnect(gridMate);
}
Version 1.10
1037
Lumberyard Developer Guide
Sessions
}
Disconnect
The following example shows how to disconnect from the session event bus and stop receiving session events.
void MyClass::Term()
{
GridMate::IGridMate* gridMate = gEnv->pNetwork->GetGridMate();
if(gridMate)
{
GridMate::SessionEventBus::Handler::BusDisconnect(gridMate);
}
}
Network Session Service Event Descriptions
A description of each session event follows.
virtual void OnSessionServiceReady()
Callback that occurs when the session service is ready to process sessions.
virtual void OnGridSearchStart(GridSearch* gridSearch)
Callback when a grid search begins.
virtual void OnGridSearchComplete(GridSearch* gridSearch)
Callback that notifies the title when a game search query is complete.
virtual void OnGridSearchRelease(GridSearch* gridSearch)
Callback when a grid search is released (deleted). It is not safe to hold the grid pointer after this event.
virtual void OnMemberJoined(GridSession* session, GridMember* member)
Callback that notifies the title when a new member joins the game session.
virtual void OnMemberLeaving(GridSession* session, GridMember* member)
Callback that notifies the title that a member is leaving the game session.
Warning
The member pointer is not valid after the callback returns.
virtual void OnMemberKicked(GridSession* session, GridMember* member)
Callback that occurs when a host decides to kick a member. An
OnMemberLeaving
event is triggered when the actual member leaves the session.
virtual void OnSessionCreated(GridSession* session)
Callback that occurs when a session is created. After this callback it is safe to access session features.
The host session is fully operational if client waits for the
OnSessionJoined
event.
virtual void OnSessionJoined(GridSession* session)
Called on client machines to indicate that the session has been joined successfully.
virtual void OnSessionDelete(GridSession* session)
Callback that notifies the title when a session is about to be terminated.
Warning
The session pointer is not valid after the callback returns.
Version 1.10
1038
Lumberyard Developer Guide
Replicas
virtual void OnSessionError(GridSession* session, const string& errorMsg )
Called when a session error occurs.
virtual void OnSessionStart(GridSession* session)
Called when the game (match) starts.
virtual void OnSessionEnd(GridSession* session)
Called when the game (match) ends.
virtual void OnMigrationStart(GridSession* session)
Called when a host migration begins.
virtual void OnMigrationElectHost(GridSession* session,GridMember*& newHost)
Called to enable the user to select a member to be the new Host.
Note
The value is ignored if it is null, if the value is the current host, or if the member has an invalid connection ID.
virtual void OnMigrationEnd(GridSession* session,GridMember* newHost)
Called when the host migration is complete.
virtual void OnWriteStatistics(GridSession* session, GridMember* member, StatisticsData& data)
Called at the last opportunity to write statistics data for a member in the session.
Game sessions use replicas to synchronize the state of the session. To use a replica, you simply declare the states that must be synchronized and the remote procedure calls (RPCs) that are supported. After you bind the replica object to the network, the engine does the work. There is no need to worry about how to properly route messages or discover remote objects. When you add a local (master) replica to the network, the replica is automatically discovered by remote nodes. In addition, corresponding remote proxy replica objects are created on the remote nodes. Only the owner of the replica is allowed to change states, and new states are automatically propagated to all other nodes. RPCs can be called from any node but are routed to the master (owner) node for verification and processing.
Topics
•
•
•
•
Remote Procedure Calls (RPCs) (p. 1047)
Replicas are core components of GridMate's replication system that are created by network-connected
GridMate peers. When a peer creates a replica, GridMate propagates the replica over the network to synchronize the replica's state across the session. A locally created and owned replica is called a
master replica
. The copy of the master replica that connected peers receive is called a
proxy replica
. The synchronization and instantiation of replicas is handled by
Replica Chunks
Every replica holds a collection of user-defined
objects that are synchronized
Version 1.10
1039
Lumberyard Developer Guide
Replicas
objects and Remote Procedure Calls (RPCs) (p. 1047) . Any change to a
DataSet
object or a call to an RPC causes the replica to synchronize its state across the session.
Limitations
Replica chunks have the following limitations:
• Each replica can contain only 32 chunks.
• Chunks can be attached or detached only when a replica is not bound to a replica manager.
Creating a Replica and Attaching Chunks
To create a replica, invoke the following method:
GridMate::ReplicaPtr replica = GridMate::Replica::CreateReplica();
Most use cases require only one chunk per replica. To create a chunk and attach it to a replica by using a single call, use the
CreateAndAttachReplicaChunk
helper function, as in the following example:
GridMate::CreateAndAttachReplicaChunk<MyReplicaChunk>(replica, ...);
If you just want to attach a chunk to a replica, do the following: replica->AttachReplicaChunk(myChunk);
For more information about the creation and propagation of replica chunks, see
Binding a Replica to the Session Replica Manager
In order for a replica to be synchronized, it must be bound to the session replica manager. After you create a replica and attach chunks to it, get the replica manager from the
Then, bind the replica to it as follows:
GridMate::ReplicaManager* replicaManager = session->GetReplicaMgr(); replicaManager->AddMaster(replica);
Proxy replicas are automatically instantiated by remote peers' replica managers and, therefore, automatically bound.
Replica Ownership
When a peer creates a replica and binds it to the session replica manager, that peer becomes the owner of the replica. Each replica can be owned by only one peer. The replica owner is the only peer on the network that has the authority to change the state of the replica. For example, it can change the chunks' datasets or directly execute its RPCs. Any state changes performed on a proxy replica are considered invalid and do not propagate throughout the session. RPCs can be called on a proxy replica, but the calls are forwarded to the owner for confirmation before they can be executed. Once this confirmation is given, the RPC is sent to all proxies and also executed locally by the peer. If the master replica denies the execution, no peers receive the RPC call.
Changing Ownership
Replica ownership can be transferred from one peer to another, but the current owner of the replica must agree to the transfer. For information on how a replica owner can prevent transfer of ownership,
.
Version 1.10
1040
Lumberyard Developer Guide
Replicas
Ownership transfer happens automatically when a session performs host migration on a peer-to-peer network. You can also request it explicitly by invoking the following method: replica->RequestChangeOwnership(); // Request ownership of a given replica for the local
peer
Ownership transfer is an asynchronous process. When an ownership transfer is completed, each replica chunk is notified of the change by the
OnReplicaChangeOwnership
callback function.
Replica ID
Each replica has a unique ID associated with it. The replica ID is guaranteed to be unique within a particular GridMate session. You can use the replica ID to retrieve a replica from the session replica manager, as in the following example:
GridMate::ReplicaManager* replicaManager = session->GetReplicaMgr();
GridMate::ReplicaPtr replica = replicaManager->FindReplica(myReplicaId); if (replica == nullptr)
{
// Replica with given ID does not exist
return;
} if (replica->IsProxy())
{
// This is a proxy replica
} if (replica->IsMaster())
{
// This is a master replica
}
Lifetime
The lifetime of a replica is controlled by a
GridMate::ReplicaPtr
, which is a reference-counted smart pointer. The replica manager retains a reference to every replica that is bound to it. It is therefore safe to omit a reference to the replica from user code; the replica is not destroyed as long as the reference is held in replica manager. However, you can force the replica manager to release its reference and free the replica by invoking the following method: replica->Destroy();
Sample Code
This example creates a user-defined chunk, creates a replica, attaches the chuck to the replica, and binds the replica to the session replica manager.
// User-defined ReplicaChunk class to be carried with the replica class MyChunk : public GridMate::ReplicaChunk
{ public:
GM_CLASS_ALLOCATOR(MyChunk);
typedef AZStd::intrusive_ptr<MyChunk> Ptr; // smartptr to hold the chunk
static const char* GetChunkName() { return "MyChunk"; } // Unique chunk name
bool IsReplicaMigratable() override { return false; } // Replica ownership
// cannot be changed
MyChunk () : m_data("Data", 0) { } // chunk constructor
Version 1.10
1041
Lumberyard Developer Guide
Replicas
void OnReplicaActivate(const ReplicaContext& rc) override // Called when replica is
bound
// to the replica manager
(both
// on local and remote peers)
{
// printing out whether it is a proxy or a master replica
if (IsMaster())
printf("I am master!\n");
if (IsProxy())
printf("I am proxy!\n");
}
GridMate::DataSet<int> m_data; // data this chunk holds
};
GridMate::ReplicaPtr replica = GridMate::Replica::CreateReplica(); // Creating a replica
GridMate::CreateAndAttachReplicaChunk<MyChunk>(replica); // Creating chunk of our custom
type
// and attaching it to the replica
GridMate::ReplicaManager* replicaManager = session->GetReplicaMgr(); // Getting replica
manager instance
// from current
session replicaManager->AddMaster(replica); // Binding replica to the replica manager,
// making local peer the owner of this replica
...
// Starting from this point and up until replica destruction, the replica and MyChunk
object
// that the replica is carrying are synchronized with other peers.
// Other peers receive the new replica and bind it to their replica managers. When this is
done,
// OnReplicaActivate is triggered, and the "I am proxy" message is printed out on the
remote peers.
// Every change of m_data DataSet results in the synchronization of the new value in
// the master replica with all of the proxy replicas.
A replica chunk is a user extendable network object. One or more
ReplicaChunk
objects can be owned by a
master peer and is propagated to other network nodes as a proxy replica. The data that a replica chunk contains should generally be related to the other data stored within it. Since multiple chunks can be attached to a replica, unrelated data can be stored in other chunks within the same replica.
A replica chunk can contain Datasets (p. 1045)
and/or
Remote Procedure Calls (RPCs) (p. 1047) . Data
sets store arbitrary data, which only the master replica is able to modify. Any changes are propagated to the chunks in proxy replicas on the other nodes. RPCs are methods that can be executed on remote nodes. They are first invoked on the master, which decides whether the invocation will be propagated to the proxies.
Replica Chunk Requirements and Limitations
A replica chunk has several important attributes:
• It can have up to 32
DataSet
definitions.
• It can have up to 256 RPC definitions.
• It is reference counted and therefore must be held by a smart pointer .
• It is not synchronized across the session until the replica manager is ready.
Version 1.10
1042
Lumberyard Developer Guide
Replicas
Implementing a New Replica Chunk Type
You have two ways to implement a new replica chunk type: handle data set changes and RPC calls
("game logic") inside the chunk, or outside the chunk. In both cases, the following apply:
• The name of the chunk type must be unique throughout the system. To achieve this, every replica chunk type must implement the static member function const char* GetChunkName()
. The string returned by the
GetChunkName
function must uniquely identify the chunk type.
• To indicate whether the ownership of this type of chunk is transferrable, every chunk type needs to override the bool IsReplicaMigratable()
virtual function. If any chunk in a replica is not migratable, the replica's ownership cannot be transferred from one peer to another.
• Every chunk type must define a smart pointer that holds the chunk type instances.
Declaring a Replica Chunk Type with Internal Game Logic Handling
To have your replica chunk class handle game logic directly, it should inherit from
ReplicaChunk
: class MyChunk : public GridMate::
ReplicaChunk
{ public:
GM_CLASS_ALLOCATOR(MyChunk); // Using GridMate's allocator
MyChunk()
: m_data("Data", 0) // Initializing integer DataSet to zero, and
assigning a name for it
, MyRpcMethodRpc("MyRpcMethodRpc") // Initializing RPC by passing in its name; the
RPC name is for debugging purposes
{
}
typedef AZStd::intrusive_ptr<DataSetChunk> Ptr; // Defining smart pointer type
for this chunk
static const char* GetChunkName() { return "MyChunk"; } // Unique chunk type name
bool IsReplicaMigratable() override { return false; } // Specify whether the chunk
can participate in replica's ownership changes
bool MyRpcMethod(int value, const GridMate::RpcContext& context)
{
// Handle event here
return true; // Propagate this call to all proxies
}
GridMate::Rpc<GridMate::RpcArg<int>>::BindInterface<MyChunk, &CustomChunk::MyRpcMethod>
MyRpcMethodRpc;
GridMate::DataSet<int> m_data;
};
Declaring a Replica Chunk Type with External Game Logic Handling
To have your replica chunk class act as a simple data carrier and forward data changes and events to a designated handler (an external class), inherit your handler class from
ReplicaChunkInterface
, and your replica chunk class from
ReplicaChunkBase
: class CustomHandler : public GridMate::
ReplicaChunkInterface
{ public:
GM_CLASS_ALLOCATOR(CustomHandler); // using GridMate's allocator
void DataSetHandler(const int& value, const GridMate::TimeContext& context)
Version 1.10
1043
Lumberyard Developer Guide
Replicas
{
// Handle changes
}
bool RpcHandler(AZ::u32 value, const GridMate::RpcContext &context)
{
// Handle event here
return true; // Propagate this call to all proxies
}
}; class MyChunk : public GridMate::
ReplicaChunkBase
{ public:
GM_CLASS_ALLOCATOR(MyChunk); // Using GridMate's allocator
MyChunk()
: m_data("Data", 0) // Initializing integer DataSet to zero and
assigning a name for it
, MyRpcMethodRpc("MyRpcMethodRpc") // Initializing RPC by passing its name; the
RPC's name is used for debugging purposes
{
}
typedef AZStd::intrusive_ptr<DataSetChunk> Ptr; // Defining smart pointer type
for this chunk
static const char* GetChunkName() { return "MyChunk"; } // Unique chunk type name
bool IsReplicaMigratable() override { return false; } // Whether chunk can
participate in replica's ownership changes
GridMate::DataSet<int>::BindInterface<CustomHandler, &CustomHandler::DataSetHandler>
m_data;
GridMate::Rpc<GridMate::RpcArg<AZ::u32>>::BindInterface<CustomHandler,
&CustomHandler::RpcHandler> MyRpcMethodRpcPC;
};
Registering Chunk Type
Every user-defined replica chunk type should be registered with
ReplicaChunkDescriptorTable
to create the factory required by the
To register replica chunks, use this call:
GridMate::ReplicaChunkDescriptorTable::Get().RegisterChunkType<MyChunk>();
Attaching a Replica Chunk to the Replica
You must add a replica chunk to a replica before you bind the replica to replica manager. After you bind the replica to replica manager, you cannot add or remove replica chunks to or from the replica.
To create a replica chunk, use this call:
MyChunk::Ptr myChunk = GridMate::CreateReplicaChunk<MyChunk>(
<...>
);
Where
<...>
is forwarded to the
MyChunk
constructor.
To attach the chunk to a replica, use this call: replica->AttachReplicaChunk(myChunk);
Version 1.10
1044
Lumberyard Developer Guide
Replicas
Alternatively, you can create the chunk and attach it in one step:
GridMate::CreateAndAttachReplicaChunk<MyChunk>(replica,
<...>
);
After you add the chunk to the replica, the replica retains a smart pointer to the chunk. The chunk is released only when its replica is destroyed.
You can use
DataSet
objects to synchronize the state of a session across the network. When a value in the dataset changes, the updates are propagated automatically. Datasets can be of any type, but they must support the assignment and comparison operators. Your
DataSet
declaration can specify a custom marshaler. If you do not specify a marshaler, the
DataSet
object uses
GridMate::Marshaler<T>
.
A
DataSet
must be declared inside a
ReplicaChunk
object. A
ReplicaChunk
object can contain up to 32
DataSet
objects. You must supply a debug name to the dataset constructor.
The following example declares a
ReplicaChunk
object that has two
DataSet
objects of type float
. One dataset uses the default marshaler. The other dataset uses a custom marshaler called
MyCustomMarshaler
.
class MyChunkType : public GridMate::ReplicaChunk
{
public:
MyChunkType()
: m_synchedFloat("SynchedFloat")
, m_synchedHalf("SynchedHalf")
{
}
GridMate::DataSet<float> m_synchedFloat;
GridMate::DataSet<float, MyCustomMarshaler> m_synchedHalf;
};
Datasets can be optionally bound to a callback on the chunk interface so that the callback is called when new data arrives.
class MyChunkType : public GridMate::ReplicaChunk
{ public:
MyChunkType()
: m_synchedFloat("SynchedFloat")
{
}
// Callback to call when new data arrives.
void OnSynchedFloatData(const float& newValue, const GridMate::TimeContext&
timeContext);
GridMate::DataSet<float>::BindInterface<MyChunkType,
amp;MyChunkType::OnSynchedFloatData> m_synchedFloat;
};
Eventual consistency is guaranteed for datasets. Normally, datasets propagate unreliably. To compensate for potential packet losses, and to minimize latency, GridMate handles events in the following order:
1. A user changes a value in the dataset.
2. The new value is broadcast to the remote peers.
3. The dataset stops changing.
Version 1.10
1045
Lumberyard Developer Guide
Replicas
4. A user-configurable grace period elapses.
5. A last update is sent reliably.
6. To conserve bandwidth, propagation is suspended until the next change.
You can change the length of the grace period in step 4 by calling
SetMaxIdleTime
:
...
GridMate::DataSet<Vector3> m_pos;
...
...
m_pos.SetMaxIdleTime(5.f); // Suspend sending if m_pos has not changed for 5 ticks
...
Examples
The examples in this section show three different ways to create datasets.
Example 1
The following example creates a
DataSet
object that stores a u32
value, using the default marshaler for u32
.
GridMate::DataSet<AZ::u32> m_data;
Example 2
The following example creates a
DataSet
object that stores a float. The data written to the network is half float size because of the specified marshaler.
GridMate::DataSet<float, HalfMarshaler> m_data;
Example 3
The following example creates a
DataSet
object that stores an s32
value using the default marshaler for s32
. Whenever the
DataSet
value changes, the
DataSetHandler
function is called on the
MyReplicaChunk instance. This is true for both master and proxy nodes; the event is triggered on local data changes for the master, and upon received data changes for the proxies.
class MyReplicaChunk : public GridMate::ReplicaChunk
{
void DataSetHandler(const AZ::s32& value, const GridMate::TimeContext& context) { /*
Data Changed Logic */ }
GridMate::DataSet<AZ::s32>::BindInterface<MyReplicaChunk,
&MyReplicaChunk::DataSetHandler> Data;
};
Throttlers
Datasets can be throttled based on an optional throttler parameter to the template. The throttler can choose to send data or withhold downstream updates unless a certain condition has been met. The throttler must implement the
WithinThreshold
method using the following syntax.
bool WithinThreshold(T previousValue, T currentValue);
The return value of the method determines whether to send the data to the proxy peers.
Version 1.10
1046
Lumberyard Developer Guide
Replicas
RPCs allow games to send events or requests to remote nodes through replicas. They can be used to send messages to a specific node, or to route function calls to the authoritative node. For example, you can use RPCs to implement functions that change the position of an object. This ensures that changes happen only at the node that owns the object. For server-authoritative games, reliable RPCs can be used for sending frequent client input commands.
RPCs have the following characteristics:
• RPC arguments can be of any type, as long as a valid marshaler is provided.
• All RPC requests are routed to the master replica.
• The RPC handler function in the master replica chooses whether to propagate the RPC to proxy replicas.
• RPCs are not kept in the history, and late-joining clients might not receive RPCs requested before the client joined.
Like datasets, RPCs are declared as replica chunk members. An RPC handler function is bound to the RPC as part of the declaration. RPC requests are forwarded to the handler function along with the arguments and an
RpcContext
associated with the request.
The RPC handler function can perform additional checks before executing the request.
The handler for an RPC returns a Boolean value to GridMate. This value is used on the replica's master node to determine whether the RPC is propagated to all proxies.
Remote procedure calls are always invoked first on the master node for the replica. This is true whether the initial caller is a master or proxy. The master node's RPC handler decides whether the RPC should be propagated to the proxy nodes based on the return value of the RPC handler. The user returns true
to mean "propagate to all replica proxies," and false
to mean "only invoke this RPC on the master."
RPCs have a constructor that requires a string. This is used for debugging and statistical purposes. Any debugging or network monitoring exposes the given RPC name. Using modern C++, the name can also be specified inline, as in the following example.
Rpc<RpcArg<AZ::u32>>::BindInterface<MyClass,
&MyClass::Func> Rpc = {"My RPC"};
Examples
The following examples show how RPCs can be used in GridMate.
Example 1
In the following example,
Rpc1
is an RPC that takes a single parameter of type u32
. It uses the default u32 marshaler.
class MyReplicaChunk : public GridMate::ReplicaChunk
{
bool Rpc1Handler(AZ::u32 val, const GridMate::RpcContext& context) { /* RPC Logic */ }
GridMate::Rpc<GridMate::RpcArg<AZ::u32>>::BindInterface<MyReplicaChunk,
&MyReplicaChunk::Rpc1Handler> Rpc1;
};
Example 2
In the following example,
Rpc2
is an RPC that takes a single parameter of type s32
. It uses
IntegerQuantizationMarshaler
, with a range from
-100
to
100
and writes one byte to the wire.
Version 1.10
1047
Lumberyard Developer Guide
Replicas class MyReplicaChunk : public GridMate::ReplicaChunk
{
bool Rpc2Handler(AZ::s32 val, const GridMate::RpcContext& context) { /* RPC Logic */ }
GridMate::Rpc<GridMate::RpcArg<AZ::s32, GridMate::IntegerQuantizationMarshaler<-100,
100, 1>>>::BindInterface<MyReplicaChunk, &MyReplicaChunk::Rpc2Handler> Rpc2;
};
Example 3
In the following example,
Rpc3
is an RPC that takes two parameters; a u8
and a string. It uses the default marshalers for each argument.
class MyReplicaChunk : public GridMate::ReplicaChunk
{
bool Rpc3Handler(AZ::u8 val, const AZStd::string& str, const GridMate::RpcContext&
context) { /* RPC Logic */ }
GridMate::Rpc<GridMate::RpcArg<AZ::u8>, GridMate::RpcArg<const
AZStd::string&>>::BindInterface<MyReplicaChunk, &MyReplicaChunk::Rpc3Handler> Rpc3;
};
Example 4
If you want to send a custom class as an RPC parameter, you must first write a marshaler for it, as in the following example.
struct MyClass
{
AZ::Crc32 m_name;
AZ::u32 m_value;
}; namespace GridMate
{
template<>
class Marshaler<MyClass>
{
public:
static const AZStd::size_t MarshalSize = Marshaler<AZ::Crc32>::MarshalSize +
sizeof(AZ::u32);
void Marshal(WriteBuffer& wb, const MyClass& value) const
{
wb.Write(value.m_name);
wb.Write(value.m_value);
}
void Unmarshal(MyClass & value, ReadBuffer& rb) const
{
rb.Read(value.m_name);
rb.Read(value.m_value);
}
};
}
An RPC that passes a parameter of the foregoing class might be declared like this: class MyReplicaChunk : public GridMate::ReplicaChunk
{
bool Rpc4Handler(const MyClass& value, const GridMate::RpcContext& context) { /* RPC
Logic */ }
GridMate::Rpc<GridMate::RpcArg<const MyClass&>>::BindInterface<MyReplicaChunk,
&MyReplicaChunk::Rpc4Handler> Rpc4;
Version 1.10
1048
Lumberyard Developer Guide
Replica Manager
};
For
Rpc4
, the first and only argument is a const
reference to the
MyClass
object. The const MyClass& is specified to indicate that the
Rpc4Handler
function takes a const
reference. This allows you to avoid making a copy of the object when it is passed to the handler function. Behind the scenes, GridMate stores a temporary value of
MyClass
, which is what the reference binds to. The temporary referent is removed after the RPC has been called. You can also use this technique to marshal objects that are wrapped in smart pointers.
Example 5
In order to invoke an RPC on a given chunk instance, you can simply call the RPC, as in the following example.
class MyReplicaChunk : public GridMate::ReplicaChunk
{
bool Rpc5Handler(AZ::u32 val, const GridMate::RpcContext& context) { /* RPC Logic */ }
GridMate::Rpc<GridMate::RpcArg<AZ::u32>>::BindInterface<MyReplicaChunk,
&MyReplicaChunk::Rpc1Handler> Rpc5;
}; void Foo(MyChunkType* myChunkInstance)
{
myChunkInstance->Rpc5(1);
}
Rpc5
is an RPC that takes a single parameter of type u32
. It uses the default u32
marshaler. Calling
Foo invokes the RPC on the replica chunk instance and passes in a value of
1
.
RPC Type Traits
RPCs have an optional typetraits
parameter. The following traits are expected in the traits
class.
Trait Default
Value
s_isReliable true s_isPostAttached true
Description
Uses reliable transmission to send the RPC.
Forces any dirty datasets to also be sent reliably in advance. This is useful if the RPC relies on the data in the datasets to be up to date on the destination peer.
The replica manager is a subsystem that is responsible for managing the synchronization of replicas. The replica manager is responsible for the following:
• Marshaling and unmarshaling the replicas in each peer
• Forwarding replicas from one peer to another
• Handling ownership changes of replicas
• Managing replica lifetimes
Managing Replica Lifecycle
The replica manager must do the following:
Version 1.10
1049
Lumberyard Developer Guide
Replica Manager
• Keep track of all replicas by holding a reference-counted pointer to every master and proxy replica object.
• Guarantee consistency across the session by capturing and propagating the last state of every replica before a replica is destroyed.
• Guarantee that all proxies reach eventual consistency before a replica is deactivated.
• Release all GridMate references to a replica object when the object has been destroyed.
Topics
•
Binding a New Master Replica to Replica Manager (p. 1050)
•
Retrieving Replicas from Replica Manager (p. 1050)
•
How Replica Manager Updates Replicas (p. 1050)
•
After a new master replica is created, it must be bound to the replica manager as follows:
GridMate::ReplicaManager* replicaManager = session->GetReplicaMgr(); // Get replica manager
from the current session replicaManager->AddMaster(myReplica1); // Bind replica to replica manager replicaManager->AddMaster(myReplica2); // Bind replica to replica manager
Proxy replicas are bound to their session's replica managers automatically. Each
ReplicaManager
instance holds a reference to every replica that is bound to it. That changes only when the user calls
Destroy()
on the replica or when the
ReplicaManager
itself is destroyed.
Every replica has a numeric identifier that is unique in the session. To find a replica by its ID, invoke
FindReplica(
<ReplicaId>
)
, as in the following example:
GridMate::ReplicaPtr replica = replicaManager->FindReplica(
<myReplicaId>
);
AZ_Assert(replica != nullptr, "Replica with id=%d not found.",
<myReplicaId>
);
The GridMate session triggers the replica manager to perform replica updates on a continuous basis. These updates include the following actions:
• Unmarshaling
• Update from replica
• Update replicas
• Marshaling
Marshaling: Sending Data to Other Peers
Changes in a replica must be replicated to every remote peer in the GridMate session. To communicate a change in one of its replicas, a peer's replica manager serializes the replica object into a send buffer. It then sends the object to the network. Replica marshaling occurs in two main phases:
Version 1.10
1050
Lumberyard Developer Guide
Using Lumberyard Networking
•
Data Preparation
– A premarshaling phase that, based on changes in the replica, determines which
RPCs and
DataSet
objects to send. This phase also validates the data integrity of the objects to be sent.
•
Actual Marshaling
– The transformation of a replica object into a byte stream. The actual data that must be marshaled depends on how much new information the master replica has relative to its corresponding remote proxy replica. For example, new proxy replicas require all information about the master replica. This includes its
, and construction metadata.
Previously synchronized proxy replicas require only the information from the master replica that is different, including any pending RPC calls.
Unmarshaling: Receiving Data from Other Peers
In unmarshaling, the replica manager communicates with the remote peers, receives and parses new data from them, and updates its own replicas accordingly. These updates can include accepting new peers, instantiating new proxy replicas, handling ownership changes, or destroying proxy replicas.
Note
For more information about marshaling, see Marshalling (p. 1027) .
Update from Replica: Updating Proxy Replicas
A change in a custom
results in an
UpdateFromChunk
callback that causes all proxy replicas to update their state. RPCs from proxy and master replicas are processed and invoked during this step.
Update Replicas: Updating Master Replicas Locally
A change in a custom replica chunk results in an
UpdateChunk
callback that causes all master replicas on a local peer to update their states.
The replica manager holds two task manager instances: one for updating and one for marshaling replicas. Updating tasks are executed within the replica manager's
UpdateFromReplica
step, while marshaling tasks are executed in the
Marshal
step. Tasks can execute other tasks while running.
TaskManager::Add
queues the tasks in an ordered list.
TaskManager::Wait
executes a task and waits until it finishes. When an event fires in the replica system, replica manager adds the corresponding task into
TaskSystem
.
Here are few examples of this behavior:
• A user changes a dataset's value within a replica. The change needs to be marshaled to other peers.
The
OnReplicaChanged
event is called on
ReplicaManager
, and
ReplicaMarshalTask
is queued for execution. Because replicas must be sent in the order of their creation, the task's priority is based on the replica's creation time. The queued task is executed at the appropriate time within the
Marshal step.
• A new proxy replica is unmarshaled. When this happens,
OnReplicaUnmarshaled()
is called and
ReplicaUpdateTask
is queued. This task's priority is always zero because the order of execution is not important.
UpdateFromReplica
is called to notify the user of the new replica's data.
Lumberyard's GridMate networking system offers many ways to improve your game:
• Synchronize game state by using components or scripts.
Version 1.10
1051
Lumberyard Developer Guide
Synchronizing Game State Using Components
• Use encryption for enhanced security.
• Control bandwidth.
• Take advantage of powerful features that enable you to create a professional-grade game.
Topics
•
Synchronizing Game State Using Components (p. 1052)
•
Synchronizing Game State Using Scripts (p. 1058)
•
•
•
Controlling Bandwidth Usage (p. 1065)
•
Using Bit Packing in Lumberyard Networking (p. 1067)
•
•
Creating Dedicated Servers (p. 1069)
•
Using the TCP Stream Driver (p. 1070)
•
Using Amazon GameLift (p. 1072)
•
Useful Console Commands (p. 1073)
The network binding API in the AZ framework provides a way for components to synchronize their states over the network.
To enable network synchronization for a component, you must do the following:
1. Derive the component from
NetBindable
and implement the network binding interfaces.
2. Implement a new replica chunk type and add the datasets and RPCs necessary to provide synchronization.
Topics
•
Synchronizing an Entity with a NetBindingComponent (p. 1052)
•
Binding Process on Remote Nodes (p. 1052)
•
•
NetBindable Component Flexibility (p. 1053)
•
•
Creating a NetBindable Component (p. 1054)
Because a special
NetBindingComponent
is responsible for the actual binding process, entities that need to be synchronized must have a
NetBindingComponent
added to them. When a game enters a multiplayer session, the
NetBindingComponent
collects replica chunks from the
NetBindable
instances on the entity and adds them to a Replica master. A special
NetBindingChunk
captures and stores spawning and other binding information for the entity.
NetBindingComponent
instances activated during a multiplayer session automatically start the binding process.
As replicas arrive at remote nodes,
NetBindingChunk
starts the entity spawning and binding process on the remote node. The binding process is completely asynchronous. The replicas become active first. Then
Version 1.10
1052
Lumberyard Developer Guide
Synchronizing Game State Using Components an entity spawn request is queued. After the entity becomes available, its
NetBindable
components are bound to their corresponding chunks. Finally, the entity is activated.
When replicas are removed, affected
NetBindingComponent
instances start the unbinding process. By default, entities that are unbound from proxy replicas are deleted, but this doesn’t have to be always the case. A game can choose to keep all entities in place and seamlessly switch to single-player mode.
A
NetBindingComponent
must exist for an entity to be bound to the network. This allows
NetBindable components to be used in single-player modes without any additional runtime cost.
NetBindable instances can also be disabled for each instance. This gives you the additional flexibility: The transform component can provide entity transform synchronization by default, but for special entities, a physics or animation component can provide more advanced synchronization.
In Lumberyard, every entity has a unique ID so that it can be referenced in the game. Entity IDs are 64bit strings generated using an algorithm that ensures uniqueness across computing devices. To reduce binding complexity, the net binding system spawns entities to be bound to proxy replicas using the same
ID as the master.
The following diagram shows how the net binding system binds an entity to the network and spawns an entity. It does this with the same ID that it binds to a proxy replica.
Version 1.10
1053
Lumberyard Developer Guide
Synchronizing Game State Using Components
For a Lumberyard component to share data on the network, it must include the
NetBindingComponent
.
The
NetBindingComponent
for the component and can bind any replica chunk (p. 1042) that a component creates to the replica.
To enable networking on a component
1. Inherit the component from
AzFramework::NetBindable
:
#include <AzFramework/Network/NetBindable.h> class ShipComponent
: public Component
, public AzFramework::NetBindable
2. Modify the
AZ_COMPONENT
definition to include
AzFramework::NetBindable
:
AZ_COMPONENT(ShipComponent,"{D466FD68-96C9-45AF-8A89-59402B0350F7}",
AzFramework::NetBindable);
3. Modify
SerializeContext
to include
AzFramework::NetBindable
: if (serialize)
{ serializeContext->Class<ShipComponent, AzFramework::NetBindable, AZ::Component>()
...
}
4. Implement the
AzFramework::NetBindable
interfaces:
// Called during network binding on the master. Implementations should create and
return a new binding.
virtual GridMate::ReplicaChunkPtr
GetNetworkBinding
() = 0;
// Called during network binding on proxies.
virtual void
SetNetworkBinding
(GridMate::ReplicaChunkPtr chunk) = 0;
// Called when network is unbound. Implementations should release their references to
the binding.
virtual void
UnbindFromNetwork
() = 0;
Notes
• If the
AZ_COMPONENT
definition change is missing, the
NetBindingComponent
does not recognize the component when it checks for components to add to the replica.
• If the
SerializeContext
definition is missing, the master replica still functions correctly. However, the proxy cannot match the IDs because it is not serialized as an
AzFramework::NetBindable
interface.
• Changes to these definitions require a re-export of levels for the static IDs to match correctly.
Network Binding Function Details
The following functions are available for working with component entities on the network.
Version 1.10
1054
Lumberyard Developer Guide
Synchronizing Game State Using Components
GetNetworkBinding
The component uses this function to create its
ReplicaChunk
and initialize any state it wants to synchronize across the session. This function is called only on the master
ComponentEntity
. The
ReplicaChunk
that is returned is automatically attached to the appropriate
Replica
.
SetNetworkBinding
This function passes a
ReplicaChunk
to the component and initializes the internal data of the component to match that of the
ReplicaChunk
. This function is called only on the proxy
ComponentEntity
instances that are already bound to an appropriate
Replica
.
UnbindFromNetwork
The
UnbindFromNetwork
function is called to stop the component from reacting to data updates from the network. This can happen, for example, when the master no longer exists, has been deactivated, or has relinquished control to the local source.
Creating a Chunk
After you have enabled the
NetBindable
interface on the
component
, you must create a
ReplicaChunk object that will store any state that the component wants to share.
class ShipComponentReplicaChunk : public GridMate::ReplicaChunkBase
{ public:
AZ_CLASS_ALLOCATOR(ShipComponentReplicaChunk, AZ::SystemAllocator, 0);
static const char* GetChunkName() { return "ShipComponentReplicaChunk"; }
ShipComponentReplicaChunk()
: SetFiring("SetFireLaser")
, m_playerEntityId("PlayerEntityId")
{
}
bool IsReplicaMigratable()
{
return true;
}
GridMate::Rpc< GridMate::RpcArg<bool> >::BindInterface<ShipComponent,
&ShipComponent::SetFiringRPC, NetworkUtils::ShipControllerRPCTraits> SetFiring;
GridMate::DataSet<AZ::EntityId>::
BindInterface
<ShipComponent,
&ShipComponent::OnNewNetPlayerEntityId> m_playerEntityId;
};
Note
You must reflect this new replica chunk's datasets and RPCs in the component's
Reflect function.
AzFramework::NetworkContext* netContext =
azrtti_cast<AzFramework::NetworkContext*>(context); if (netContext)
{
netContext->Class<ShipComponent>()
->Chunk<ShipComponentReplicaChunk>()
->RPC<ShipComponentReplicaChunk, ShipComponent>("SetFireLaser",
&ShipComponentReplicaChunk::SetFiring)
->Field("PlayerEntityId", &ShipComponentReplicaChunk::m_playerEntityId)
;
Version 1.10
1055
Lumberyard Developer Guide
Synchronizing Game State Using Components
}
In order for the component to react to a change in the
DataSet
object, one of the following must occur:
• The replica chunk must signal to the component when the change occurs (in the example, this is done using the
BindInterface
extension to
DataSet
).
• The component must poll the replica chunk and check the
DataSet
object for changes.
Example: Filling Out the AzFramework::NetBindable Interface
The examples below illustrate the use of
GetNetworkBinding
,
SetNetworkBinding
and
UnbindFromNetwork
.
GetNetworkBinding
In the following example, the component creates the new replica chunk and initializes the data to be networked. This function is called by the master replica to retrieve the binding from the component.
GridMate::ReplicaChunkPtr ShipComponent::GetNetworkBinding()
{
ShipComponentReplicaChunk* replicaChunk =
GridMate::CreateReplicaChunk<ShipComponentReplicaChunk>();
replicaChunk->SetHandler(this);
m_replicaChunk = replicaChunk;
return m_replicaChunk;
}
SetNetworkBinding
In the following example, the component is bound to the supplied replica chunk. It also relinquishes its local state to the state specified by the replica chunk. This function is called on proxies to hand their binding over to the component.
void ShipComponent::SetNetworkBinding(GridMate::ReplicaChunkPtr chunk)
{
chunk->SetHandler(this);
m_replicaChunk = chunk;
ShipComponentReplicaChunk* shipControllerChunk =
static_cast<ShipComponentReplicaChunk*>(m_replicaChunk.get());
SetPlayerEntityIdImpl(shipControllerChunk->m_playerEntityId.Get());
}
UnbindFromNetwork void ShipComponent::UnbindFromNetwork()
{
m_replicaChunk->SetHandler(nullptr);
m_replicaChunk = nullptr;
}
Maintaining State
The last step is to create checks to make sure that any local modifications to the preferred networkable state do not overwrite the networked state. In addition, you must update the replica chunk whenever the local state changes and the component is in control of the state.
Version 1.10
1056
Lumberyard Developer Guide
Synchronizing Game State Using Components void ShipComponent::OnNewNetPlayerEntityId(const AZ::EntityId& playerEntityId, const
GridMate::TimeContext& tc)
{
(void)tc;
SetPlayerEntityIdImpl(playerEntityId);
} bool ShipComponent::SetFiringRPC(bool firing, const GridMate::RpcContext& rpcContext)
{
if (AllowRPCContext(rpcContext))
{
SetFiring(firing);
}
return false;
}
// Component implementation of to set firing void ShipComponent::SetFiring(bool firing)
{
m_isFiring = firing;
if (!AzFramework::NetQuery::IsEntityAuthoritative(GetEntityId()))
{
// If the ship component is not authoritative, send an RPC update to the replica
chunk
ShipComponentReplicaChunk* shipChunk =
static_cast<ShipComponentReplicaChunk*>(m_replicaChunk.get());
shipChunk->SetFiring(firing);
}
else
{
if (m_isFiring)
{
EBUS_EVENT_ID(GetGun(), ShipGunBus, StartFire);
}
else
{
EBUS_EVENT_ID(GetGun(), ShipGunBus, StopFire);
}
}
} void ShipComponent::SetPlayerEntityIdImpl(AZ::EntityId playerEntityId)
{
AZ_Error("ShipControllerComponent",!m_playerEntityId.IsValid() || !
playerEntityId.IsValid(),"Trying to rebind an already bound ship");
if (m_playerEntityId != playerEntityId)
{
m_playerEntityId = playerEntityId;
HandleShipSetup();
if (m_replicaChunk && AzFramework::NetQuery::IsEntityAuthoritative(GetEntityId()))
{
// If you are authoritative over the entity and the component is replicated,
update the value of the DataSet and propagate to clients
ShipComponentReplicaChunk* shipChunk =
static_cast<ShipComponentReplicaChunk*>(m_replicaChunk.get());
shipChunk->m_playerEntityId.Set(m_playerEntityId);
}
}
}
Version 1.10
1057
Lumberyard Developer Guide
Synchronizing Game State Using Scripts
You can synchronize game state by using the Lua
ScriptComponent
. The initial steps of synchronizing game state using the Lua
ScriptComponent
are similar to any other component. There are two main steps:
1. You must add a
NetBindingComponent
to the definition of the entity that contains the script and the
ScriptComponent
and whose state you want to synchronize.
2. Inside the script, any properties that need to be synchronized must be tagged accordingly. For more
information, see Network Binding (p. 626) in the
Writing Lua Scripts (p. 620) topic.
When these steps are completed, your game state data should synchronize correctly.
GridMate uses the OpenSSL implementation of Datagram Transport Layer Security (DTLS) to support encryption of all UDP traffic sent between clients and servers.
GridMate's implementation of encryption has the following limitations:
• Only 64-bit Windows is supported.
• Only client-server topologies are supported.
GridMate supports encryption for the following implementations:
• Server and client authentication
• Self-signed certificates
• A single strong OpenSSL cipher
GridMate uses the following single OpenSSL cipher for all encrypted connections:
ECDHE-RSA-AES256-
GCM-SHA384
.
This cipher uses the technologies listed in the following table:
Cipher Technologies in GridMate
Technology
ECDHE
RSA
AES256
Role
Master key exchange
Description
Ephemeral Elliptic Curve Diffie-Hellman anonymous key agreement protocol
RSA algorithm used to authenticate client and server Peer authentication
Symmetric encryption cipher Advanced Encryption Standard that uses a 256-bit master key
GCM Block cipher mode of operation
Galois/Counter Mode authenticated encryption algorithm
Version 1.10
1058
Lumberyard Developer Guide
Using Encyrption
Technology Role
SHA384 Hashing algorithm
Description
SHA-2 with a 384-bit digest size
Topics
•
Building with Encryption (p. 1059)
•
When you include the GridMate library in your project, encryption support is automatically provided.
However, because the GridMate library is statically linked, you must first make some modifications to the
WAF build script (wscript) that uses GridMate.
Building Your Project with Encryption
To use encryption with GridMate, you must modify your
.wscript
file to add a dependency on GridMate, link the OpenSSL library, and specify OpenSSL library paths.
To modify your .wscript file to use OpenSSL with GridMate
1. Add the following line to create a dependency on GridMate: use = ['GridMate']
2. Add the following line to link the OpenSSL library: win_lib = ['ssleay32', 'libeay32']
3. Add the OpenSSL library paths, as in the following example. Within the Lumberyard install directory, these paths are in the folder dev\Code\SDKs\OpenSSL\lib\
: win_x64_debug_libpath = [ bld.Path('Code/SDKs/OpenSSL/lib/vc120_x64_debug') ], win_x64_profile_libpath = [ bld.Path('Code/SDKs/OpenSSL/lib/vc120_x64_release') ], win_x64_release_libpath = [ bld.Path('Code/SDKs/OpenSSL/lib/vc120_x64_release') ], win_x64_debug_dedicated_libpath = [ bld.Path('Code/SDKs/OpenSSL/lib/ vc120_x64_debug') ], win_x64_profile_dedicated_libpath = [ bld.Path('Code/SDKs/OpenSSL/lib/ vc120_x64_release') ], win_x64_release_dedicated_libpath = [ bld.Path('Code/SDKs/OpenSSL/lib/ vc120_x64_release') ]
Building Without Encryption
If your project uses GridMate, but does not require support for encryption, ensure that the
GridMateForTools
line is in your
.wscript
file: use = ['GridMateForTools']
To enable encryption with OpenSSL in a GridMate session, perform the following steps.
Version 1.10
1059
Lumberyard Developer Guide
Using Encyrption
To enable encryption in a GridMate session
1. To set the encryption parameters, create an instance of
SecureSocketDesc
. The parameters are described in
2. Create an instance of
SecureSocketDriver
that passes in the instance of
SecureSocketDesc
. The instance of
SecureSocketDesc
must be available for the duration of the GridMate session.
3. Before hosting or joining a GridMate session, define
CarrierDesc
by setting the
CarrierDesc::m_driver
property to the instance of
SecureSocketDriver
. If no instance of
SecureSocketDriver
is provided, an unencrypted driver is used that provides plaintext communication.
4. You can delete the
SecureSocketDriver
instance at the end of the GridMate session, ideally in the
OnSessionDelete
event on the
SessionEventBus
.
The
GridMate Session Encryption Example (p. 1061)
at the end of this topic has sample code for these steps.
SecureSocketDesc
The constructor for
SecureSocketDriver
requires a
SecureSocketDesc
object that provides all encryption configuration required for the secure connection. The configuration parameters are described in the following table.
SecureSocketDesc Configuration Parameters
Parameter
m_privateKeyPEM
Description
Base-64 encoded string PEM private key.
m_certificatePEM m_certificateAuthorityPEM m_authenticateClient
Base-64 encoded string PEM public certificate.
Base-64 encoded string PEM certificate authority.
If set to 1, the client is expected to provide a signed certificate for authentication. To implement this, m_certificatePEM
must be set on the client, and the server needs to set up m_certificateAuthorityPEM
.
The default setting is 0.
Server Authentication Only
You can use the server authentication only configuration when the client needs to verify the authenticity of the server to which it connects. The server has a secret private key and a public certificate signed by a certificate authority. This is the most common configuration.
Server Authentication Only Configuration
Role
Client
Parameters
Server m_certificateAuthorityPEM m_privateKeyPEM
, m_certificatePEM
, m_certificateAuthorityPEM
Client and Server Authentication
Use this configuration when the client must verify authenticity of the server and the server must verify authenticity of the client. The client has its own unique private key and corresponding signed public certificate. The server has its own unique private key and corresponding signed public certificate.
Version 1.10
1060
Lumberyard Developer Guide
Using Encyrption
It's possible to share or use the same certificate authority for both, but keys and certificates must be unique to each peer.
Client and Server Authentication Configuration
Role
Client
Server
Parameters
m_privateKeyPEM
, m_certificatePEM
, m_certificateAuthorityPEM m_privateKeyPEM
, m_certificatePEM
, m_certificateAuthorityPEM
Self-signed Certificates
You can use self-signed certificates for development purposes.
Warning
Do not use self-signed certificates for production environments.
When you use self-signed certificates, there is no certificate authority to sign the public certificates.
To permit the absence of a certificate authority, set m_certificateAuthorityPEM
to the same value as m_certificatePEM
.
GridMate Session Encryption Example
The following code snippet enables encryption in a GridMate session.
class MyClass : public GridMate::SessionEventBus::Handler
{ public:
void OnSessionDelete(GridMate::GridSession* session) override; private:
GridMate::SecureSocketDriver* m_secureDriver;
}; void MyClass::JoinSession() {
// ...
// Create an instance of SecureSocketDesc and set its encryption parameters.
GridMate::SecureSocketDesc secureDesc;
secureDesc.m_privateKeyPEM = "..."
secureDesc.m_certificatePEM = "..."
secureDesc.m_certificateAuthorityPEM = "..."
// Create an instance of SecureSocketDriver that passes in the instance of
// SecureSocketDesc.
m_secureDriver = new GridMate::SecureSocketDriver(secureDesc);
// Before hosting or joining a GridMate session, set the CarrierDesc::m_driver
// property to the instance of SecureSocketDriver.
carrierDesc.m_driver = m_secureDriver;
// ...
}
// At the end of the GridMate session, delete the SecureSocketDriver instance in
// the OnSessionDelete event. void MyClass::OnSessionDelete(GridMate::GridSession* session) {
// ...
delete m_secureDriver;
m_secureDriver = nullptr;
Version 1.10
1061
Lumberyard Developer Guide
HttpRequestor Gem
// ...
}
How To Generate a Private Key and Public Certificate
You can use the openssl req
command to generate a self-signed certificate from OpenSSL, as in the following example.
dev/Code/SDKs/OpenSSL/bin/openssl req -x509 -newkey rsa:2048 -keyout key.pem -out cert.pem
-days 365 -nodes
The arguments are as follows.
•
-x509
– The certificate format.
•
-newkey
– The type of key. This example generates an RSA key with 2048 bits.
•
-keyout
– The name of the key PEM file that will be generated
•
-out
– The name of the cert PEM file that will be generated.
Upon execution, the command prompts for additional user input required to generate the certificate.
You can use the HttpRequestor Gem to make asynchronous HTTP/HTTPS requests and return data
through a user-provided call back function. This gem uses EBuses (p. 576)
for communication and provides all requests asynchronously.
Note
This feature is only supported on Windows and replaces
CryAction::HttpRequest
.
In order to use the HttpRequestor Gem, you must enable it in your project.
To enable the HttpRequestor Gem
1. In Project Configurator , find your project in the list, and then click
Enable Gems
.
2. In the list of gems, select the checkbox next to
HttpRequestor
.
3. Click
Save
.
4. Type the following command to rebuild your project.
lmbr_waf configure
The HttpRequestor Gem has separate sets of APIs for adding requests and adding text requests.
AddRequest, AddRequestWithHeaders, AddRequestWithHeadersAndBody
You can use the
AddRequest
,
AddRequestWithHeaders
, and
AddRequestWithHeadersAndBody
APIs to send generic HTTP requests to any website and receive the return data in JSON format. The methods return the data received in the callback
parameter.
Version 1.10
1062
Lumberyard Developer Guide
HttpRequestor Gem
Syntax
EBUS_EVENT(HttpRequestor::HttpRequestorRequestBus,
AddRequest
, URI, method, callback)
EBUS_EVENT(HttpRequestor::HttpRequestorRequestBus,
AddRequestWithHeaders
, URI, method,
headers, callback)
EBUS_EVENT(HttpRequestor::HttpRequestorRequestBus,
AddRequestWithHeadersAndBody
, URI,
method, headers, body, callback)
Each of the add request methods requires the URI, a method and a callback.
Parameters
Description
URI AZStd::String
The fully qualified web address, in the form of scheme:[//
[user:password@]host[:port]][/]path[?query][#fragment] method
The method type, only supported values are
HTTP_GET
,
HTTP_POST
,
HTTP_DELETE
,
HTTP_PUT
,
HTTP_HEAD
, and
HTTP_PATCH
.
callback
This function is called when the HTTP request has completed. The response body and code are present in the callback.
body AZStd::String
Optional body to send with the request.
Return: No return value.
JSON Request Callback
This callback is returned for the
AddRequest
,
AddRequestWithHeaders
, and
AddRequestWithHeadersAndBody
methods.
void Callback(const
Aws::Utils::Json::JsonValue& json
, Aws::Http::HttpResponseCode
responseCode);
Parameters
Parameter
json
Type
Aws::Utils::Json::JsonValue
Aws::Http::HttpResponseCode
Description
The JSON object. The life span of this object is valid only during the scope of the callback.
The HTTP response code.
responseCode
Return: No return value.
Version 1.10
1063
Lumberyard Developer Guide
HttpRequestor Gem
AddTextRequest, AddTextRequestWithHeaders,
AddTextRequestWithHeadersAndBody
You can use the
AddTextRequest
,
AddTextRequestWithHeaders
, and
AddTextRequestWithHeadersAndBody
APIs to send a generic HTTP request to any website and receive the return data in a text string. The methods return the data received in the callback
parameter.
Syntax
EBUS_EVENT(HttpRequestor::HttpRequestorRequestBus,
AddTextRequest
, URI, method, callback)
EBUS_EVENT(HttpRequestor::HttpRequestorRequestBus,
AddTextRequestWithHeaders
, URI, method,
headers, callback)
EBUS_EVENT(HttpRequestor::HttpRequestorRequestBus,
AddTextRequestWithHeadersAndBody
, URI,
method, headers, body, callback)
Each of the add text request methods requires the URI, a method and a callback.
Parameters
ParameterType
URI AZStd::String
Description
The fully qualified web address, in the form of scheme:[//
[user:password@]host[:port]][/]path[?query][#fragment] method
The method type. Supported values are
HTTP_GET
,
HTTP_POST
,
HTTP_DELETE
,
HTTP_PUT
,
HTTP_HEAD
, and
HTTP_PATCH
.
callback
This function is called when the HTTP request has completed. The response body and code are present in the callback.
body AZStd::String
Optional body to send with the request.
Return: No return value.
Text Request Callback
This callback is returned for
AddTextRequest
,
AddTextRequestWithHeaders
,
AddTextRequestWithHeadersAndBody
methods.
void Callback(const
AZStd::string&
response, Aws::Http::HttpResponseCode responseCode);
Parameters
Parameter
response
Type
AZStd::string&
Description
The text returned from the server. The life span of this object is valid only during the scope of the callback.
Version 1.10
1064
Lumberyard Developer Guide
Controlling Bandwidth Usage
Description Parameter Type
Return: No return value.
The following example uses the Metastream C++ API to to obtain a gateway IP address.
EBUS_EVENT(HttpRequestor::HttpRequestorRequestBus,
AddRequest
, "https://httpbin.org/ip",
Aws::Http::HttpMethod::HTTP_GET, [this](AXStd::string && data, Aws::Http::HttpResponseCode
code)
{
AZStd::string resultData = std::move(data);
resultCode = code;
/* Upon success:
** resultCode = Aws::Http::HttpResponceCode::Ok
** resultData = "{"origin": "xxx.xxx.xxx.xxx"}" /* Your IP will be displayed */
*/
}));
GridMate (p. 1004) provides several ways to control the bandwidth that your game uses, including
bandwidth throttling and the prioritization of replica (p. 1039) updates.
You can use GridMate to control the server send rate, which is a common technique for reducing bandwidth usage in multiplayer games. In this scenario, a multiplayer game is hosted by a dedicated server to which clients send their replica changes at their default rate (for example, 60 frames per second). To reduce bandwidth usage, you lower the server send rate (for example, to 20 transmissions per second). To avoid jitter when this technique is used, the client must be able to interpolate the game state that it receives from the server.
To control the server send rate in GridMate, set the time interval for replica data transmissions:
ReplicaMgr* replicaManager = session->GetReplicaMgr(); // Get the replica manager instance.
This assumes the session has been established.
replicaManager->
SetSendTimeInterval
(100); // Set the send interval to 100 milliseconds. 10
updates per second will be sent.
Setting the
SetSendTimeInterval
to
0
sends the data at the engine's frame rate. The default is
0
.
Another technique is to limit outgoing bandwidth in exchange for increased latency in the replication of objects. In GridMate, you can do this by setting a bandwidth limit on replica manager. To do so, specify a byte limit for
SetSendLimit
, as in the following example:
ReplicaMgr* replicaManager = session->GetReplicaMgr(); // Get the replica manager instance.
This assumes the session has been established.
Version 1.10
1065
Lumberyard Developer Guide
Controlling Bandwidth Usage replicaManager->
SetSendLimit
(10000); // Set the transmission limit to 10 kilobytes per
second.
Setting
SetSendLimit
to
0
disables the bandwidth limiter. The default is
0
.
You can use the GridMate limiter to accommodate short bursts in bandwidth if your bandwidth usage is not already at its maximum. This can be useful in many game applications. For example, when a user is in a multiplayer lobby, the corresponding bandwidth usage is quite low. However, when the user joins the game, the bandwidth usage spikes as the initial game state replicates from the server to the client. To control the length of the burst permitted, specify the desired number of seconds for
SetSendLimitBurstRange
, as in the following example:
ReplicaMgr* replicaManager = session->GetReplicaMgr(); // Get the replica manager instance.
This assumes the session has been established.
replicaManager->
SetSendLimitBurstRange
(5.f); // Set the maximum permitted length of the
burst to 5 seconds.
Bursts in bandwidth usage are allowed for the number of seconds specified, after which the bandwidth is capped to the value set by
SetSendLimit
. The default value for
SetSendLimitBurstRange
is 10 seconds.
If bandwidth usage has already reached its limit when the burst occurs, bandwidth usage continues to be capped, and the
SetSendLimitBurstRange
setting has no effect.
from
0
through
65534
. Larger integers represent higher priorities. Replicas with higher priorities are sent first. The default is
32768
.
This prioritization is especially important when you use the bandwidth limiter because you can use it to define which objects are more important and which are less important. If your game has a bandwidth cap and you have prioritized your replicas appropriately, the objects with higher priority are sent more often. The objects with lower priority are sent only when there is enough bandwidth to accommodate them.
For convenience, GridMate provides five predefined priorities that you can use for custom replica chunks: static const ReplicaPriority
k_replicaPriorityHighest
= 0xFFFE; // Decimal 65534, highest
priority.
static const ReplicaPriority
k_replicaPriorityHigh
= 0xC000; // Decimal 49152, high
priority.
static const ReplicaPriority
k_replicaPriorityNormal
= 0x8000; // Decimal 32768, normal
priority. This is the Default.
static const ReplicaPriority
k_replicaPriorityLow
= 0x4000; // Decimal 16384, low
priority.
static const ReplicaPriority
k_replicaPriorityLowest
= 0x0000; // Decimal 0, lowest
possible priority.
By default, all chunks have normal priority (
k_replicaPriorityNormal
). You can use these predefined priorities as is, or use them to create your own, as in the following example:
// A replica chunk with this priority will be sent before all the chunks with Normal
priority, but after all the chunks with High priority:
Version 1.10
1066
Lumberyard Developer Guide
Using Bit Packing const ReplicaPriority k_myCustomPriority = (
k_replicaPriorityNormal
+
k_replicaPriorityHigh
) / 2; // (=Decimal 40960)
The priority for the whole replica is the maximum priority found in its chunks. Priority for a chunk can be set after the chunk is created, or at any point during its lifetime, as in the following example:
MyChunk::Ptr myChunk = GridMate::CreateReplicaChunk<MyChunk>(...); myChunk->SetPriority(
k_replicaPriorityLow
); // Sets low priority for myChunk.
Chunks with the same priority are sent and received in the order of their creation. Replicas created earlier are sent and received first.
You can tune bandwidth usage while the game is running by using the following configuration variables
(CVars):
CVar Description
The time, in milliseconds, between replica transmissions. A value of 0 binds the interval to the GridMate tick rate.
The limit, in bytes, of the amount of replica data that can be sent per second. A value of 0 disables the limit.
gm_burstTimeLimit
The time, in seconds, that bursts in bandwidth are allowed. Bursts are allowed only if the bandwidth is not capped when the burst occurs.
Most built-in C++ types use more than one byte in memory. Even a Boolean value uses one byte. On some platforms, it can use more. However, the Lumberyard networking system, GridMate, optimizes networking traffic by tightly packing your data into the network payload.
GridMate is intelligent enough to pack a Boolean value into a single bit. For example, if a replica chunk contains several Boolean fields, each field uses a single bit during network transmission. In the following example, GridMate serializes the payload for
MyChunk
into just three bits.
class MyChunk : public ReplicaChunk
{
...
public:
......DataSet<bool> m_field1; // This field occupies only one bit.
......DataSet<bool> m_field2; // This field occupies only one bit.
......DataSet<bool> m_field3; // This field occupies only one bit.
};
Tip
Using
AZStd::bitset
is unnecessary and is often less efficient. Because
AZStd::bitset
writes its payload in full bytes, packing one Boolean or eight Booleans into
AZStd::bitset
takes a whole byte. It is better to use
DataSet<bool>
instead of
DataSet<AZStd::bitset>
.
Version 1.10
1067
Lumberyard Developer Guide
Using Bit Packing
The following steps show you how to implement bit packing for a custom class.
1. Declare an Integer Variable That Uses Only the Required Number of Bits
If you have some custom types that you want to pack efficiently, declare an integer variable that uses only the required number of bits. The following simple example declares a flags
variable for storing flags in a bit field.
struct CustomClass
{
int flags : 4; // C declaration of an integer value that uses only 4 bits.
};
2. Provide a Custom Marshaler
For best results, provide a custom marshaler as in the following example: class MarshalerCustomClass
{ public: void Marshal(WriteBuffer& wb, const CustomClass& value) const
{
AZ::u8 tmp = value.flags;
wb.WriteRaw(&tmp, { 0, 4 }); // Writes 4 bits and 0 bytes from 'tmp'.
} void Unmarshal(CustomClass& value, ReadBuffer& rb) const
{
AZ::u8 tmp;
rb.ReadRaw(&tmp, { 0, 4 }); // Reads just 4 bits and no full bytes.
value.flags = tmp;
};
3. Pass the Marshaler Type as a
DataSet
Argument
Now, when you declare a
DataSet
for a
CustomClass
variable, you can simply pass the marshaler type into the template arguments for
DataSet
. The following example shows the syntax.
DataSet<CustomClass, MarshalerCustomClass> m_value;
In this implementation, the example uses a total of only 4 bits to serialize
CustomClass
.
4. Read and Write Data at the Bit Level
The following example shows how
ReadBuffer
supports direct control over reading data at the bit level.
bool ReadBuffer::ReadRaw(void* source, PackedSize size);
// PackedSize is a special type that you can use to define granularity at the bit level.
// For example PackedSize(0, 1) means 1 bit.
// PackedSize(4, 5) means 4 bytes and 5 bits.
// PackedSize(10) means 10 bytes.
The
WriteBuffer
method has the same capability. The following example uses both the
ReadBuffer
and
WriteBuffer
methods.
/*
Version 1.10
1068
Lumberyard Developer Guide
Setting up a Lobby
* This example takes advantage of the bit packing feature in GridMate.
*/ struct CustomClass3
{
int flags : 7; // Uses only seven bits.
bool b; // Uses only one bit.
};
/*
* Marshaler for PackedSize objects.
*
* Note that PackedSize::additionalBits requires only 3 bits because it has a range of
[0..7].
*/ class MarshalerCustomClass3
{ public:
void Marshal(WriteBuffer& wb, const CustomClass3& value) const
{
AZ::u8 tmp = value.flags;
wb.WriteRaw(&tmp, { 0, 7 });
wb.WriteRawBit(value.b);
}
void Unmarshal(CustomClass3& value, ReadBuffer& rb) const
{
AZ::u8 tmp;
rb.ReadRaw(&tmp, { 0, 7 });
value.flags = tmp;
rb.ReadRawBit(value.b);
}
};
//////
DataSet<CustomClass3, MarshalerCustomClass3> m_field;
By default, the Lumberyard engine does not provide any specific lobby implementation, but instead provides the code interface required to construct one. The Multiplayer Gem does, however, provide some useful constructs that aid in lobby creation using flow graph nodes , and a basic lobby implementation using Components , that can be used as is, or as a reference.
For more information, see the Multiplayer Gem Documentation .
In Lumberyard, you can create a build of your game that runs on a headless dedicated server. A dedicated server build omits the packages and modules that a headless server does not require and has a smaller compiled size.
The package that you build for the dedicated server must include the resources that are required to run the game on the client. You can use Lumberyard's asset pipeline to exclude certain resources that are not needed on the server. For more information, see Configuring the Asset Pipeline .
Amazon GameLift splits sessions between client and server, but Lumberyard does not. Lumberyard recommends that you not compile critical server logic on clients or include client data in the server package.
Version 1.10
1069
Lumberyard Developer Guide
Using the TCP Stream Driver
To generate a dedicated server build that you can use locally or upload to Amazon GameLift, attach the
_dedicated
label to your build configuration in Waf. For more information on using Waf to set up the dedicated server, see Creating a Dedicated Server in the Amazon Lumberyard User Guide . The topic is part of the Multiplayer Sample , which includes an example of a dedicated server.
Lumberyard has a Linux version of the dedicated server. For information on how to compile and build dedicated server packages in Linux, see Linux Support .
To use the TCP stream socket driver, you specify connection parameters for internal buffers, a listening port, and the maximum number of connections.
After you construct the new stream driver, you can use the socket driver for server or client work. For server work, the driver can monitor for connections. For client work, the driver can connect to a server’s endpoint address and port.
To start accepting new connections on the server, call the
StartListen()
method. When new clients connect or disconnect, the socket driver sends events through the event bus.
During the setup for the carrier instance, call the
StartListen()
method for servers and the
ConnectTo() method for clients. You can do this before you assign the m_driver
member of the
CarrierDesc structure.
To construct a stream socket driver, specify the maximum number of connections (1 for clients), the maximum packet size, and the byte sizes for the internal buffers for inbound and outbound traffic.
To prepare the socket driver, use the
Initialize()
method with a socket family. IPv4 and IPv6 are supported. Specify binding parameters and socket buffer sizes. The driver uses internal buffers to spool streamed traffic during the
Update()
call. GridMate processes the
Update()
call when it is using the carrier instance.
Constructing the TCP Socket Driver
The following code example shows how to construct the TCP socket driver.
// Specify the maximum number of connections that the server accepts.
const AZ::u32 maxConnections = 32;
// Specify the largest packet to be sent.
const AZ::u32 maxPacketSize = 1024 * 64;
// Specify the size of the internal byte buffer that stores incoming bytes from the socket.
const AZ::u32 inboundBufferSize = 1024 * 64;
// Specify the size of the internal byte buffer that stores outbound bytes to the socket.
const AZ::u32 outboundBufferSize = 1024 * 64;
GridMate::StreamSocketDriver server(maxConnections, maxPacketSize, inboundBufferSize,
outboundBufferSize);
Note the following:
• The sizes are specified in bytes.
Version 1.10
1070
Lumberyard Developer Guide
Using the TCP Stream Driver
• The maximum packet size should be less than or equal to the outbound buffer size.
• Both buffer sizes are stored in application memory.
Initializing the Socket Driver
The following code example shows how to initialize the TCP socket driver.
// For IPv4, specify driver BSD_AF_INET. For IPv6, specify BSD_AF_INET6.
const AZ::s32 familyType = GridMate::Driver::BSD_AF_INET;
// Specify the address of the Ethernet card to bind to.
const char* address = "127.0.0.1";
// Specify the port for the server to monitor.
const AZ::u32 serverPort = 2017;
// Specify that TCP sockets cannot send broadcast packets.
const bool isBroadcast = false;
// Set the receive buffer size for each new socket.
const AZ::u32 receiveBufferSize = 1024 * 256;
// Set the send buffer size for each new socket.
const AZ::u32 sendBufferSize = 1024 * 64; server.Initialize(familyType, address, serverPort, isBroadcast, receiveBufferSize,
sendBufferSize);
Note the following:
• Both server and client have to use the same socket family
AF_*
type.
• The address can be nullptr
, which means bind to all the available network interfaces.
• The isBroadcast
flag is always set to false
, since a TCP socket is not able to send broadcast packets.
• The receive and send buffer size are specified in bytes and refer to the TCP stack’s buffer size for the socket.
An event bus handler instance monitors connection events from GridMate’s stream socket driver. The following code shows a simple stream socket event handler.
struct ConnectionHandler : public GridMate::StreamSocketDriverEventsBus::Handler
{
ConnectionHandler(GridMate::IGridMate* gridMate)
{
m_ConnectionCount = 0;
GridMate::StreamSocketDriverEventsBus::Handler::BusConnect(gridMate);
}
~ConnectionHandler()
{
m_ConnectionCount = -1;
GridMate::StreamSocketDriverEventsBus::Handler::BusDisconnect();
}
void OnConnectionEstablished(const SocketDriverAddress& address) override
{
m_ConnectionCount++;
}
void OnConnectionDisconnected(const SocketDriverAddress& address) override
{
Version 1.10
1071
Lumberyard Developer Guide
Using Amazon GameLift
m_ConnectionCount--;
}
bool DidConnect()
{
return m_ConnectionCount > 0;
}
AZ::s32 m_ConnectionCount;};
After you construct and initialize the stream socket driver, use the
StartListen()
method to instruct the server to accept clients. The
StartListen()
method takes a backlog
parameter that specifies the incoming connection request limit. The driver emits successful connections to its event bus.
When you are finished with the server process, but before you shut down GridMate, call the
StopListen()
method. To disconnect a client, you can use the
DisconnectFrom()
method on the server’s driver instance.
To connect a client to a server, create a socket driver address. To start the connection process, use the
ConnectTo()
method. When the stream socket driver establishes a connection to the server, it sends a connect event.
To disconnect from the server, the client code uses the
DisconnectFrom()
method. The driver sends a disconnect event when the server gracefully disconnects from the client.
To send and receive data from the stream driver, you use the
Send()
and
Receive()
methods just as you do with the UDP driver.
For both sending and receiving, the data
and data size
values should be equal to or greater than the maximum packet size. If the
Send()
method does not return
GridMate::Driver::EC_OK
, then the connection to the remote endpoint has been closed.
The
Receive()
method returns the number of bytes written to the data buffer. If it returns zero (0) bytes and returns a result code of
GridMate::Driver::EC_OK
, then no more packets are ready to be read.
Lumberyard supports hosting dedicated servers on the cloud by using Amazon GameLift. Amazon
GameLift is a managed AWS service for deploying, operating, and scaling session-based multiplayer games. Amazon GameLift is built on AWS’s highly available cloud infrastructure and allows you to quickly scale high-performance game servers up and down to meet player demand – without any additional engineering effort or upfront costs. It reduces the time required to build a multiplayer backend from thousands of hours to just minutes.
To use GameLift in your project, there are two options:
• Enable the GameLift Gem in your project. Lumberyard has integrated Amazon GameLift, which makes it easier for you to use GameLift.
• Enable the Lumberyard Multiplayer Gem in your project (which requires the GameLift Gem).
For information about configuring GameLift for the multiplayer sample, see Configuring the Multiplayer
Sample for Amazon GameLift (p. 1012) . For information about gems, see
Gems in the Amazon
Lumberyard User Guide . For more information about GameLift, see Amazon GameLift .
Version 1.10
1072
Lumberyard Developer Guide
Useful Console Commands
• Tutorial: Creating and connecting to a game session (pdf)
• Amazon GameLift - Creating game sessions and connecting (video)
• Amazon GameLift Developer Guide
• Amazon GameLift API Reference
Use the following commands in Lumberyard when working with a network server.
gm_debugdraw debug_draw_level
Sets the debug draw level. Accepts as a parameter a number whos bits represent the flags for the debug data to draw. For example, when set to 1, displays an overlay with GridMate network statistics and information.
The available bit flags come from the enum
DebugDrawBits
and are as follows: enum DebugDrawBits
{
Basic = BIT(0),
Trace = BIT(1),
Stats = BIT(2),
Replicas = BIT(3),
Actors = BIT(4),
EntityDetail = BIT(5),
Full = Basic | Trace | Stats | Replicas | Actors,
All = 0xffffffff,
};
gm_disconnectDetection
When set to 0, disables disconnect detection. This is useful when you are debugging a server or client and don’t want to be disconnected when stepping through code. The default value is 1.
gm_dumpstats
Write GridMate network profiling stats to file.
gm_dumpstats_file
The file to which GridMate profiling stats are written. The default is net_profile.log
.
gm_net_simulator
Activate GridMate network simulator to simulate latency, packet loss, bandwidth restrictions, and other conditions. For available options, type gm_net_simulator help
.
gm_setdebugdraw
Display an overlay with detailed GridMate networking statistics and information. A user-friendly helper command for
gm_debugdraw debug_draw_level
. Possible parameters are
Basic
,
Trace
,
Stats
,
Replicas
, and
Actors
.
gm_stats_interval_msec
Set the interval, in milliseconds, for gathering network profiling statistics. The default is 1000.
Version 1.10
1073
Lumberyard Developer Guide
CryNetwork Backward Compatibility
gm_tracelevel trace_level
Set the GridMate debugging trace verbosity level. The default is 0. The higher the value, the greater the verbosity. Typical values range from 1 to 3.
mpstart [
<local_port>
]
Starts a LAN session by initializing the network system and optionally setting the local UDP port that initializes the socket. The default port is 64090. To use the ephemeral port, set the port to 0.
This is useful if you want to connect to a server on the same computer as the client.
mphost
Create a session as host. The server listens for incoming connections on the port specified in mpstart
.
mpjoin [
<server_addr>
] [
<server_port>
]
Connect to a server at the optionally specified
<server_addr>
and
<server_port>
. The defaults are localhost
and
64090
, respectively.
map
<map_name>
Loads the level with the specified map name. Replace
<map_name>
with the name of the map you want to use. To view a list of available levels, type
map
, and then press the tab key.
mpdisconnect
Terminate the current game instance session.
mpstop
Terminate the multiplayer service.
CryNetwork has been deprecated and removed, and is no longer be supported in Lumberyard. There were several systems added to provide backwards compatibility for GridMate to the networked systems in CryEngine, namely remote method invocations, network serialization, and aspects. For more information, see the following sub topics.
Topics
•
•
Network Serialization and Aspects (p. 1077)
To send remote method invocations (RMIs), use the
InvokeRMI
function, which has the following syntax: void InvokeRMI( IRMIRep&
<rep>
, ParamsType&&
<params>
, uint32
<where>
, ChannelId
<channel>
= kInvalidChannelId );
Parameters
<rep>
Represents the remote function to be called (the RMI ID).
Version 1.10
1074
Lumberyard Developer Guide
RMI Functions
<params>
Specifies the parameters to pass into the remote function.
<where>
Specifies a flag that determines the category of clients to which the RMI will be sent. For information, see the
RMI Function Flags (p. 1075) section later in this document.
<channel>
Specifies specific clients to which the RMI will be sent, or specific clients to exclude. For information,
see the RMI Function Flags (p. 1075)
section later in this document.
The
IGameObject.h
file includes macros for declaring RMI classes (for example, those beginning with
DECLARE_SERVER_RMI_
<...>
). The different declaration types are as follows:
•
PREATTACH
– The RMI is attached at the top of the data update for the object. You can use this declaration type to prepare the remote entity for new incoming data.
•
POSTATTACH
– The RMI is attached at the bottom of the data update, so it is called after the data is serialized. You can use this declaration type to complete an action with the new data.
•
NOATTACH
– The RMI is not attached to a data update, so the RMI cannot rely on the data. You can use this declaration type for calls that don’t rely on data.
The order for RMIs is only applicable within an object and attachment type set.
For example, in the following ordered list, PLAYER RMI 1, 2, and 3 will arrive in that order; however, ITEM
RMI 1 might arrive before or after the following PLAYER RMIs:
• PLAYER RMI 1
• PLAYER RMI 2
• ITEM RMI 1
• PLAYER RMI 3
Using declaration types adds a layer of complication to the order of incoming data:
•
PREATTACH
– Messages are ordered within themselves.
•
POSTATTACH
– Messages are ordered within themselves.
•
NOATTACH
– Messages are ordered within themselves; however,
NOATTACH
can only fall on either side of the following diagram and never in between:
To specify the clients that will receive an RMI, replace the
<where>
parameter in the
InvokeRMI
function with one of the following flags.
Version 1.10
1075
Lumberyard Developer Guide
RMI Functions
Server RMIs eRMI_ToClientChannel
Sends an RMI from the server to a specific client. Specify the destination channel in the
<channel>
parameter.
eRMI_ToOwningClient
Sends an RMI from the server to the client that owns the actor.
eRMI_ToOtherClients
Sends an RMI from the server to all clients except the client specified. Specify the client to ignore in the
<channel>
parameter.
eRMI_ToRemoteClients
Sends an RMI from the server to all remote clients. Ignores the local client.
eRMI_ToOtherRemoteClients
Sends an RMI from the server to all remote clients except the remote client specified. Ignores the local client. The remote client to ignore is specified in the
<channel>
parameter.
eRMI_ToAllClients
Sends an RMI from the server to all clients.
Client RMIs eRMI_ToServer
Sends an RMI from the client to the server.
To define a function to be implemented as RMI, use the
IMPLEMENT_RMI #define
from
IGameObject.h
.
#define IMPLEMENT_RMI(cls, name)
The following example implements a new function called
Cl_SetAmmoCount
in the
CInventory
class to be used as a client-side RMI, taking one argument of type
TRMIInventory_Ammo
:
Class CInventory : public CGameObjectExtensionHelper<CIventory, IInventory>
{
// …
DECLARE_CLIENT_RMI_NOATTACH(Cl_SetAmmoCount, TRMIInventory_Ammo, eNRT_ReliableOrdered);
// …
};
IMPLEMENT_RMI(CInventory, Cl_SetAmmoCount)
{
// Game code:
TRMIInventory_Ammo Info(params);
IEntityClass* pClass = gEnv->pEntitySystem->GetClassRegistry()-
>FindClass(Info.m_AmmoClass.c_str());
If (pClass)
SetAmmoCount(pClass, Info.m_iAmount);
return true; // Always return true - false will drop connection
}
Version 1.10
1076
Lumberyard Developer Guide
Network Serialization and Aspects
The following line will invoke the function: pInventory->GetGameObject()->InvokeRMI(CInventory::Cl_SetAmmoCount(),
TRMIInventory_Ammo(“Pistol”, 10), eRMI_ToAllClients);
The following line will invoke the function: pInventory->GetGameObject()->InvokeRMI(CInventory::C1_SetAmmoCount(),
TRMIInventory_Ammo("Pistol", 10), eRMI_ToAllClients);
All objects that are intended to be synchronized over the network should have a function called
NetSerialize()
. In the
GameObject
, this appears as:
IGameObject::NetSerialize()
.
The
NetSerialize()
function uses a
TSerialize
object of type
ISerialize
to transform relevant data to a stream. The serialization uses different aspects and profiles to distinguish the various types of streams.
Note
Serialized data for a given aspect and profile must remain fixed. For example, if you serialized four floats, you must always serialize four floats.
You use aspects to logically group data together.
Aspects are defined as follows:
• eEA_GameClient
– Information sent from the client to the server, if the client has authority over the object.
• eEA_GameServer
– The normal server to client data stream.
•
Dynamic/Static
– Data that is constantly changing should be added to the
Dynamic
aspect. Objects that rarely change should be added to the
Static
aspect. Updates are not sent if only one value changes.
• eEA_Script
– Used where script network data is transported, including any script RMI calls.
• eEA_Physics
– Used where physics data is transported. It is not divided into client/server because it always uses the same path: (controlling-client) to serve other clients.
Profiles allow an aspect’s fixed format data to be different. There are potentially eight profiles per aspect, and they are only used for physics aspects (for example, switching between ragdoll and living entity).
Version 1.10
1077
Lumberyard Developer Guide
Physics Scripting Guide
This section describes the Physics system and how to interact with the physics engine.
To create a physical world object, you use the
CreatePhysicalWorld()
function. The
CreatePhysicalWorld()
function returns a pointer to the
IPhysicalWorld
interface. You then fill the world with geometries and physical entities. You control the entities with the functions described in this section. Some functions apply to almost all entities, while others apply to specific entity structures.
Other functions control how entities interact and how the world affects them.
The following sections describe these topics in detail:
Topics
•
Physics Scripting Guide (p. 1078)
•
•
•
Functions for Entity Structures (p. 1085)
•
•
Functions for World Entities (p. 1095)
When scripting physics, deciding on an appropriate threading strategy can be important. This topic offers physics scripting advice on threading and troubleshooting and provides some sample code.
When writing scripts that interact with physics, it is important to understand how the physics system processes requests. You can configure the physics system to run in several different ways, each with its own benefits and drawbacks. This guide covers the two most common configurations.
Version 1.10
1078
Lumberyard Developer Guide
Threading
Running the physics simulation on its own thread takes advantage of a machine's multiple cores and should lead to faster frame rates on physics-intensive games. However, this approach can make gameplay scripting more complex.
Note
This is the default configuration starting in Lumberyard 1.8.
The following diagram shows the relationships between the physics thread and main thread.
If a change request arrives when the simulation is busy, the request is queued and is processed the next time the simulation runs. If the simulation is idle, the change request is processed immediately.
Similarly, if a query is made when the simulation is busy, the response contains the state from the end of the last simulation. If the simulation is idle when the query is made, the response represents the true latest state.
In the diagram, note how
OnPrePhysicsUpdate
and
OnPostPhysicsUpdate
run between simulations. This means that requests are processed immediately and queries represent the true latest state. You should avoid performing time-consuming tasks in the
OnPrePhysicsUpdate
and
OnPostPhysicsUpdate
functions.
Such tasks delay the start of simulation on the physics thread.
During the
OnTick
event, the state of the simulation can vary. Requests are either queued or processed immediately depending on whether the simulation has been completed for the frame.
The following table provides some tips on using the
OnTick
,
OnPrePhysicsUpdate
, and
OnPostPhysicsUpdate
functions.
Function
OnTick
Good For
Making fire-and-forget requests
OnPrePhysicsUpdate
Making a request and reliably querying its impact
Bad For
Knowing when a request is done processing
Time-consuming tasks
EBus
TickBus
PhysicsSystemEventBus
Running the physics simulation in the main thread makes gameplay scripting simpler and more reliable.
All requests are processed immediately and all queries represent the latest state. However, a physicsintensive game is more likely to impact the frame rate.
Version 1.10
1079
Lumberyard Developer Guide
Physics Scripting Tips and Tricks
The following diagram illustrates a physics simulation on the main thread.
To enable physics in the main thread, type the following in the game.cfg
file: sys_physics_CPU=0
Following are a few troubleshooting tips for physics scripting.
To turn on debug rendering of physics proxies
Do one of the following:
• In the console, type the following: p_draw_helpers=1
• In Lumberyard Editor,in the
Rollup Bar
, click the
Display Settings
tab. Under
Render Settings
in the
Profile Options
section, select
Show Proxy
.
If an entity floats away like a balloon, check the following common causes and solutions:
• The entity has gone beyond the borders of the terrain. The solution is to stay on the terrain.
• The entity has a low mass, and CryPhysics has determined that it is less dense than air. The solution is to adjust the mass or density.
The following code example uses
BehaviorContext
syntax to script the physics for a rocket.
local rocket =
{
Properties =
{
InitialVelocity = {default=Vector3(), description="The initial speed and direction
of the entity"},
Impulse = {default=Vector3(), description="The impulse to add every frame"},
},
} function rocket:OnActivate()
PhysicsComponentRequestBus.Event.SetVelocity(self.entityId,
self.Properties.InitialVelocity)
self.TickHandler = TickBus.CreateHandler(self) end
Version 1.10
1080
Lumberyard Developer Guide
Geometries function rocket:OnTick(dt, scriptTime)
PhysicsComponentRequestBus.Event.AddImpulse(self.Properties.Impulse) end function rocket:OnDeactivate()
self.TickHandler:Disconnect() end return rocket
Geometries are first created as independent objects so that they can be used alone via the
IGeometry interface which they expose and then they can be physicalized and added to physical entities. Geometry physicalization means computing physical properties (volume, inertia tensor) and storing them in a special internal structure. Pointers to these structures can then be passed to physical entities.
Each physicalized geometry has a reference counter which is set to 1 during creation, incremented every time the geometry is added to an entity and decremented every time the geometry is removed or the entity is deleted. When the counter reaches 0, the physical geometry structure is deleted and the corresponding
IGeometry
object is released. The
IGeometry
object is also reference counted.
Geometry management functions are accessible through the geometry manager, which is a part of physical world. To obtain a pointer to the geometry manger, call the
GetGeomManager()
function.
The
CreateMesh
geometry management function creates a triangular mesh object from a set of vertices and indices (3 indices per triangle) and returns the corresponding IGeometry pointer.
• The engine uses triangle connectivity information in many places, so it is strongly recommended to have meshes closed and manifold. The function is able to recognize different vertices that represent the same point in space for connectivity calculations (there is no tolerance though, it checks only for exact duplicates). Open edges are ok only for geometries that will not be used as parts of dynamic physical entities and only if there will be little or no interaction with them.
• For collision detection the function can create either an OBB or a memory-optimized AABB or a single box tree. Selection is made by specifying the corresponding flag. If both AABB and OBB flags are specified, the function selects the tree that fits the geometry most tightly. Since an OBB tree is tighter in most cases, priority of AABBs can be boosted to save memory (also, AABB checks are slightly faster if the trees are equally tight). The engine can either copy the vertex/index data or use it directly from the pointers provided.
• The mesh_multycontact flags
give some hints on whether multiple contacts are possible. Specifying that multiple contacts are unlikely ( mesh_multycontact0
) can improve performance a bit at the expense of missing multiple contacts if they do occur (note that it does not necessarily mean they will be missed, it is a hint for the algorithm to use some optimizations more aggressively).
mesh_multycontact2
disables this optimization and ..1 is a recommended default setting. Convex geometries are detected and some additional optimizations are used for them, although internally there is no separate class for convex objects (this may change in the future).
• Meshes can have per-face materials. Materials are used to look up friction, bounciness, and pierceability coefficients and can be queried by the game as a part of collision detection output.
• The
CreateMesh
function is able to detect meshes that represent primitives (with the specified tolerance) and returns primitive objects instead. In order to activate this detection, the corresponding
Version 1.10
1081
Lumberyard Developer Guide
Physical Entities flags should be specified. Note that primitives can't store materials. They can only have one in the physical geometry structure, so this detection is not used when the material array has more than one material index in it.
CreatePrimitive:
Creates a primitive geometry explicitly. The corresponding primitive (cylinder, sphere, box, heightfield, or ray) structure should be filled and passed as a parameter, along with its ::type.
RegisterGeometry
physicalizes an
IGeometry
object by computing its physical properties and storing them in an auxiliary structure. Material index ( surfaceidx
) can be stored in it; it will be used if the geometry itself does not have any materials specified (such as if it is a primitive).
AddRefGeometry
and
UnregisterGeometry
comprise a reference "sandwich" for it. Note that the latter does not delete the object until its reference count becomes 0.
Geometries and physicalized geometries can be serialized. This saves time when computing OBB trees.
That computation is not particularly slow, but serialization is faster.
Physical entities can be created via calls to the
CreatePhysicalEntity
method of the physical world.
CreatePhysicalEntity
can create the types of entities noted in the following table:
Physical Entity Types
Type Description
PE_ARTICULATED
An articulated structure, consisting of several rigid bodies connected with joints (a ragdoll, for instance). It is also possible to manually connect several
PE_RIGID
entities with joints, but in this case they will not know that they comprise a single object, and thus some useful optimizations cannot be used.
PE_LIVING
PE_PARTICLE
A special entity type to represent player characters that can move through the physical world and interact with it.
A simple entity that represents a small lightweight rigid body. It is simulated as a point with some thickness and supports flying, sliding and rolling modes.
Recommended usage: rockets, grenades and small debris.
PE_RIGID
A single rigid body. Can have infinite mass (specified by setting mass to 0), in which case it will not be simulated but will interact properly with other simulated objects;
A rope object. It can either hang freely or connect two purely physical entities.
PE_ROPE
PE_SOFT
A system of non-rigidly connected vertices that can interact with the environment. A typical usage is cloth objects.
PE_STATIC
An immovable entity. An immovable entity can still be moved manually by setting positions from outside, but in order to ensure proper interactions with simulated objects, it is better to use
PE_RIGID
entity with infinite mass.
A wheeled vehicle. Internally it is built on top of a rigid body, with added vehicle functionality (wheels, suspensions, engine, brakes).
Version 1.10
1082
Lumberyard Developer Guide
Creating and managing entities
Note
PE_RIGID
,
PE_ARTICULATED
and
PE_WHEELEDVEHICLE
are purely physical entities that comprise the core of the simulation engine. The other entities are processed independently.
When creating and managing entities, keep in mind the following:
• Entities use a two-dimensional, regular grid to speed up broad phase collision detection. The grid should call the
SetupEntityGrid
function before physical entities are created.
• Entities can be created in permanent or on-demand mode and are specified by the parameter lifeTime
(use 0 for permanent entities). For on-demand mode, the entity placeholders should be created first using
CreatePhysicalPlaceholder
. Physics will then call the outer system to create the full entity whenever an interaction is required in the bounding box for this placeholder.
• If an entity is not involved in any interactions for the specified lifetime, it will be destroyed, with the placeholder remaining. Placeholders require less memory than full entities (around 70 bytes versus
260 bytes). It is possible for an outer system to support hierarchical placeholders, such as metaplaceholders that create other placeholders upon request.
• A sector-based, on-demand physicalization is activated after
RegisterBBoxInPODGrid
is called. Entities are created and destroyed on a sector basis. The sector size is specified in
SetupEntityGrid
.
• You can use
SetHeightfieldData
to set up one special static terrain object in the physical world. You can also create unlimited terrain geometry manually and add it to an entity.
Destroying, suspending, and restoring entities
To destroy, suspend, or restore a physical entity, use
DestroyPhysicalEntity
and set the mode
parameter to 0, 1, or 2, respectively. Suspending an entity clears all of its connections to other entities, including constraints, without actually deleting the entity. Restoring an entity after suspension will not restore all lost connections automatically. Deleted entities are not destroyed immediately; instead, they are put into a recycle bin. You might need to remove references to any one-way connections. The recycle bin is emptied at the end of each
TimeStep
. You can also call
PurgeDeletedEntities
.
Physical entity IDs
All physical entities have unique IDs that the physics engine generates automatically. You do not need to specify an ID during creation. You can also set a new ID later. Entities use these IDs during serialization to save dependency information. When reading the saved state, be sure that entities have the same IDs. IDs are mapped to entity pointers by use of an array, so using large ID numbers will result in allocation of an equally large array.
Associations with outside objects
To maintain associations with outside engine objects, physical entities store an additional void pointer and two 16-bit integers ( pForeignData
, iForeignData
, and iForeignFlags
) . These parameters are set from outside, not by the entities. Use pForeignData
to store a pointer to the outside engine reference entity and iForeignData
to store the entity type, if applicable.
For each material index, the physical world stores the friction coefficient, a bounciness (restitution) coefficient, and flags. When two surfaces contact, the contact's friction and bounciness are computed as an average of the values of both surfaces. The flags only affect raytracing.
Physical entities are grouped by their simulation type, in order of increasing "awareness". Certain interface functions, such as ray tracing and querying entities in an area, allow filtering of these entities by type.
Version 1.10
1083
Lumberyard Developer Guide
Creating and managing entities
• 0 ( bitmask ent_static
) – Static entities. Although terrain is considered static, it does not have a special simulation type. It can be filtered independently with the ent_terrain
bitmask.
• 1 ( bitmask ent_sleeping_rigid
) – Deactivated, physical objects (rigid bodies and articulated bodies).
• 2 ( bitmask ent_rigid
) – Active, physical objects.
• 3 ( bitmask ent_living
) – Living entities.
• 4 ( bitmask ent_independent
) – Physical entities that are simulated independently from other entities
(particles, ropes, and soft objects).
• 6 ( bitmask ent_triggers
) – Entities (or placeholders) that are not simulated and only issue callbacks when other entities enter their bounding box.
• 7 ( bitmask ent_deleted
) – Objects in the recycle bin. Do not use this directly.
Entities that have a lower simulation type are not aware of entities with higher simulation types
(types 1 and 2 are considered as one for this purpose), so players (type 3) and particles (type 4) check collisions against physical entities (types 1 and 2) but physical entities do not know anything about them.
Similarly, ropes (type 4) can check collisions against players but not the other way. However, entities of higher types can still affect entities with lower types by using impulses and constraints. Most entities expect a particular simulation type (and will automatically set to the proper value).
There are exceptions to the 'awareness hierarchy': for example, articulated entities can be simulated in types 1 and 2 as fully physicalized dead bodies, or in type 4 as skeletons that play impact animations without affecting the environment and being affected by it.
Most interactions with physical entities will use the functions
AddGeometry
,
SetParams
,
GetParams
,
GetStatus
, and
Action
.
•
AddGeometry
– Adds multiple geometries (physicalized geometries) to entities. For more details, see the
AddGeometry section that follows.
•
RemoveGeometry
– Removes geometries from entities.
•
SetParams
– Sets parameters.
•
GetParams
– Gets the simulation input parameters.
•
GetStatus
– Gets the simulation output parameters.
GetStatus
requests the values that an entity changes during simulation.
•
Action
– Makes an entity execute an action, such as adding an impulse.
These functions take structure pointers as parameters. When you want to issue a command, you can create a corresponding structure (for example, as a local variable) and specify only the fields you need.
The constructor of each structure provides a special value for all fields that tells the physics engine that the field is unused. You can also do this explicitly by using the
MARK_UNUSED
macro and is_unused
to verify that the field is unused.
AddGeometry
AddGeometry
adds a physicalized geometry to an entity. Each geometry has the following properties:
• id
– A unique part identifier within the bounds of the entity to which the geometry belongs. You can specify the ID or use
AddGeometry
to generate a value automatically. The ID doesn't change if the parts array changes (for example, if some parts from the middle are removed), but the internal parts index might change.
• position
, orientation
, and uniform scaling
– Relative to the entity.
• mass
– Used for non-static objects; static objects assume infinite mass in all interactions. You can specify the mass or density where the complementary value will be computed automatically (using
Version 1.10
1084
Lumberyard Developer Guide
Functions for Entity Structures formula mass = density*volume; volume
is stored in the physicalized geometry structure and scaled if the geometry is scaled).
• surface_idx
– Used if neither IGeometry nor physicalized geometry have surface (material) identifiers.
• flags
and flagsCollider
– When an entity checks collisions against other objects, it checks only parts that have a flag mask that intersects its current part's flagsCollider
. You can use 16type bits ( geom_colltype
) to represent certain entity groups. Although not enforced, it is good practice to keep these relationships symmetrical. If collision checks are known to be one-sided (for example, entity A can check collisions against entity B but never in reverse), you can choose to not maintain this rule. Certain flags are reserved for special collision groups, such as geom_colltype1 = geom_colltype_players
and geom_colltype2 = geom_colltype_explosion
(when explosion pressure is calculated, only parts with this flag are considered). There are also special flags for raytracing and buoyancy calculations: geom_colltype_ray
and geom_floats
.
• minContactDist
– The minimum distance between contacts the current part of the entity might have with another part of an entity. Contacts belonging to different parts are not checked for this. You can leave this unused so it will initialize with a default value based on geometry size. Each part can have both geometry and proxy geometry. Geometry is used exclusively for raytracing and proxy geometry.
If no proxy geometry is specified, both geometries are set to be equal to allow the raytracing to test against high-poly meshes without needing to introduce changes to the part array layout.
This section describes functions that control general and specific kinds of entity structures.
Topics
•
•
Living Entity-Specific Functions (p. 1087)
•
Particle Entity-Specific Functions (p. 1089)
•
Articulated Entity-Specific Functions (p. 1089)
•
Rope Entity-Specific Functions (p. 1091)
•
Soft Entity-Specific Functions (p. 1091)
Sets the position and orientation of the entity. You can use offset/quaternion/scaling values directly or allow the physics to extract them from a 3x3 (orientation+scaling) or a 4x4 (orientation_scaling
+offset) matrix. Physics use a right-to-left transformation order convention, with vectors being columns
( vector_in_world = Matrix_Entity * Matrix_Entity_Parts * vector_in_geometry
). All interface structures that support matrices can use either row-major or column-major matrix layout in memory (the latter is considered transposed; thus, the corresponding member has T at the end of its name).
There is no per-entity scaling; scaling is only present for parts. When a new scaling is set with pe_params_pos
, it is copied into each part and overrides any previous individual scalings. This structure also allows you to set the simulation type manually. After changes are made, entity bounds are typically recalculated and the entity is re-registered in the collision hash grid; however, this can be postponed if bRecalcBounds
is set to
0
.
Sets an entity's bounding box to a particular value, or queries it when used with
GetParams
). The bounding box is recalculated automatically based on the entity's geometries, but you can set the
Version 1.10
1085
Lumberyard Developer Guide
Common Functions bounding box manually for entities without geometries (for example, triggers) or placeholders. If the entity has geometries, it might recalculate its bounding box later, overriding these values. Bounding boxes are axis-aligned and in the world coordinate system.
Specifies an outer entity for an entity. When a box of interest (its center) is inside the entity with an outer entity, the outer entity is excluded from the set of potential colliders. This allows you to have a building exterior quickly culled away when the region of interest is inside the building's interior. Outer entities can be nested and an optional geometry to test for containment is supported.
Sets or queries the entity part's properties. The part can be specified using an internal part index or its
ID.
Sets simulation parameters for entities that can accept these parameters (e.g. physical entities, ropes, and soft entities). minEnergy
is equal to sleep speed squared. Damping and gravity can be specified independently for colliding and falling state, for example when there are no contacts.
Sets the buoyancy properties of the object and the water plane. The physics engine does not have a list of water volumes, so the outer system must update water plane parameters when they change. The water surface is assumed to be a perfect plane, so you can simulate bobbing of the waves by disturbing the normal of this surface. waterFlow
specifies the water movement velocity and affects the object based on its waterResistance
property). A separate sleeping condition is used in the water ( waterEmin
).
Attaches sensors to entities. Sensors are rays that the entity can shoot to sample the environment around it. It is more efficient to do it from inside the entity step than by calling the world's raytracing function for every ray from outside the entity step. Living entities support vertical-down sensors.
Adds a one-time impulse to an entity. impulse
is the impulse property (in N*sec; impulse P will change the object's velocity by P/[object mass]). point
is a point in world space where the impulse is applied and used to calculate the rotational effects of the impulse. The of point
momentum can be used to specify the rotational impulse explicitly. If neither the point nor momentum are specified, the impulse is applied to the center of the mass of the object. iApplyTime
specifies the time when the impulse is applied. By default the value is 2 ("after the next step") to allow the solver an opportunity to reflect the impulse.
Adds a constraint between two objects. Points specify the constraint positions in world space. If the second point is used and different from the first point, the solver will attempt to join them.
Relative positions are always fully constrained to be 0 (i.e. the points on the bodies will always be in one spot) and relative rotations can be constrained in twist and bend directions. These directions correspond to rotation around the x-axis and the remaining rotation around a line on the yz-plane (tilt of the x-axis) of a relative transformation between the two constraint coordinate frames attached to the affected bodies.
Version 1.10
1086
Lumberyard Developer Guide
Living Entity-Specific Functions
The original position of the constraint frames are specified with qframe
parameters in world or entity coordinate space (as indicated by the corresponding flag in flags
). If one or both qframes are unused, they are considered to be an identity transformation in either the world or entity frame.
Rotation limits are specified with the xlimits
and yzlimits
parameters, with valid element values of 0
(minimum) and 1 (maximum). If the minimum is more than or equal to the maximum, the corresponding relative rotation is prohibited. pConstraintEntity
specifies an entity that represents the constraint.
When passed a pe_action_add_constraint pointer,
Action
returns a constraint identifier that can be used to remove the constraint. 0 indicates a failure.
Sets the velocity of an object, which is useful for rigid bodies with infinite mass (represented as mass).
pe_action_set_velocity
informs the physics system about the body's velocity, which can help the solver ensure zero relative velocity with the objects contacted. If velocity is not set and only the position is changed, the engine relies solely on penetrations to enforce the contacts. Velocity will not be computed automatically if the position is set manually each frame. The body will continue moving with the specified velocity once it has been set.
Requests the current transformation (position, orientation, and scale) of an entity or its part. You can also use pe_params_pos
with
GetParams
. If matrix pointers are set, the engine will provide data in the corresponding format. The
BBox
member in this structure is relative to the entity's position.
Retrieves an entity's movement parameters. Acceleration and angular acceleration are computed based on gravity and interactions with other objects. External impulses that might have been added to the entity are considered instantaneous. submergedFraction
is a fraction of the entity's volume under water during the last frame (only parts with the geom_float
flag are considered). waterResistance
contains the maximum water resistance that the entity encountered in one frame since the status was last requested
(the accumulated value is cleared when the status is returned). This value can be useful for generating splash effects.
Living entities use cylinders or capsules as their bounding geometry. Normally the cylinders are hovering above the ground and the entity shoots a single ray down to detect if it is standing on something. This cylinder geometry always occupies the first part slot (it is created automatically). It is possible to add more geometries manually, but they will not be tested against the environment when the entity moves.
However, other entities will process them when testing collisions against the entity.
Living entities never change their orientation themselves; this is always set from outside. Normally, living entities are expected to rotate only around the z-axis, but other orientations are supported. However, collisions against living entities always assume vertically oriented cylinders.
Sets the dimensions of the living entity's bounding geometry.
heightPivot
specifies the z-coordinate of a point in the entity frame that is considered to be at the feet level (usually 0).
heightEye
is the z-coordinate of the camera attached to the entity. This camera does not affect entity movement, its sole purpose is to smooth out height changes that the entity undergoes (during walking
Version 1.10
1087
Lumberyard Developer Guide
Living Entity-Specific Functions on a highly bumpy surface, such as stairs, after dimensions change and during landing after a period of flying). The camera position can be requested via the pe_status_living
structure.
sizeCollider
specifies the size of the cylinder (x is radius, z is half-height, y is unused).
heightColliders
is the cylinder's center z-coordinate.
The head is an auxiliary sphere that is checked for collisions with objects above the cylinder. Head collisions don't affect movement but they make the camera position go down. headRadius
is the radius of this sphere and headHeight
is the z-coordinate of its center in the topmost state (that is, when it doesn't touch anything).
Sets a living entity's movement parameters. Living entities have their 'desired' (also called 'requested') movement velocity (set with pe_action_move
) and they attempt to reach it. How fast that happens depends on the kInertia
setting. The greater this value is, the faster the velocity specified by pe_action_move
is reached. The default is 8. 0 means that the desired velocity will be reached instantly.
kAirControl
(0..1) specifies how strongly the requested velocity affects movement when the entity is flying (1 means that whenever a new requested velocity is set, it is copied to the actual movement velocity).
kAirResistance
describes how fast velocity is damped during flying.
nodSpeed
(default 60) sets the strength of camera reaction to landings.
bSwimming
is a flag that tells that the entity is allowed to attempt to move in all directions (gravity might still pull it down though). If not set, the requested velocity will always be projected on the ground if the entity is not flying.
minSlideAngle
, maxClimbAngle
, maxJumpAngle
and minFallAngle
are threshold angles for living entities that specify maximum or minimum ground slopes for certain activities. Note that if an entity's bounding cylinder collides with a sloped ground, the behavior is not governed by these slopes only.
Setting bNetwork
makes the entity allocate a much longer movement history array which might be required for synchronization (if not set, this array will be allocated the first time network-related actions are requested, such as performing a step back).
Setting bActive
to 0 puts the living entity to a special 'inactive' state where it does not check collisions with the environment and only moves with the requested velocity (other entities can still collide with it, though; note that this applies only to the entities of the same or higher simulation classes).
Requests a movement from a living entity. dir
is the requested velocity the entity will try to reach.
If iJump
is not 0, this velocity will not be projected on the ground, and snapping to the ground will be turned off for a short period of time. If iJump
is 1, the movement velocity is set to be equal to dir instantly. If iJump
is 2, dir
is added to it. dt
is reserved for internal use.
Returns the status of a living entity.
vel
is the velocity that is averaged from the entity's position change over several frames.
velUnconstrained
is the current movement velocity. It can be different from vel
because in many cases when the entity bumps into an obstacle, it will restrict the actual movement but keep the movement velocity the same, so that if on the next frame the obstacle ends, no speed will be lost.
Version 1.10
1088
Lumberyard Developer Guide
Particle Entity-Specific Functions groundHeight
and groundSlope
contain the point's z coordinate and normal if the entity is standing on something; otherwise, bFlying
is 1. Note that pGroundCollider
is set only if the entity is standing on a non-static object.
camOffset
contains the current camera offset as a 3d vector in the entity frame (although only z coordinates actually changes in it).
bOnStairs
is a heuristic flag that indicates that the entity assumes that it is currently walking on stairs because of often and abrupt height changes.
Sets particle entity parameters.
During movement, particles trace rays along their paths with the length size*0.5
(since size
stands for 'diameter' rather than 'radius') to check if they hit something. When they lie or slide, they position themselves at a distance of thickness*0.5
from the surface (thus thin objects like shards of glass can be simulated).
Particles can be set to have additional acceleration due to thrust of a lifting force (assuming that they have wings) with the parameters accThrust
and accLift
but these should never be used without specifying kAirResistance
; otherwise, particles gain infinite velocity.
Particles can optionally spin when in the air (toggled with flag particle_no_spin
). Spinning is independent from linear motion of particles and is changed only after impacts or falling from surfaces.
Particles can align themselves with the direction of the movement (toggled with particle_no_path_alignment
flag) which is very useful for objects like rockets. That way, the y-axis of the entity is aligned with the heading and the z-axis is set to be orthogonal to y and to point upward
('up' direction is considered to be opposite to particle's gravity).
When moving along a surface, particles can either slide or roll. Rolling can be disabled with the flag particle_no_roll
(it is automatically disabled on steep slopes). Note that rolling uses the particle material's friction as damping while rolling treats friction in a conventional way. When touching ground, particles align themselves so that their normal (defined in entity frame) is parallel to the surface normal.
Particles can always keep the initial orientation as well ( particle_constant_orientation
) and stop completely after the first contact ( particle_single_contact
). minBounceVel
specifies the lower velocity threshold after which the particle will not bounce, even if the bounciness of the contact is more than 0.
Articulated entities consist of linked, rigid bodies called structural units. Each structural unit has a joint that connects it to its parent. For the connection structure, you should use a tree with a single root.
Linked loops are not allowed.
Articulated entities can simulate body effects without interactions with the environment by using featherstone mode, which you can tweak so that the entity tolerates strong impacts and so that complex body structures have stiff springs. Articulated entities use a common solver for interactive mode.
You can use pe_params_joint
to:
• Create a joint between two bodies in an articulated entity
• Change the parameters of an existing articulated entity
Version 1.10
1089
Lumberyard Developer Guide
Articulated Entity-Specific Functions
• Query the parameters of an existing articulated entity, when used with
GetParams
A joint is created between the two bodies specified in the op
parameter at the pivot point (in the entity frame). When a geometry is added to an articulated entity, it uses pe_articgeomparams
to specify which body the geometry belongs to (in idbody
). idbody
can be any unique number and each body can have several geometries. There are no restrictions on the order in which joints are created, but all bodies in an entity must be connected before the simulation starts.
Joints use Euler angles to define rotational limits. Flags that start with angle0_
can be specified individually for each angle by shifting left by the 0-based angle index. For example, to lock the z-axis you can use OR the flags with angle0_locked<<2
). The child body inherits the coordinate frame from the first entity (geometry) that was assigned to it.
Joint angular limits are defined in a relative frame between the bodies that the joint connects. Optionally the frame of the child body can be offset by specifying a child's orientation that corresponds to rotation angles (0,0,0), using q0, pMtx0, or pMtx0T. This can help to get limits that can be robustly represented using Euler angles.
A general rule for limits is to set upper and lower bounds at least 15 to 20 degrees apart (depending on simulation settings and the height of the joint's velocity) and to keep the y-axis limit in the -90..90
degrees range (preferably within safe margins from its ends).
Note
All angles are defined in radians in the parameter structure.
pe_params_joint
uses 3D vectors to represent groups of three values that define properties for each angle. In addition to limits, each angle can have a spring that will pull the angle to 0 and a dashpot that will dampen the movement as the angle approaches its limit. Springs are specified in acceleration terms: stiffness and damping can stay the same for joints that connect bodies with different masses, and damping can be computed automatically to yield a critically damped spring by specifying auto_kd
for the corresponding angle.
joint_no_gravity
makes the joint unaffected by gravity, which is useful if you assume forces that hold the joint in its default position are enough to counter gravity). This flag is supported in featherstone mode.
joint_isolated_accelerations
makes the joint use a special mode that treats springs like guidelines for acceleration, which is recommended for simulating effects on a skeleton. This flag is supported in featherstone mode.
Effective joint angles are always the sum of q
and qext
. If springs are activated, they attempt to drive q
to 0. The allows you to set a pose from animation and then apply physical effects relative to it. In articulated entities, collisions are only checked for pairs that are explicitly specified in pSelfCollidingParts
(this setting is per body or per joint, rather than per part).
pe_params_articulated_body
allows you to set and query articulated entity simulation mode parameters. Articulated entities can be attached to something or be free, and are set by the bGrounded flag. When grounded, the entity can:
• Fetch dynamic parameters from the entity it is attached to (if bInreritVel
is set; the entity is specified in pHost
)
• Be set using the a
, wa
, w
and v
parameters bCollisionResp
switches between featherstone mode (0) and constraint mode (1).
bCheckCollisions
turns collision detection on and off. It is supported in constraint mode.
Version 1.10
1090
Lumberyard Developer Guide
Rope Entity-Specific Functions iSimType
specifies a simulation type, which defines the way in which bodies that comprise the entity evolve. Valid values:
•
0
– joint pivots are enforced by projecting the movement of child bodies to a set of constrained directions |
•
1
– bodies evolve independently and rely on the solver to enforce the joints. The second mode is not supported in featherstone mode. In constraint mode, it is turned on automatically if bodies are moving fast enough.
We recommend setting this value to
1
to make slow motion smoother.
Lying mode
Articulated entities support a lying mode that is enabled when the number of contacts is greater than a specified threshold ( nCollLyingMode
). Lying mode has a separate set of simulation parameters, such as gravity and damping. This feature was designed for ragdolls to help simulate the high damping of a human body in a simple way, for example by setting gravity to a lower value and damping to a higher than usual value.
Standard simulation versus freefall parameters
Standard simulation parameters can be different from freefall parameters. When using the constraint mode, articulated entities can attempt to represent hinge joints (rotational joints with only axis enabled) as two point-to-point constraints by setting the bExpandHinges
parameter (this value propagates to joint_expand_hinge
flags for all joints, so you do not need to manually set the value for joints).
Ropes are simulated as chains of connected equal-length sticks ("segments") with point masses. Each segment can individually collide with the environment. Ropes can tie two entities together. In this case ropes add a constraint to the entities when the ropes are fully strained and won't affect their movement.
In order to collide with other objects (pushing them if necessary) in a strained state, the rope must use dynamic subdivision mode (set by rope_subdivide_segs
flag).
Specifies all the parameters a rope needs to be functional.
Rope entities do not require any geometry. If you do not specify initial point positions, the rope is assumed to be hanging down from its entity position. If you do specify initial point positions, segments should have equal length but within some error margin. Ropes use an explicit friction value (not materials) to specify friction.
If pe_params_rope
is passed to
GetParams
, pPoints
will be a pointer to the first vertex in an internal rope vertex structure, and iStride
will contain the size of it.
There are two types of soft entities:
mesh-based
and
tetrahedral lattice-based
. Mesh based entities use a soft, constraint-like solver and are typically cloth objects. Tetrahedral lattice-based entities use a spring solver and are typically jelly-like objects.
The longest edges of all triangles can optionally be discarded with the sef_skip_longest_edges
flag.
Collisions are handled at the vertex level only (although vertices have a customizable thickness) and work best against primitive geometries rather than meshes.
Version 1.10
1091
Lumberyard Developer Guide
Collision Classes
This is the main structure to set up a working soft entity (another one is pe_simulation_params
).
Thickness
The thickness of the soft entity is the collision size of vertices (they are therefore treated as spheres).
If an edge differs from the original length by more than maxSafeStep
, positional length enforcement occurs.
Damping
Spring damping is defined with kdRatio
as a ratio to a critically damped value (overall damping from pe_simulation_params
is also supported).
Wind
Soft entities react to wind if airResistance
is not 0 (if wind is 0, having non-zero airResistance
would mean that the entity will look like it is additionally damped - air resistance will attempt to even surface velocity with air velocity).
Water
Soft entities react to water in the same way that they react to wind, but the parameters specified in pe_params_buoyancy
are used instead. Note that the Archimedean force that acts on vertices submerged in the water will depend on the entity's density which should be defined explicitly in pe_simulation_params
(dependence will be same as for rigid bodies - the force will be 0 if waterDensity is equal to density
). collTypes
enables collisions with entities of a particular simulation type using ent
_ masks.
Can be used to attach some of a soft entity's vertices to another physical entity.
piVtx
specifies vertex indices.
points
specify attachment positions in world space. If points
values are not specified, current vertex positions are the attachment points.
Use collision classes to filter collisions between two physical entities. A collision class comprises two 32bit uints, a type
, and an ignore
.
You can use collision classes to implement scenarios such as "player only collisions," which are objects passable by AI actors but not passable by players. This feature allows you to configure filtering of the collision between physical entities independently of their collision types.
Physical entities can have one or more collision classes and can ignore one or more collision classes. To have a physical entity ignore a collision, use the ignore_collision
attribute of the
<Physics>
element in the
<SurfaceType>
definition, as shown in the following example:
SurfaceTypes.xml
<SurfaceType name="mat_nodraw_ai_passable">
Version 1.10
1092
Lumberyard Developer Guide
Code
<Physics friction="0" elasticity="0" pierceability="15"
ignore_collision="collision_class_ai"/>
</SurfaceType>
All physical entity types such as
LivingEntity
and
ParticleEntity
are supplied with default collision classes like collision_class_living
and collision_class_particle
. Living entity uses one additional game specific collision class: either collision_class_ai
for AI actors, or collision_class_player
for players.
Player.lua
Player = {
...
physicsParams =
{
collisionClass=collision_class_player,
},
...
}
BasicAI.lua
BasicAI = {
...
physicsParams =
{
collisionClass=collision_class_ai,
},
...
}
struct SCollisionClass
{
uint32 type; // collision_class flags to identify the entity
uint32 ignore; // another entity will be ignored if *any* of these bits are set in
its type
};
The type
identifies which entity the collision classes belong to.
Some collision classes like the following are defined in
CryPhysics
:
• collision_class_terrain
• collision_class_wheeled
• collision_class_living
• collision_class_articulated
• collision_class_soft
• collision_class_roped
• collision_class_particle
Other collision classes are defined in
GamePhysicsSettings.h
, starting from the collision_class_game bit:
#define GAME_COLLISION_CLASSES(f) \
Version 1.10
1093
Lumberyard Developer Guide
Types
f( gcc_player_capsule, collision_class_game << 0) \
f( gcc_player_body, collision_class_game << 1) \
f( gcc_pinger_capsule, collision_class_game << 2) \
f( gcc_pinger_body, collision_class_game << 3) \
f( gcc_vehicle, collision_class_game << 4) \
f( gcc_large_kickable, collision_class_game << 5) \
f( gcc_ragdoll, collision_class_game << 6) \
f( gcc_rigid, collision_class_game << 7) \
f( gcc_alien_drop_pod, collision_class_game << 8) \
f( gcc_vtol, collision_class_game << 9) \
All these classes are automatically exposed to Lua. Brushes and most objects have the collision classes available in the properties through the editor.
For types, you can set many or zero bits.
In the following example, of the classes
LIVING
,
PLAYER
,
TEAM1
,
TEAM2
,
AI
,
AI_1
, and
AI_2
, player1 belongs to the
LIVING
entity class, the
PLAYER
class, and the
TEAM1
class:
SCollisionClass player1(0,0), player2(0,0), ai1(0,0), ai7(0,0), object1(0,0); player1.type = LIVING|PLAYER|TEAM1; player2.type = LIVING|PLAYER|TEAM2; ai1.type = LIVING|AI|AI_1; ai7.type = LIVING|AI|AI_2; object1.type = 0;
Filtering occurs by checking the type
of one entity against the ignore
of another entity.
This is done both ways, and if bits overlap, then the collision is ignored. For example: bool ignoreCollision = (A->type & B->ignore) || (A->ignore & B->type);
If you want ai7
to ignore collisions with anything that has
AI_1
set, then add
AI_1
to the ignore
flags like this: ai7.ignore = AI_1
If you want object1
to ignore all living physical entities, set its ignore
flag like this: object1.ignore=LIVING
• For code, see physinterface.h
and
GamePhysicsSettings.h
.
• To access and set the collision classes on the physical entity, use
*pe_collision_class struct
SCollisionClass pe_params_collision_class
.
• For helpers that set additional ignore maps, see
GamePhysicsSettings.h
.
• In Lua, see
SetupCollisionFiltering
and
ApplyCollisionFiltering
. Lua script-binding is done through
SetPhysicParams(PHYSICPARAM_COLLISION_CLASS)
.
Version 1.10
1094
Lumberyard Developer Guide
Functions for World Entities
Use the functions in this section to modify entities or a physical world environment.
The
TimeStep
functions make the entities advance their state by the specified time interval.
If timeGranularity
in the physical variables is set, the time interval will be snapped to an integer value with the specified granularity (for example, if timeGranularity
is 0.001, the time interval will be snapped to a millisecond).
Entities that perform the step can be filtered with ent
_ flags in the flags
parameter.
The flags
parameter can contain ent_
masks for Simulation type (p. 1083) .
The flags
parameter can also contain the ent_flagged_only
flag. This flag causes entities to be updated only if the entities have the pef_update
flag set.
Specifying the ent_deleted
flag will allow the world to delete entities that have timed out if physics on demand is used.
Most entities have the maximum time step capped. To have larger timesteps, entities have to perform several substeps. The number of substeps can be limited with the physics variable nMaxSubsteps
.
The function
GetEntitiesInBox
uses the internal entity hash grid to return the number of entities
Syntax
virtual int GetEntitiesInBox(Vec3 ptmin,Vec3 ptmax, IPhysicalEntity **&pList, int objtypes,
int szListPrealloc=0) = 0;
Example call
IPhysicalEntity** entityList = 0; int entityCount = gEnv->pPhysicalWorld->GetEntitiesInBox(m_volume.min, m_volume.max,
entityList,
ent_static | ent_terrain | ent_sleeping_rigid | ent_rigid);
Parameters
Parameter Description
ptmin ptmax pList objtypes
Minimum point in the space that defines the desired box volume.
Maximum point in the space that defines the desired box volume.
Pointer to a list of objects that the function poplulates.
Types of objects that need to be considered in the query.
Version 1.10
1095
Lumberyard Developer Guide
Casting Rays in an Environment
Parameter Description
If specified, the maximum number of objects contained in the pList
array.
The possible object types are described in the physinterface.h
header file in the entity_query_flags enumerators. A few are listed in the following table:
Entity type flag
ent_static ent_terrain
Description
Static entities
Terrain ent_rigid
Rigid bodies
After the function completes, you can easily iterate through the entity list to perform desired operations, as in the following code outline: for (int i = 0; i < entityCount; \++i)
{
IPhysicalEntity\* entity = entityList[i];
[...]
if (entity->GetType() == PE_RIGID)
{
[...]
}
[...]
}
If ent_alloctate_list
is specified, the function allocates memory for the list (the memory can later be freed by a call to pWorld->GetPhysUtils()->DeletePointer
). Otherwise, an internal pointer will be returned.
Note
Because the physics system uses this pointer in almost all operations that require forming an entity list, no such calls should be made when the list is in use. If such calls are required and memory allocation is undesired, copy the list to a local pre-allocated array before iterating over it.
The
RayWorldIntersection
physical world function casts rays into the environment.
Depending on the material that the ray hits and the ray properties, a hit can be pierceable or solid.
A pierceable hit is a hit that has a material pierceability higher than the ray's pierceability. Material pierceability and ray pierceability occupy the lowest 4 bits of material
flags and
RayWorldIntersection flags.
Version 1.10
1096
Lumberyard Developer Guide
Creating Explosions
Pierceable hits don't stop the ray and are accumulated as a list sorted by hit distance. The caller provides the function with an array for the hits. A solid hit (if any) always takes the slot with index 0 and pierceable hits slots from 1 to the end.
Optionally, the function can separate between 'important' and 'unimportant' pierceable hits (importance is indicated by sf_important
in material flags) and can make important hits have a higher priority
(regardless of hit distance) than unimportant ones when competing for space in the array.
By default,
RayWorldIntersection
checks only entity parts with the geom_colltype_ray flag. You can specify another flag or combination of flags by setting flags |= geom_colltype_mask<<rwi_colltype_bit
. In this case, all flags should be set in part so that the specified flag can be tested.
RayTraceEntity
is a more low-level function and checks ray hits for one entity only.
RayTraceEntity returns only the closest hit.
Alternatively,
CollideEntityWithBeam
can perform a sweep-check within a sphere of the specified radius. In order to detect collisions reliably, the sphere specified should be outside of the object. The org parameter corresponds to the sphere center.
The function
SimulateExplosion
is used to simulate explosions in a physical world.
The only effect of explosions inside the physics system are impulses that are added to the nearby objects.
A single impulse is calculated by integrating impulsive pressure at an area fragment multiplied by this area and scaled by its orientation towards the epicenter.
Impulsive pressure has a falloff proportional to
1/distance2
. If distance
is smaller than rmin
, it is clamped to rmin
.
impulsive_pressure_at_r
is the impulsive pressure at distance r
.
SimulateExplosion
can optionally build an occlusion cubemap to find entities occluded from the explosion ( nOccRe_s
should be set to a non-zero cubemap resolution in one dimension in this case). First, static entities are drawn into the cubemap, and then dynamic entities of the types specified in iTypes
are tested against the map. Thus, dynamic entities never occlude each other.
Passing -1 to nOccRes
tells the function to reuse the cubemap from the last call and process only the dynamic entities that were not processed during the last call. This is useful when the code that creates the explosion decides to spawn new entities afterwards, such as debris or dead bodies, and wants to add explosion impulses to them without recomputing the occlusion map.
Due to the projective nature of the cubemap, small objects very close to the epicenter can occlude more than they normally would. To counter this, rmin_occ
can specify linear dimensions of a small cube that is subtracted from the environment when building the occlusion map. This crops the smaller objects but can make explosions go through thin walls, so a compromise set of dimensions should be used.
nGrow
specifies the number of occlusion cubemap cells (in one dimension) that dynamic entities are inflated with. This can help explosions to reach around corners in a controllable way. After a call has been made to
SimulateExplosion
, the physics system can return how much a particular entity was affected by by calling
IsAffectedByExplosion
.
IsAffectedByExplosion
returns fraction from zero to one. The
IsAffectedByExplosion
function performs a lookup into a stored entity list; it does not recompute the cubemap. The explosion epicenter used for generating impulses can be made different from the one used to build a cubemap. For example, you can create explosions slightly below the ground to make things go up instead of sideways. Note that this function processes only parts with geom_colltype_explosion
.
Version 1.10
1097
Lumberyard Developer Guide
Profiler Tutorial
Profiler is in preview release and is subject to change.
Profiler is a Lumberyard tool that can capture, save, and analyze network, CPU, and VRAM usage statistics. You can used the saved data to analyze network usage frame by frame, fix problems in the use of network bandwidth, and optimize the performance of your game.
To capture data, Profiler works with GridHub. When you launch Profiler, GridHub launches automatically
as a supporting background process. For more information about GridHub, see Using GridHub (p. 1126)
.
Topics
•
•
Creating and Using Annotations (p. 1108)
•
Using Profiler for Networking (p. 1111)
•
Using the Profiler for CPU Usage (p. 1120)
•
Using Profiler for VRAM (p. 1123)
•
Profiler is in preview release and is subject to change.
You can register an application in GridHub and use Profiler to capture, inspect, play back, and export the data that you collect.
Topics
•
Registering Your Application (p. 1099)
•
•
Version 1.10
1098
Lumberyard Developer Guide
Registering Your Application
•
•
•
To enable Profiler to capture information from your application, you must first register the application in GridHub. To do so, add
AzFramework::TargetManagementComponent
to the application’s
SystemComponent
.
Note
: Lumberyard's built-in applications already have this component added by default.
Unlike many Lumberyard utilities, you launch Profiler from its own executable file.
To launch profiler
• From the Lumberyard dev\Bin64\
directory, run
Profiler.exe
.
Profiler has two main modes of use:
capture mode
and
inspection mode
.
To use capture mode, perform the following steps.
To capture data
1. Click
Target
.
Profiler shows you the applications that are available for profiling:
2. Select a target application.
After you have selected a target, the target selector shows the state of the connection to the target.
The next time you launch Profiler, it automatically selects your target for you, if it's available.
Version 1.10
1099
Lumberyard Developer Guide
Capturing Data
The window is divided horizontally into channels that have associated Profiler instances. A channel is a collection of Profiler instances that relate to a specific system.
3. Each Profiler instance in a channel has a unique color. A Profiler instance is active when its color is solid:
Click the color next to a Profiler instance. The color is no longer solid, showing that the Profiler instance is inactive:
Click the color again to turn on the display and activate the instance again.
4. After you have selected a target and chosen the Profiler instances that you want to see, click
Capture
.
After the capture begins, data begins to populate the channels.
5. To stop the data capture, click
Stop Capture
.
Version 1.10
1100
Lumberyard Developer Guide
Inspecting Data
6. When prompted, save the captured data to disk. Profiler saves the data in a binary format file with a
.drl
extension, reloads the data from disk, and switches to inspection mode.
Note
If you do not save the data, it will be discarded.
You can use profiler to examine the data that you have captured.
To inspect captured data
1. In Profiler, click
File
,
Open Data
, or press
Ctrl+O
:
2. Navigate to the
.drl
file that contains your saved data and open it.
The main screen of the Profiler provides an overview of the channels of system information. This example uses a file that has 1162 frames of data:
You can use this main view to discover anomalies across channels, or to examine particular areas of interest at a high level.
When you open the main window, the scroll box at the bottom is on the right because the playback stopped at the end of the captured data.
Notice the red vertical line on the right.
3. Click in the channels area of the window.
Version 1.10
1101
Lumberyard Developer Guide
Inspecting Data
The red vertical line moves to where you clicked. The frame indicator shows the new position of the red line. You can place the red line, which is called the
scrubber
, on any frame that you want to examine in detail. For finer control over the position of the scrubber, you can enter a number in the
Frame
indicator.
The scrubber moves accordingly.
4. To view detailed information about a frame on which the scrubber rests, the click the
Detailed
Profiling Information
icon next to the profiler instance whose data you would like to see:
Profiler instance information appears in a detail window.
Version 1.10
1102
Lumberyard Developer Guide
Playing Back Data
Individual profilers present details in different ways, so their detail windows can look
, Using the Profiler for CPU Usage (p. 1120) , and
.
5. To return to capture mode from inspection mode, click the
LIVE
tab.
You can mark and play back a subset of your captured data.
Notice that after you moved the scrubber the first time, a yellow vertical line appeared on the right at the end of the data:
Version 1.10
1103
Lumberyard Developer Guide
Playing Back Data
This yellow marker is movable and marks the end of your desired playback range. By default, it is at the end of the captured data but may be obscured by the red scrubber.
1. Scroll the window all the way to the left, to the beginning of the capture range.
Now a yellow marker also appears at the beginning of the data. You can use these two yellow markers, which by default are at the beginning and end of the capture range, to restrict the range of playback to an area of data that you are interested in. You will use these shortly.
If you have many frames of data (as in this example), the initial view does not show you all frames by default.
2. To see all frames at once, click the
Frame Count Selector
, which determines the number of frames visible, and choose
All frames
:
Version 1.10
1104
Lumberyard Developer Guide
Playing Back Data
Now you can see the entire range of captured data, with the yellow markers at the beginning and at the end:
3. Drag the two yellow markers to an area of data that you want to play back. You can ignore the position of the scrubber for now.
Version 1.10
1105
Lumberyard Developer Guide
Playing Back Data
4. Click
Play
to start the playback:
As the data plays back, the scrubber moves from the first yellow marker to the second, and then loops back to the first.
Here are some tips to keep in mind:
• If the playback speed is too fast (the default is 60), use the
Playback Speed
option to adjust it from 1 through 60.
• If you click a location in the playback window during playback, the playback stops and moves the scrubber to the location that you clicked.
• You can place the scrubber on a frame that you are interested in and click the detail button for a profiler instance to see the detail window for the frame.
• For greater convenience and visibility, leave the profiler instance detail window open to see the data change in the detail window as the scrubber loops between markers.
Version 1.10
1106
Lumberyard Developer Guide
Playing Back Data
5. Click
Stop
to stop the playback.
Version 1.10
1107
Lumberyard Developer Guide
Exporting Data
Some Profiler instances have an export option that you can use to save data to a
.csv
file.
To export data from a Profiler instance to a
.csv
file
1. Click the
Save to CSV
icon for the Profiler instance whose data you want to save:
Note
Not all profilers have the data export option.
2. To choose the fields that you want to export, click
Customize
in the export dialog box.
Profiler is in preview release and is subject to change.
In Profiler, annotations are a convenient way of highlighting per-frame log information from the data captured from your application. After you learn how annotations are used in Profiler, you can modify your application so that they appear in Profiler.
Topics
•
•
Creating Annotations (p. 1110)
•
Viewing Annotations in Trace Messages Profiler (p. 1111)
Version 1.10
1108
Lumberyard Developer Guide
Using Annotations
Annotations in the Lumberyard Profiler tool flag frames in your captured data that have associated log information. By default, annotations are turned off.
To use annotations
1. To turn on annotations in the Lumberyard Profiler tool, click
Configure Annotations
:
The
Configure Annotations
dialog box contains a list of available annotations and their
display colors. For information on creating annotations for your application, see Creating
2. When you select an annotation in the dialog box, a marker and line of the same color appears in the channel display. Note that you might have to scroll horizontally to find the marker.
3. To display details for the annotations that occurred on a frame, pause your pointer on an annotation marker. In the example image, IP addresses have been redacted out.
Version 1.10
1109
Lumberyard Developer Guide
Creating Annotations
To create an annotation, you add one or more lines of C++ logging code to your application. The added code instructs Lumberyard's logging system to include the logging information that you specify as a part of your capture. Lumberyard transforms the logged messages into annotations for you. Then, in Profiler, when you click
Configure Annotations
, you actually choose which system's annotations are displayed
(for example,
GridMate
or
MultiplayerProject
).
To create an annotation, place a line of C++ code like the following in your application:
AZ_TracePrintf("GridMate","Connection %s => %s (%s) (Connections=%d!\n")
The first parameter is the window (that is, system) of the trace (in this case,
GridMate
), and the second is the content of the trace that will be shown as the annotation.
The example results in the following annotation text:
GridMate - Connection
<IP_Address>
|64090 =>
<IP_Address>
|57455 (Client) (Connections=1)!
The text displays in Profiler like this:
In your code, instead of using
AZ_TracePrintf
, you can use
AZ_Error
or
AZ_Warning
, depending on the degree of severity that you want.
AZ_TracePrintf
always logs a message, but is of the lowest concern from an inspection viewpoint.
The following example uses
AZ_Error
:
Version 1.10
1110
Lumberyard Developer Guide
Viewing Annotations in Trace Messages Profiler if (networkTableContext.ReadValue(elementIndex,forcedDataSetIndex))
{
AZ_Error("ScriptComponent",forcedDataSetIndex >= 1 && forcedDataSetIndex <=
ScriptComponentReplicaChunk::k_maxScriptableDataSets,"Trying to force Property (%s) to an
invalid DataSetIndex(%i).",scriptProperty->m_name.c_str(),forcedDataSetIndex);
if (forcedDataSetIndex >= 1 && forcedDataSetIndex <=
ScriptComponentReplicaChunk::k_maxScriptableDataSets)
{
networkedTableValue.SetForcedDataSetIndex(forcedDataSetIndex);
}
} else
{
AZ_Error("ScriptComponent",false,"Trying to force Property (%s) to unknown
DataSetIndex. Ignoring field.", scriptProperty->m_name.c_str());
}
In the example, if either of the error conditions occur, an annotation is created.
Another way to confirm that your annotations are in place is by using the Trace Messages profiler.
In the Profiler
Logging
channel, click the
Trace messages
profiler details icon to see the logging systems currently in place:
The
Trace messages
profiler instance shows all the trace messages that were generated from the start of the capture to the currently analyzed frame. Messages are shown with the oldest message at the top and the newest message at the bottom:
You can use the
Window Filter
to show the system and/or
Message Filter
to show the message text that you are interested in.
The following example, filtered by "GridMate", shows the message specified by the line of code that was added to the application:
Profiler is in preview release and is subject to change.
Version 1.10
1111
Lumberyard Developer Guide
Prerequisites
You can use the Lumberyard Profiler tool to examine how your game uses network bandwidth, including its GridMate carrier connections and replica activity. You can use network-specific profilers to drill down further into the activity of specific replica chunks, RPCs, and data sets.
This topic assumes familiarity with Lumberyard networking and the Lumberyard Profiler tool. For
information on Lumberyard networking, see Networking System (p. 1004)
. For an introduction to the
Profiler tool, see Profiler (p. 1098)
.
Topics
•
•
Replica Activity Profiler (p. 1113)
The Profiler tool has a GridMate channel with
Carrier
and
Replica activity
profiler instances. You can use the Carrier profiler detail view to examine the bandwidth usage of a selected GridMate carrier connection.
To open the detail view for the Carrier profiler
• Click the
Detailed Profiling Information
icon for
Carrier
in the GridMate channel:
The Carrier profiler detail view resembles the following image:
Version 1.10
1112
Lumberyard Developer Guide
Replica Activity Profiler
This view uses all of the data supplied in the capture session to show an overview of the bandwidth usage through the GridMate carrier for the selected connection. It includes the following information:
•
Total Sent/Total Received
– The total number of bytes sent and the total number of bytes received on the selected connection.
•
User Data Sent/User Data Received
– The user data sent and the user data received on the selected connection. This data does not include the overhead associated with carrier or connection maintenance.
•
Packets Sent/Packets Received
– The number of packets sent and the number of packets received.
•
Return Trip Time (Latency)
– How many seconds the packets took to make a return trip.
You can use the Replica Activity profiler to see how much replica bandwidth your application is using.
To open the Replica Activity profiler
• Click the
Detailed Profiling Information
icon for
Replica activity
.
The Replica Activity profiler detail view has a pair of
Bytes Sent
and
Bytes Received
graphs at the top, a toolbar to control the display in the middle, and a table of replicas at the bottom:
Version 1.10
1113
Lumberyard Developer Guide
Replica Activity Profiler
This view is useful for discovering how much bandwidth a single entity is using, and for finding what information is synchronized in response to particular events for particular entities.
Two main detail views are available for replica activity:
Replica
and
Chunk Type
. The view defaults to
Replica
, but Profiler remembers your most recent choice and uses it the next time you view replica activity details.
In replica view, the table shows how much data each replica used in a given frame.
To change the view to Replica
• In the toolbar, choose
Replica
.
Version 1.10
1114
Lumberyard Developer Guide
Replica Activity Profiler
Each replica is represented by its associated color in the graphs above the toolbar. Replica view includes the following information:
•
Bytes Sent
– Shows bandwidth usage in bytes sent by the object for a particular frame.
•
Bytes Received
– Shows bandwidth usage in bytes received by the object for a particular frame.
To display or hide an individual line in the graph
• Double-click the associated row in the tree.
The toolbar also offers the following options:
•
Hide All
– Hides the line graphs of all replicas in the table.
•
Show All
– Shows the line graphs for all replicas in the table.
•
Hide Selected
and
Show Selected
– Use
Ctrl+click
to select individual replicas in the table, and then click
Hide Selected
or
Show Selected
to hide or show the graphs for the replicas that you selected.
•
Display Range
– Determines the number of frames that are shown in the graph, with the currently selected frame in the center. You can use this option to zoom in or out on the data.
To display replica chunk details for a particular replica
• Click its details icon.
The graph shows the bytes sent and received for a replica chunk, data set, and RCP:
Version 1.10
1115
Lumberyard Developer Guide
Replica Activity Profiler
You can use this details view to see what replica chunk types a given replica is using, how much data each replica chunk type is using, and how much bandwidth individual data sets and RPCs are using.
Tip
Click
Expand All
to list all replica chunks in all replicas, and every data set and remote procedure call (RPC) in each replica chunk:
Version 1.10
1116
Lumberyard Developer Guide
Replica Activity Profiler
To use the Replica Activity profiler tree view
• Do either of the following:
• Select a row to highlight its corresponding line in the graph.
• Double-click a row to display or hide the graph for the row.
The following information is available:
•
Display Name
– The debug name associated with the corresponding row of the table.
•
Sent Bytes
– The number of bytes sent for an item, including all information sent by children of the item.
•
Received Bytes
– The number of bytes received by an item, including all information received by children of the item.
Version 1.10
1117
Lumberyard Developer Guide
Replica Activity Profiler
Chunk type view shows you how much data each chunk type used in a given frame. The view is useful for seeing how much information a particular system might be using across all entities.
To change the view to Chunk Type
• In the toolbar on the main detail page for
Replica activity
, choose
Chunk Type
.
The chunk type view shows how much data a particular replica chunk type is using in a given frame:
To inspect chunk type details
• Click the details icon for the chunk type:
The details window shows which replicas are using a chunk type's bandwidth, how much data they are using, and how much data the individual data sets and RPCs are using:
Version 1.10
1118
Lumberyard Developer Guide
Replica Activity Profiler
As before, you can expand the items in the tree to see detailed information about each:
Version 1.10
1119
Lumberyard Developer Guide
Using the Profiler for CPU Usage
Profiler is in preview release and is subject to change.
The CPU profiler gathers usage statistics about how long a function or method executed, how many times it was executed, who called it, and how much of a frame was spent on it. You can combine this information to get a systemwide view of usage, or isolate particular systems by filtering for specific threads.
To use the CPU profiler
1. To open the detail view for the CPU profiler, click the
Detailed Profiling Information
icon for the
CPU
profiler instance.
The CPU details view has a graph of CPU usage, a toolbar, and a tree view of calls made in a frame.
Each call in the tree view has the same color as its corresponding line in the graph:
2. Pause your mouse on a line in the graph to see the call that the line represents and to display the specific value for the graph at the area near the cursor.
3. To show or hide the line graph of a row in the tree, double-click the row.
Version 1.10
1120
Lumberyard Developer Guide
Understanding the Tree View
The CPU profiler tree view represents a call hierarchy of profiler log points (called
hooks
). A profiler hook that is active while another call is active shows as a child of the first hook. The hooks act as a stack:
The last hook that was pushed onto the stack is the parent of the hook that was pushed onto the stack before it. The tree view has the following information:
Function
The function declaration where the profiler data point was generated.
Comment
A user-defined message that distinguishes specific events in the same function.
Excl. Time (Micro)
(Exclusive time) The time, in microseconds, spent executing this function and no other functions called by this function.
Incl. Time (Micro)
(Inclusive time) The time, in microseconds, spent executing this function and other functions called by this function.
Excl. Pct
(Exclusive percent) Exclusive time represented as a percent of total run time.
Incl. Pct
Calls
(Inclusive percent) Inclusive time represented as a percent of total run time.
The number of calls to this function.
Child Time (Micro)
The time, in microseconds, that functions that were called by this function took to execute.
Total Time (Micro)
A running total of the time, in microseconds, that was spent inside of this function.
Child Calls
How many functions this function called.
Total Calls
The running total of how many times this function was called.
Thread ID
The thread on which this function was executed
You can use the toolbar to control how the captured CPU data is displayed:
Hide Selected
Hide the graph of the rows selected in tree view.
Version 1.10
1121
Lumberyard Developer Guide
Controlling the Display
Show Selected
Show the graph of the rows selected in tree view.
Hide All
Hides the graph of all rows in the tree view.
Show All
Shows the graphs of all rows in the tree view.
Invert
Shows graphs for all rows in the tree view that are hidden; hides the graphs of all rows in the tree view that are showing.
Expand Tree
Expands all rows in the tree view hierarchy.
The right side of the toolbar offers more options:
All Threads
Use the thread selector to control which threads are shown in the tree view and in the graph:
Incl. Time
Use this selector to choose the meaning of the time displayed.
•
Incl. Time
– (Inclusive time) The time spent in this function inclusively.
•
Excl. Time
– (Exclusive time) The time spent in this function exclusively.
•
Calls
– The number of times this function was called in the frame.
Version 1.10
1122
Lumberyard Developer Guide
Using Profiler for VRAM
•
Acc. Time
– (Accumulated time) The total amount of time spent in this function up to the frame being analyzed.
•
Acc. Calls
– (Accumulated calls) – The total number of times this function was called up to the frame being analyzed.
<number>
Frames
Use this selector to choose how frames of history are displayed in the graph:
Delta
Unused option.
Autozoom
When selected, maintains the approximate zoom level (number of frames displayed) whenever the graph changes.
Flat View
Flattens the tree of function calls (removes the hierarchical indentation), as in the following image:
Profiler is in preview release and is subject to change.
You can use the video memory profiler (VRAM profiler) to determine which resources are contributing most to run-time VRAM usage in your game.
The VRAM profiler records the amount of video memory used by a game, including how many memory deallocations and allocations occurred during the capture. This latter information is useful in tracking down rendering performance bottlenecks.
You can also use the memory usage information from VRAM profiler to determine your game's minimum
PC GPU (graphics processing unit) memory requirements, or to determine whether your game will run out of memory on a console or mobile device.
Version 1.10
1123
Lumberyard Developer Guide
Notes
Topics
•
•
Understanding the Captured Data (p. 1124)
•
The VRAM profiler has the following attributes:
• The VRAM profiler has no graph view or tree view.
• The only supported export format is
.csv
. For steps on saving Profiler data to a
.csv
file, see Exporting
Data .
• Lumberyard uses a variety of memory pooling schemes, so the actual allocated amount of VRAM is slightly more than what is reported.
The following image shows how your saved
.csv
file appears in a spreadsheet application:
The captured data contains essentially two tables of information: an overview of memory allocation and usage (divided between texture and buffer assets), and a list of resources with the amount of VRAM that was allocated for each during the capture.
Detailed information about each heading follows.
Category
Indicates the type of allocation:
•
Texture
– Includes texture assets, dynamically generated textures, and frame buffers.
•
Buffer
– Includes vertex and index buffers, constant buffers, and other run-time buffers.
Number of Allocations
The number of allocation events recorded. When the capture starts, all active allocations are sent to the profiler as a starting number. Any new allocations or deallocations will increase or decrease this number.
Memory Usage
The total size, in bytes, of VRAM used.
Version 1.10
1124
Lumberyard Developer Guide
Inspecting the Data
Resource Name
The name and full path of the allocated resource. A resource name without a path usually denotes a run-time engine resource.
VRAM Allocation Size
The size, in bytes, of the allocation.
When you first open the spreadsheet, the data is unordered. To sort the data, you can use a spreadsheet application:
To quickly and easily identify the largest offending assets or run-time resources, sort by
VRAM
Allocation Size
in descending order, or by
Resource Name
from A to Z:
Some fields may have a negative number for
VRAM Allocation Size
, as in the following image:
These important occurrences show that a VRAM deallocation event occurred during the capture. If you observe a large number of deallocation entries over a short time period, your game might be
Version 1.10
1125
Lumberyard Developer Guide
Using GridHub experiencing a significance decrease in performance. To improve your game's performance across all platforms, you should aim to have as few idle per-frame VRAM allocations and deallocations as possible.
If you see a lot of allocations named
StreamingTexturePool
or entries like
$TexturePool_9_0000000002C59248
, this means the texture streaming system is active. The texture streaming system allocates all textures by default into a variety of cached texture pools. The VRAM profiler reports the size of the active streaming pools and not the names of the actual texture assets.
To obtain the names and sizes of the allocated and loaded textures, set r_TexturesStreaming=0
in your system configuration file, and then do another capture. This setting disables the texture streaming system and causes the true sizes of the texture allocations to be reported.
Note
In this situation, it is advisable to do two captures: one with r_TexturesStreaming
enabled, and one with it disabled. When texture streaming is enabled, your VRAM usage is less because of texture eviction and the loading of lower resolution mipmap levels. The memory reporting is more accurate when texture streaming is enabled, but you get a much clearer view of your worst-case memory usage when texture streaming is disabled.
GridHub is in preview release and is subject to change.
GridHub is Lumberyard's connection hub for debugging. GridHub acts as a central hub through which specified local clients connect with each other and exchange information. When you run the Lumberyard diagnostic and debugging tools
Profiler.exe
or
LuaIDE.exe
(located in the
\dev\Bin64
directory),
GridHub launches as a background process in Windows and enables their functionality. For more
information about Profiler, see Profiler (p. 1098)
.
Note
Because GridHub listens for connections on the loopback address (
127.0.0.1
), you must run
GridHub on the same computer as the target application.
Topics
•
Registering an Application in GridHub (p. 1126)
•
Viewing and Configuring GridHub (p. 1126)
•
Troubleshooting GridHub (p. 1128)
To register an application in GridHub so that Profiler can capture information from the application, add
AzFramework::TargetManagementComponent
to the application’s
SystemComponent
.
Note
Lumberyard's built-in applications already have this component added by default.
When you launch
Profiler.exe
or
LuaIDE.exe
, GridHub starts automatically and is represented by a globe icon in the Windows taskbar.
Version 1.10
1126
Lumberyard Developer Guide
Viewing and Configuring GridHub
To view and configure GridHub
1. In the Windows taskbar, right-click the globe icon and choose
Show
:
The GridHub window has a configuration bar, a connections pane, and pane for viewing log messages:
2. You can use the configuration toolbar to view or change GridHub configuration:
The toolbar options are as follows:
Session port
– Specifies the port on which GridHub listens for discovery requests.
Connection slots
– Specifies the maximum number of applications that can be connected concurrently to GridHub.
Hub name
– The name of your hub. By default, this is the name of the local computer.
Note
The name of the hub must be the neighborhood name to which the
TargetManagementComponent
connects.
Enable Disconnection Detection
– Specifies whether the connection to GridHub is terminated when the source fails to respond.
Add to Windows startup folder
– Specifies whether GridHub starts automatically when Windows starts.
Log activity
– Starts or stops logging.
Version 1.10
1127
Lumberyard Developer Guide
Troubleshooting GridHub
Start/Stop
– Starts or stops GridHub. When GridHub is off, no connections are discovered or maintained.
3. When GridHub and your target application are active, your target application appears in the GridHub
Connections
list:
The columns in the
Connections
list provide the following information:
ID
– The identifier of the connected application.
Name
– The name of the connected application.
Connection ID
– The identifier of the connection between GridHub and the application.
IsHost
– Whether or not the connection is the connection host
IsLocal
– Whether or not the connection is local.
IsReady
– Whether or not the application is ready to handle further connections.
4. Use the
Output
window to see the log messages that GridHub generates as it manages connections:
When GridHub is terminated, the connections it established are also terminated.
If you experience difficulty using GridHub, check the following:
• Make sure that the neighborhood name in
TargetManagerComponent
is the same as the one in GridHub.
• Make sure that the port that GridHub is listening on is the same port as the one specified for
TargetManagementComponent
.
• Make sure that all applications are running on the same computer. The GridHub socket is bound to the loopback address
127.0.0.1
.
Version 1.10
1128
Lumberyard Developer Guide
Memory Handling
This section contains topics on general system issues, including memory handling, streaming, and localization. It also provides information on logging and console tools.
Topics
•
•
•
Text Localization and Unicode Support (p. 1141)
•
•
This article discusses some memory and storage considerations related to game development.
Developing for game consoles can be challenging due to memory limitations. From a production point of view, it is tempting to use less powerful hardware for consoles, but the expectations for console quality are usually higher in an increasingly competitive market.
It is often better to choose only one development platform, even if multiple platforms are targeted for production. Choosing a platform with lower memory requirements eases production in the long run, but it can degrade the quality on other platforms. Some global code adjustments (for example, TIF setting
"globalreduce", TIF preset setting "don't use highest LOD") can help in reducing memory usage, but often more asset-specific adjustments are needed, like using the TIF "reduce" setting. If those adjustments are insufficient, completely different assets are required (for example, all LODs of some object are different for console and PC). This can be done through a CryPak feature. It is possible to bind multiple pak files to a path and have them behave as layered. This way it is possible to customize some platforms to use
Version 1.10
1129
Lumberyard Developer Guide
Budgets different assets. Platforms that use multiple layers have more overhead (memory, performance, I/O), so it is better to use multiple layers on more powerful hardware.
Budgets are mostly game specific because all kinds of memory (for example, video/system/disk) are shared across multiple assets, and each game utilizes memory differently. It's a wise decision to dedicate a certain amount of memory to similar types of assets. For example, if all weapons roughly cost the same amount of memory, the cost of a defined number of weapons is predictable, and with some careful planning in production, late and problematic cuts can be avoided.
The Lumberyard memory manager tries to minimize fragmentation by grouping small allocations of similar size. This is done in order to save memory, allow fast allocations and deallocations and to minimize conflicts between multiple threads (synchronization primitives for each bucket). Bigger allocations run through the OS as that is quite efficient. It is possible to allocate memory in other than the main thread, but this can negatively impact the readability of the code. Memory allocated in one module should be deallocated in the same module. Violating this rule might work in some cases, but this breaks per module allocation statistics. The simple
Release()
method ensures objects are freed in the same module. The string class
(CryString)
has this behavior built in, which means the programmer doesn't need to decide where the memory should be released.
In general, it is better to perform skinning (vertex transformation based on joints) of characters on the
GPU. The GPU is generally faster in doing the required computations than the CPU. Caching the skinned result is still possible, but memory is often limited on graphics hardware, which tends to be stronger on computations. Under these conditions, it makes sense to recompute the data for every pass, eliminating the need to manage cache memory. This approach is advantageous because character counts can vary significantly in dynamic game scenes.
There are many lossy and lossless compression techniques that work efficiently for a certain kind of data.
They differ in complexity, compression and decompression time and can be asymmetric. Compression can introduce more latency, and only few techniques can deal with broken data such as packet loss and bit-flips.
Installing modern games on a PC can be quite time consuming. Avoiding installation by running the game directly from a DVD is a tempting choice, but DVD performance is much worse than hard drive performance, especially for random access patterns. Consoles have restrictions on game startup times and often require a game to cope with a limited amount of disk memory, or no disk memory at all. If a game is too big to fit into memory, streaming is required.
To keep the total size of a build small, the asset count and the asset quality should be reasonable. For production it can make sense to create all textures in double resolution and downsample the content
Version 1.10
1130
Lumberyard Developer Guide
Address Space with the Resource Compiler. This can be useful for cross-platform development and allows later release of the content with higher quality. It also eases the workflow for artists as they often create the assets in higher resolutions anyway. Having the content available at higher resolutions also enables the engine to render cut-scenes with the highest quality if needed (for example, when creating videos).
Many media have a format that maximizes space, but using the larger format can cost more than using a smaller one (for example, using another layer on a DVD). Redundancy might be a good solution to minimize seek times (for example, storing all assets of the same level in one block).
Some operating systems (OSes) are still 32-bit, which means that an address in main memory has 32bits, which results in 4 GB of addressable memory. Unfortunately, to allow relative addressing, the top bit is lost, which leaves only 2 GB for the application. Some OSes can be instructed to drop this limitation by compiling applications with large address awareness, which frees up more memory. However, the full 4 GB cannot be used because the OS also maps things like GPU memory into the memory space.
When managing that memory, another challenge appears. Even if a total of 1 GB of memory is free, a contiguous block of 200 MB may not be available in the virtual address space. In order to avoid this problem, memory should be managed carefully. Good practices are:
• Prefer memory from the stack with constant size (SPU stack size is small).
• Allocating from the stack with dynamic size by using alloca()
is possible (even on SPU), but it can introduce bugs that can be hard to find.
• Allocate small objects in bigger chunks (flyweight design pattern).
• Avoid reallocations (for example, reserve and stick to maximum budgets).
• Avoid allocations during the frame (sometimes simple parameter passing can cause allocations).
• Ensure that after processing one level the memory is not fragmented more than necessary (test case: loading multiple levels one after another).
A 64-bit address space is a good solution for the problem. This requires a 64-bit OS and running the 64-bit version of the application. Running a 32-bit application on a 64-bit OS helps very little.
Note that compiling for 64-bit can result in a bigger executable file size, which can in some cases be counterproductive.
To reduce memory bandwidth usage, make use of caches, use a local memory access pattern, keep the right data nearby, or use smaller data structures. Another option is to avoid memory accesses all together by recomputing on demand instead of storing data and reading it later.
Different types of memory have different access performance characteristics. Careful planning of data storage location can help to improve performance. For example, blending animation for run animation needs to be accessible within a fraction of a frame, and must be accessible in memory. In contrast, cutscene animations can be stored on disk. To overcome higher latencies, extra coding may be required. In some cases the benefit may not be worth the effort.
Some CPUs require proper alignment for data access (for example, reading a float requires an address dividable by 4). Other CPUs perform slower when data is not aligned properly (misaligned data access).
As caches operate on increasing sizes, there are benefits to aligning data to the new sizes. When new
Version 1.10
1131
Lumberyard Developer Guide
Virtual Memory features are created, these structure sizes must be taken into consideration. Otherwise, the feature might not perform well or not even work.
Most operating systems try to handle memory quite conservatively because they never know what memory requests will come next. Code or data that has not been used for a certain time can be paged out to the hard drive. In games, this paging can result in stalls that can occur randomly, so most consoles avoid swapping.
Streaming enables a game to simulate a world that is larger than limited available memory would normally allow. A secondary (usually slower) storage medium is required, and the limited resource is used as a cache. This is possible because the set of assets tends to change slowly and only part of the content is required at any given time. The set of assets kept in memory must adhere to the limits of the hardware available. While memory usage can partly be determined by code, designer decisions regarding the placement, use, and reuse of assets, and the use of occlusion and streaming hints are also important in determining the amout of memory required. Latency of streaming can be an issue when large changes to the set of required assets are necessary. Seek times are faster on hard drives than on most other storage media like DVDs, Blue-Rays or CDs. Sorting assets and keeping redundant copies of assets can help to improve performance.
Split screen or general multi-camera support add further challenges for the streaming system. Tracking the required asset set becomes more difficult under these circumstances. Seek performance can get get worse as multiple sets now need to be supported by the same hardware. It is wise to limit gameplay so that the streaming system can perform well. A streaming system works best if it knows about the assets that will be needed beforehand. Game code that loads assets on demand without registering them first will not be capable of doing this. It is better to wrap all asset access with a handle and allow registration and creation of handles only during some startup phase. This makes it easier to create stripped down builds (minimal builds consisting only of required assets).
The Lumberyard streaming engine takes care of the streaming of meshes, textures, music, sounds, and animations.
The file
IStreamEngine.h
in CryCommon contains all the important interfaces and structs used by the rest of the engine.
First of all there is the
IStreamEngine
itself. There is only one
IStreamingEngine
in the application and it controls all the possible I/O streams. Most of the following information comes directly from the documentation inside the code, so it's always good to read the actual code in
IStreamEngine.h
file for any missing information.
The most important function in
IStreamEngine
is the
StartRead
function which is used to start any streaming request.
IStreamEngine.h
Version 1.10
1132
Lumberyard Developer Guide
Low-level Streaming System
UNIQUE_IFACE struct IStreamEngine
{ public:
// Description:
// Starts asynchronous read from the specified file (the file may be on a
// virtual file system, in pak or zip file or wherever).
// Reads the file contents into the given buffer, up to the given size.
// Upon success, calls success callback. If the file is truncated or for other
// reason can not be read, calls error callback. The callback can be NULL
// (in this case, the client should poll the returned IReadStream object;
// the returned object must be locked for that)
// NOTE: the error/success/progress callbacks can also be called from INSIDE
// this function
// Return Value:
// IReadStream is reference-counted and will be automatically deleted if
// you don't refer to it; if you don't store it immediately in an auto-pointer,
// it may be deleted as soon as on the next line of code,
// because the read operation may complete immediately inside StartRead()
// and the object is self-disposed as soon as the callback is called.
virtual IReadStreamPtr StartRead (const EStreamTaskType tSource, const char* szFile,
IStreamCallback* pCallback = NULL, StreamReadParams* pParams = NULL) = 0;
};
The following are the currently supported streaming task types. This enum should be extended if you want to stream a new object type.
IStreamEngine.h
enum EStreamTaskType
{
eStreamTaskTypeCount = 13,
eStreamTaskTypePak = 12, // Pak file itself
eStreamTaskTypeFlash = 11, // Flash file object
eStreamTaskTypeVideo = 10, // Video data (when streamed)
eStreamTaskTypeReadAhead = 9, // Read ahead data used for file reading prediction
eStreamTaskTypeShader = 8, // Shader combination data
eStreamTaskTypeSound = 7,
eStreamTaskTypeMusic = 6,
eStreamTaskTypeFSBCache = 5, // Complete FSB file
eStreamTaskTypeAnimation = 4, // All the possible animations types (dba, caf, ..)
eStreamTaskTypeTerrain = 3, // Partial terrain data
eStreamTaskTypeGeometry = 2, // Mesh or mesh lods
eStreamTaskTypeTexture = 1, // Texture mip maps (currently mip0 is not streamed)
};
A callback object can be provided to the
StartStream
function to be informed when the streaming request has finished. The callback object should implement the following
StreamAsyncOnComplete
and
StreamOnComplete
functions.
IStreamEngine.h
class IStreamCallback
{ public:
// Description:
// Signals that reading the requested data has completed (with or without error).
// This callback is always called, whether an error occurs or not, and is called
// from the async callback thread of the streaming engine, which happens
// directly after the reading operation
virtual void StreamAsyncOnComplete (IReadStream* pStream, unsigned nError) {}
Version 1.10
1133
Lumberyard Developer Guide
Low-level Streaming System
// Description:
// Same as the StreamAsyncOnComplete, but this function is called from the main
// thread and is always called after the StreamAsyncOnComplete function.
virtual void StreamOnComplete (IReadStream* pStream, unsigned nError) = 0;
};
When starting a read request, you can also provide the optional parameters shown in the following code.
IStreamEngine.h
struct StreamReadParams
{ public:
// The user data that'll be used to call the callback.
DWORD_PTR dwUserData;
// The priority of this read
EStreamTaskPriority ePriority;
// Description:
// The buffer into which to read the file or the file piece
// if this is NULL, the streaming engine will supply the buffer.
// Notes:
// DO NOT USE THIS BUFFER during read operation! DO NOT READ from it, it can lead to
memory corruption!
void* pBuffer;
// Description:
// Offset in the file to read; if this is not 0, then the file read
// occurs beginning with the specified offset in bytes.
// The callback interface receives the size of already read data as nSize
// and generally behaves as if the piece of file would be a file of its own.
unsigned nOffset;
// Description:
// Number of bytes to read; if this is 0, then the whole file is read,
// if nSize == 0 && nOffset != 0, then the file from the offset to the end is read.
// If nSize != 0, then the file piece from nOffset is read, at most nSize bytes
// (if less, an error is reported). So, from nOffset byte to nOffset + nSize - 1 byte
in the file.
unsigned nSize;
// Description:
// The combination of one or several flags from the stream engine general purpose
flags.
// See also:
// IStreamEngine::EFlags
unsigned nFlags;
};
The return value of the
StartRead
function is an
IReadStream
object which can be optionally stored on the client. The
IReadStream
object is refcounted internally. When the callback object can be destroyed before the reading operation is finished, the readstream should be stored separately, and the abort should be called on it. Doing this will clean up the entire read request internally and will also call the async and sync callback functions.
The
Wait
function can be used to perform a blocking reading requests on the streaming engine. This function can be used from an async reading thread that uses the Lumberyard streaming system to perform the actual reading.
IStreamEngine.h
Version 1.10
1134
Lumberyard Developer Guide
Low-level Streaming System class IReadStream : public CMultiThreadRefCount
{ public:
virtual void Abort() = 0;
virtual void Wait( int nMaxWaitMillis=-1 ) = 0;
};
The Lumberyard stream engine uses extra worker and IO threads internally. For every possible IO input, a different
StreamingIOThread
is created which can run independently from the others.
Currently the stream engine has the following IO threads:
• Optical – Streaming from the optical data drive.
• Hard disk drive (HDD) – Streaming from installed data on the hard disk drive (this could be a fully installed game, or shadow copied data).
• Memory – Streaming from packed in-memory files, which requires very little IO.
When a reading request is made on the streaming engine, it first checks which IO thread to use, and computes the sortkey. The request is then inserted into one of the
StreamingIOThread
objects.
After the reading operation is finished, the request is forwarded to one of the decompression threads if the data was compressed, and then into one of the async callback threads. The amount of async callback threads is dependent on the platform, and some async callback threads are reserved for specific streaming request types such as geometry and textures. After the async callback has been processed, the finished streaming request is added to the streaming engine to be processed on the main thread. The next update on the streaming engine from the main thread will then call the sync callback
(
StreamOnComplete
) and clean up the temporary allocated memory if needed.
For information regarding the IO/WorkerThreads please check the
StreamingIOThread
and
StreamingWorkerThread
class.
Requests to the streaming engine are
not
processed in a the same order as which they have been requested. The system tries to internally 'optimize' the order in which to read the data, to maximize the read bandwidth.
When reading data from an optical disc , it is very important to reduce the amount of seeks. (This is also true when reading from a hard disk drive, but to a lesser extent). A single seek can take over 100 milliseconds, while the actual read time might take only a few milliseconds. Some official statistics from the 360 XDK follow.
• Outer diameter throughput : 12x (approximately 15 MB per second).
• Inner diameter throughput : 5x (6.8 MB per second).
• Average seek (1/3rd stroke) time : 110 ms typical, 140 ms maximum.
• Full stroke seek time : 180 ms typical, 240 ms maximum.
• Layer switch time : 75 ms.
The internal sorting algorithm takes the following rules into account in the following order.
•
Priority of the request
– High priority requests always take precedence, but too many of them can introduce too many extra seeks.
Version 1.10
1135
Lumberyard Developer Guide
Low-level Streaming System
•
Time grouping
– Requests made within a certain time are grouped together to create a continuous reading operation on the disc for every time group. The default value is 2 seconds, but can be changed using the following cvar: sys_streaming_requests_grouping_time_period
. Time grouping has a huge impact on the average completion time of the requests. It increases the time of a few otherwise quick reading requests, but drastically reduces the overall completion time because most of the streaming requests are coming from random places on the disc.
•
Actual offset on disc
– The actual disc offset is computed and used during the sorting. Files which have a higher offset get a higher priority, so it is important to organize the layout of the disc to reflect the desired streaming order.
For information regarding sorting, please refer to the source code in
StreamAsyncFileRequest::ComputeSortKey()
. The essential sorting code follows.
CAsyncIOFileRequest::ComputeSortKey
void CAsyncIOFileRequest::ComputeSortKey(uint64 nCurrentKeyInProgress)
{
.. compute the disc offset (can be requested using CryPak)
// group items by priority, then by snapped request time, then sort by disk offset
m_nDiskOffset += m_nRequestedOffset;
m_nTimeGroup = (uint64)(gEnv->pTimer->GetCurrTime() / max(1,
g_cvars.sys_streaming_requests_grouping_time_period));
uint64 nPrioriry = m_ePriority;
int64 nDiskOffsetKB = m_nDiskOffset >> 10; // KB
m_nSortKey = (nDiskOffsetKB) | (((uint64)m_nTimeGroup) << 30) | (nPrioriry << 60);
}
The streaming engine can be polled for streaming statistics using the
GetStreamingStatistics() function.
Most of the statistics are divided into two groups, one collected during the last second, and another from the last reset (which usually happens during level loading). Statistics can also be forcibly reset during the game.
The
SMediaTypeInfo
struct gives information per IO input system (hard disk drive, optical, memory).
IStreamEngine.h
struct SMediaTypeInfo
{
// stats collected during the last second
float fActiveDuringLastSecond;
float fAverageActiveTime;
uint32 nBytesRead;
uint32 nRequestCount;
uint64 nSeekOffsetLastSecond;
uint32 nCurrentReadBandwidth;
uint32 nActualReadBandwidth; // only taking actual reading time into account
// stats collected since last reset
uint64 nTotalBytesRead;
uint32 nTotalRequestCount;
uint64 nAverageSeekOffset;
uint32 nSessionReadBandwidth;
uint32 nAverageActualReadBandwidth; // only taking actual read time into account
Version 1.10
1136
Lumberyard Developer Guide
Low-level Streaming System
};
The
SRequestTypeInfo
struct gives information about each streaming request type, such as geometry, textures, and animations.
IStreamEngine.h
struct SRequestTypeInfo
{
int nOpenRequestCount;
int nPendingReadBytes;
// stats collected during the last second
uint32 nCurrentReadBandwidth;
// stats collected since last reset
uint32 nTotalStreamingRequestCount;
uint64 nTotalReadBytes; // compressed data
uint64 nTotalRequestDataSize; // uncompressed data
uint32 nTotalRequestCount;
uint32 nSessionReadBandwidth;
float fAverageCompletionTime; // Average time it takes to fully complete a request
float fAverageRequestCount; // Average amount of requests made per second
};
The following example shows global statistics that contain all the gathered data.
IStreamEngine.h
struct SStatistics
{
SMediaTypeInfo hddInfo;
SMediaTypeInfo memoryInfo;
SMediaTypeInfo opticalInfo;
SRequestTypeInfo typeInfo[eStreamTaskTypeCount];
uint32 nTotalSessionReadBandwidth; // Average read bandwidth in total from reset -
taking full time into account from reset
uint32 nTotalCurrentReadBandwidth; // Total bytes/sec over all types and systems.
int nPendingReadBytes; // How many bytes still need to be read
float fAverageCompletionTime; // Time in seconds on average takes to complete read
request.
float fAverageRequestCount; // Average requests per second being done to streaming
engine
int nOpenRequestCount; // Amount of open requests
uint64 nTotalBytesRead; // Read bytes total from reset.
uint32 nTotalRequestCount; // Number of request from reset to the streaming engine.
uint32 nDecompressBandwidth; // Bytes/second for last second
int nMaxTempMemory; // Maximum temporary memory used by the streaming system
};
Different types of debug information can be requested using the following CVar: sys_streaming_debug x
.
Version 1.10
1137
Lumberyard Developer Guide
Streaming and Levelcache Pak Files
As mentioned earlier, it is very important to minimize the seeks and seek distances when reading from an optical media drive. For this reason, the build system is designed to optimize the internal data layout for streaming.
The easiest and fastest approach is to not do any IO at all, but read the data from compressed data in memory. For this, small paks for startup and each level are created. These are loaded into memory during level loading. Some paks remain in memory until the end of the level. Others are only used to speed up the level loading. All small files and small read requests should ideally be diverted to these paks.
A special
RC_Job
build file is used to generate these paks:
Bin32/rc/RCJob_PerLevelCache.xml
. These paks are generated during a normal build pipeline. The internal managment in the engine is done by the
CResourceManager class, which uses the global
SystemEvents
to preload or unload the paks.
Currently, the following paks are loaded into memory during level loading ( sys_PakLoadCache
).
•
level.pak
– Contains all actual level data, and should not be touched after level loading anymore.
•
xml.pak
•
dds0.pak
– Contains all lowest mips of all the textures in the level.
•
cgf.pak
and
cga.pak
– Only load when CGF streaming is enabled.
The following paks are cached into memory during the level load process ( sys_PakStreamCache
).
•
dds_cache.pak
- Contains all dds files smaller than 6 KB (except for dds.0 files).
•
cgf_cache.pak
- Contains all cgf files smaller than 32 KB (only when CGF streaming is enabled).
Important
Be sure that these paks are available. Without them, level loading can take up to a few minutes, and streaming performance is greatly reduced.
The information regarding all the resources of a level are stored in the resourcelist.txt
and auto_resourcelist.txt
. These files are generated by an automatic testing system which loads each level and executes a prerecorded playthrough on it. These resourcelist
files are used during the build phase to generate the level paks.
All data not in these in memory paks is handled through IO on the optical drive or hard disk drive, and it is also best to reduce the amount of seeks here. This optimization phase is also performed during the build process using the resource compiler.
All the data which can be streamed is extracted from all the resource lists from all levels, and is removed from the default pak files (for example, objects.pak
, textures.pak
, animations.pak
) and put into new optimized paks for streaming inside a streaming folder.
The creating of the streaming paks uses the following rules:
• Split by
extension
: Different extension files are put into different paks (for example, dds, caf, dba, cgf) so that files of the same type can be put close to each other. This enables them to be read in bursts.
The paks are also used to increase the priority of certain file types during request sorting by using the disc offset.
• Split by DDS
type
: Different dds types are sorted differently to increase the priority of different types
(for example, diffuse maps get higher priority than normal maps). The actual distance in the pak is used during the sorting of the request.
Version 1.10
1138
Lumberyard Developer Guide
Single Thread IO Access and Invalid File Access
• Split by DDS
mip
: The highest mips are put into a separate pak file. They usually take more than 60% of the size of all the smaller mips and can then be streamed with a lower priority. This greatly reduces the average seek time required to read the smaller textures. The texture streaming system internally optimizes the reads to reflect these split texture data.
• Sort
alphabetically
: Default alphabetical sorting is required because some of the data (such as CGF's during MP level loading), are loaded in alphabetical order. Changing this sort order can have a severe impact on the loading times.
The actual sorting code is hardcoded in the resource compiler, and can be found at:
Code\Tools\RC
\ResourceCompiler\PakHelpers.cpp
.
Important
If you make changes to the sorting operator in the resource compiler, be sure to make the same changes to the texture streaming and streaming engine sorting operators.
It is very important that only a single thread access a particular IO device at one time. If multiple threads read from the same IO device concurrently, then the reading speed is more than halved, and it may take a number of seconds to read just a few kilobytes. This occurs because the IO reading head will partially read a few kilobytes for one thread, and then read another few kilobytes for another thread while always performing expensive seeks in between.
The solution is to exclusively read from
StreamingIOThreads
during gameplay. Lumberyard will by default show an
Invalid File Access
warning in the top left corner when reading data from the wrong thread, and will stall deliberately for threed seconds to emulate the actual stall when reading from an optical drive.
It is very easy to extend the current streaming functionality using the streaming engine. In this section, a small example class is presented that shows how to add a new streaming type.
First, create a class which derives from the
IStreamCallback
interface, which informs about streaming completion, and add some basic functionality to read a file. The file can either be read directly or use the streaming engine. When the data is read directly, it calls the
ProcessData
function to parse the loaded data. The function is also called from the async
callback. Some processing can be performed here on the data if needed because it does not run on the main thread.
The default parameters are used when starting a reading request on the streaming engine. It is also possible to specify the final data storage to help reduce the number of dynamic allocations performed by the streaming engine.
The class also stores the read stream object in order to get information about the streaming request or to be able to cancel the request when the callback object is destroyed. The pointer is reset in the sync callback because after the call it will no longer be referenced by the streaming engine.
CNewStreamingType
#include class CNewStreamingType : public IStreamCallback
{ public:
CNewStreamingType() : m_pReadStream(0), m_bIsLoaded(false) {}
~CNewStreamingType()
{
Version 1.10
1139
Lumberyard Developer Guide
High Level Streaming Engine Usage
if (m_pReadStream)
m_pReadStream->Abort();
}
// Start reading some data
bool ReadFile(const char* acFilename, bool bUseStreamingEngine)
{
if (bUseStreamingEngine)
{
StreamReadParams params;
params.dwUserData = eLoadFullData;
params.ePriority = estpNormal;
params.nSize = 0; // read the full file
params.pBuffer = NULL; // don't provide any buffer, but copy data when
streaming is done
m_pReadStream = g_pISystem->GetStreamEngine()-
>StartRead(eStreamTaskTypeNewType, acFilename, this, ¶ms);
}
else
{
// old way of reading file in a sync way (blocking call!)
const char* acData = 0;
size_t stSize = 0;
.. read file directly using CryPak or fopen/fread
ProcessData(acData, stSize);
m_bIsLoaded = true;
}
return m_bIsLoaded;
}
// Check if the data is ready and loaded
bool IsLoaded() const { return m_bIsLoaded; } protected:
// implement the IStreamCallback function
void StreamAsyncOnComplete(IReadStream* pStream, unsigned nError)
{
if(nError)
{
return;
}
const char* acData = (char*)pStream->GetBuffer();
size_t stSize= pStream->GetBytesRead();
ProcessData(acData, stSize);
m_bIsLoaded = true;
}
void StreamOnComplete (IReadStream* pStream, unsigned nError)
{
m_pReadStream = 0;
}
// process the actual loaded data
void ProcessData(const char* acData, size_t stSize);
// store the stream callback object to be sure it can be canceled when the object is
destroyed
IReadStreamPtr m_pReadStream;
// Extra flag used to check if the data is ready
Version 1.10
1140
Lumberyard Developer Guide
Text Localization and Unicode Support
bool m_bIsLoaded;
}
Because games are typically localized to various languages, your game might have to use text data for many languages.
This document provides programming-related information regarding localization, including localization information specific to Lumberyard.
The following table provides brief descriptions of some important terms related to localization and text processing.
Term
character
Unicode
UCS
Description
A unit of textual data. A character can be a glyph or formatting indicator. Note that a glyph does not necessarily form a single visible unit. For example, a diacritical mark
[´] and the letter [a] are separate glyphs (and characters), but can be overlaid to form the character [á].
A standard maintained by the Unicode Consortium that deals with text and language standardization.
Universal Character Set, the standardized set of characters in the Unicode standard
(also, ISO-10646)
(UCS) codepoint
An integral identifier for a single character in the UCS defined range, typically displayed with the U prefix followed by hexadecimal, for example: U+12AB
(text) encoding A method of mapping (a subset of) UCS to a sequence of code-units, or the process of applying an encoding.
code-unit An encoding-specific unit integral identifier used to encode code-points. Many codeunits may be used to represent a single code-point.
ASCII
(ANSI) codepage
A standardized encoding that covers the first 128 code-points of the UCS space using
7- or 8-bit code-units.
A standardized encoding that extends ASCII by assigning additional meaning to the higher 128 values when using 8-bit code-units There are many hundreds of codepages, some of which use multi-byte sequences to encode code-points.
UTF
UTF-8
UTF-16
UTF-32
UCS Transformation Format, a standardized encoding that covers the entire UCS space.
A specific instance of UTF, using 8-bit code-units. Each code-point can take 1 to 4
(inclusive) code-units.
A specific instance of UTF, using 16-bit code-units. Each code-point can take 1 or 2 code-units.
A specific instance of UTF, using 32-bit code-units. Each code-point is directly mapped to a single code-unit.
Version 1.10
1141
Lumberyard Developer Guide
What encoding to use?
Term
byte-order
Description
How a CPU treats a sequence of bytes when interpreting multi-byte values. A byteorderTypically either little-endian or big-endian format encoding error A sequence of code-units that does not form a code-point (or an invalid code-point, as defined by the Unicode standard)
Since there are many methods of encoding text, the question that should be asked when dealing with even the smallest amount of text is, "In what encoding is this stored?" This is an important question because decoding a sequence of code-units in the wrong way will lead to encoding errors, or even worse, to valid decoding that yields the wrong content.
The following table describes some common encodings.
Encoding
ASCII
(ANSI) codepage
UTF-8
UTF-16
UCS-2
UTF-32
UCS-4
Code-unit size
7 bits
8 bits
8 bits
16 bits
16 bits
32 bits
Code-point size
1 byte
Maps the entire UCS space
no varies, usually 1 byte no
1 to 4 bytes yes
Trivial to encode/ decode
yes varies, usually yes no
Immune to byte-order differences
yes
Major users
yes
Many
English-only apps
Older OS functions yes
2 to 4 bytes
2 bytes
4 bytes yes no yes yes yes yes no no no
Most text on the internet,
XML
Windows
"wide" API,
Qt
None
(replaced with
UTF-16)
Linux "wide"
API
Because there is no single "best" encoding, you should always consider the scenario in which it will be used when choosing one.
Historically, different operating systems and software packages have chosen different sets of supported encodings. Even C++ follows different conventions on different platforms. For example, the "wide character" wchar_t
is 16-bits on Windows, but 32-bits on Linux.
Because Lumberyard products can be used on many platforms and in many languages, full UCS coverage is desirable. The follow table presents some conventions used in Lumberyard:
Version 1.10
1142
Lumberyard Developer Guide
How does this affect me when writing code?
Text data type
Encoding Reason
Source code ASCII
Text assets UTF-8
We write our code in English, which means ASCII is sufficient.
Assets can be transferred between machines with potentially differing byteorder, and may contain text in many languages.
Run-time variables
File and path names
UTF-8
ASCII
Since transforming text data from or to UTF-8 is not free, we keep data in
UTF-8 as much as possible. Exceptions must be made when interacting with libraries or operating systems that require another encoding. In these cases all transformations should be done at the call-site.
File names are a special case with regards to case-sensitivity, as defined by the file system. Unicode defines 3 cases, and conversions between them are locale-specific. In addition, the normalization formats are typically not
(all) accounted for in file-systems and their APIs. Some specialized filesystems only accept ASCII. This combination means that using the most basic and portable sub-set should be preferred, with UTF-8 being used only as required.
General principles
• Avoid using non-ASCII characters in source code. Consider using escape sequences if a non-ASCII literal is required.
• Avoid using absolute paths. Only paths that are under developer control should be entered. If possible, use relative ASCII paths for the game folder, root folder, and user folder. When this is not possible, carefully consider non-ASCII contents that may be under a user's control, such as those in the installation folder.
Since single-byte code-units are common (even in languages that also use double-byte code-units), single-byte string types can be used almost universally. In addition, since Lumberyard does not use ANSI code-pages, all text must be either ASCII or UTF-8.
The following properties hold for both ASCII and UTF-8.
• The NULL-byte (integral value 0) only occurs when a NULL-byte is intended (UTF-8 never generates a NULL-byte as part of multi-byte sequences). This means that C-style null-terminated strings act the same, and CRT functions like strlen
will work as expected, except that it counts code-units, not characters.
• Code-points in the ASCII range have the same encoded value in UTF-8. This means that you can type
English string literals in code and treat them as UTF-8 without conversion. Also, you can compare characters in the ASCII range directly against UTF-8 content (that is, when looking for an English or
ASCII symbol sub-string).
• UTF-8 sequences (containing zero or more entire code-points) do not carry context. This means they are safe to append to each other without changing the contents of the text.
The difference between position and length in code-units (as reported through string::length()
, strlen()
, and similar functions) and their matching position and length in code-points is largely irrelevant. This is because the meaning of the sequence is typically abstract, and the meaning of the bytes matters only when the text is interpreted or displayed. However, keep in mind the following caveats.
Version 1.10
1143
Lumberyard Developer Guide
How does this affect me when dealing with text assets?
•
Splitting strings
– When splitting a string, it's important to do one of the following.
1. Recombine the parts in the same order after splitting, without interpreting the splitted parts as text
(that is, without chunking for transmission).
2. Perform the split at a boundary between code-points. The positions just before and just after any
ASCII character are always safe.
•
API boundaries
– When an API accepts or returns strings, it's s important to know what encoding the
API uses. If the API doesn't treat strings as opaque (that is, interprets the text), passing UTF-8 may be problematic for APIs that accept byte-strings and interpret them as ASCII or ANSI. If no UTF-8 API is available, prefer any other Unicode API instead (UTF-16 or UTF-32). As a last resort, convert to ASCII, but understand that the conversion is lossy and cannot be recovered from the converted string. Always read the documentation of the API to see what text encoding it expects and perform any required conversion. All UTF encodings can be losslessly converted in both directions, so finding any API that accepts a UTF format gives you a way to use UTF encoding.
•
Identifiers
– When using strings as a "key" in a collection or for comparison, avoid using non-ASCII sequences as keys, as the concept of "equality" of UTF is complex due to normalization forms and locale-dependent rules. However, comparing UTF-8 strings byte-by-byte is safe if you only care about equality in terms of code-points (since code-point to code-unit mapping is 1:1).
•
Sorting
– When using strings for sorting, keep in mind that locale-specific rules for the order of text are complex. It's fine to let the UI deal with this in many cases. In general, make no assumptions of how a set of strings will be sorted. However, sorting UTF-8 strings as if they were ASCII will actually sort them by code-point. This is fine if you only require an arbitrary fixed order for std::map
look-up, but displaying contents in the UI in this order may be confusing for end-users that expect another ordering.
In general, avoid interpreting text if at all possible. Otherwise, try to operate on the ASCII subset and treat all other text parts as opaque indivisible sequences. When dealing with the concept of
"length" or "size", try to consider using in code-units instead of code-points, since those operations are computationally cheaper. In fact, the concept of the "length" of Unicode sequences is complex, and there is a many-to-many mapping between code-points and what is actually displayed.
In general, always:
• Store text assets with UTF-8 encoding.
• Store with Unicode NFC (Normalization Form C). This is the most common form of storage in text editing tools, so it's best to use this form unless you have a good reason to do otherwise.
• Store text in the correct case (that is, the one that will be displayed). Case-conversion is a complex topic in many languages and is best avoided.
Lumberyard provides some utilities to make it easy to losslessly and safely convert text between
Unicode encodings. In-depth technical details are provided in the header files that expose the
UnicodeFunctions.h
and
UnicodeIterator.h
utilities.
The most common use cases are as follows.
string utf8; wstring wide;
Unicode::Convert(utf8, wide); // Convert contents of wide string and store into UTF-8
string
Version 1.10
1144
Lumberyard Developer Guide
Further reading
Unicode::Convert(wide, utf8); // Convert contents of UTF-8 string to wide string string ascii;
Unicode::Convert<Unicode::eEncoding_ASCII, Unicode::eEncoding_UTF8>(ascii, utf8); //
Convert UTF-8 to ASCII (lossy!)
Important
The above functions assume that the input text is already validly encoded. To guard against malformed user input or potentially broken input, consider using the
Unicode::ConvertSafe function.
For an introduction to Unicode, see The Absolute Minimum Every Software Developer Absolutely,
Positively Must Know About Unicode and Character Sets (No Excuses!) .
For official information about Unicode, see The Unicode Consortium .
You can log in Lumberyard by using the following global functions.
•
CryLog (eMessage)
•
CryLogAlways (eAlways)
•
CryError (eError)
•
CryWarning (eWarning)
•
CryComment (eComment)
If more control is required, the
ILog
interface can be used directly by using the following syntax.
gEnv->pLog->LogToFile("value %d",iVal);
You can control the verbosity of logging with the console variables log_Verbosity
and log_FileVerbosity
.
The following table shows the levels of verbosity and color convention. In the console, warnings appear in yellow, and errors appear in red.
Message
eAlways X eErrorAlways X
verbosity 0 verbosity 1 verbosity 2 verbosity 3 verbosity 4 Color in console
X
X
X
X
X
X
X
X
red
X X X X yellow
Version 1.10
1145
Lumberyard Developer Guide
Log Files
Message
eInput eInputResponse?
eError eWarning eMessage eComment -
-
verbosity 0 verbosity 1 verbosity 2 verbosity 3 verbosity 4 Color in console
?
?
?
?
?
-
-
-
?
X
-
?
X
X
-
?
X
X
X
?
X
X
X
X
red yellow
Key
• X – the message type is logged to the console or file
• ? – some special logic is involved
Tip
Full logging (to console and file) can be enabled by using log_Verbosity 4
.
The following log file sources write to the log files indicated.
Source
Lumberyard Editor
Game
Error messages
Log file
Editor.log
game.log
(default)
Error.log
The following console variables relate to logging.
log_IncludeTime
Toggles time stamping of log entries.
Usage: log_IncludeTime [0/1/2/3/4/5]
0=off (default)
1=current time
2=relative time
3=current+relative time
4=absolute time in seconds since this mode was started
5=current time+server time ai_LogFileVerbosity
None = 0, progress/errors/warnings = 1, event = 2, comment = 3
Version 1.10
1146
Lumberyard Developer Guide
CryConsole log_Verbosity DUMPTODISK defines the verbosity level for log messages written to console
-1=suppress all logs (including eAlways)
0=suppress all logs(except eAlways)
1=additional errors
2=additional warnings
3=additional messages
4=additional comments
The console is a user interface system which handles console commands and console variables. It also outputs log messages and stores the input and output history.
The game console supports color coding by using the color indices 0..9 with a leading $ character. The code is hidden in the text outputted on the console. Simple log messages through the
ILog
interface can be used to send text to the console.
This is normal $1one$2two$3three and so on
In the preceding example, one renders in red, two in green, and three (and the remaining text) in blue.
All console commands and console variables can be logged to a file by using the command
DumpCommandsVars
. The default filename is consolecommandsandvars.txt
.
To restrict the variables that should be dumped, a sub-string parameter can be passed. For example, the command
DumpCommandsVars i_ logs all commands and variables that begin with the sub-string "i_". (for example, i_giveallitems
and i_debug_projectiles
).
Console variables provide a convenient way to expose variables which can be modified easily by the user either by being entered in the console during runtime or by passing it as command-line argument before launching the application.
More information on how to use command-line arguments can be found in the Command Line
Arguments article.
Console variables are commonly referred to as
CVar
in the code base.
For an integer or float based console variable, it is recommended to use the
IConsole::Register() function to expose a C++ variable as a console variable.
Version 1.10
1147
Lumberyard Developer Guide
Adding New Console Commands
To declare a new string console variable, use the
IConsole::RegisterString()
function.
Console variables are exposed using the
ICVar
interface. To retrieve this interface, use the
IConsole::GetCVar()
function.
The most efficient way to read the console variable value is to access directly the C++ variable bound to the console variable proxy.
The console can easily be extended with new console commands. A new console command can be implemented in C++ as a static function which follows the
ConsoleCommandFunc
type. Arguments for this console command are passed using the
IConsoleCmdArgs
interface.
The following code shows the skeleton implementation of a console command: static void RequestLoadMod(IConsoleCmdArgs* pCmdArgs); void RequestLoadMod(IConsoleCmdArgs* pCmdArgs)
{
if (pCmdArgs->GetArgCount() == 2)
{
const char* pName = pCmdArgs->GetArg(1);
// ...
}
else
{
CryLog("Error, correct syntax is: g_loadMod modname");
}
}
The following code will register the command with the console system:
IConsole* pConsole = gEnv->pSystem->GetIConsole(); pConsole->AddCommand("g_loadMod", RequestLoadMod);
Console variable groups provide a convenient way to apply predefined settings to multiple console variables at once.
Console variables are commonly referred to as
CVarGroup
in the code base. Console variable groups can modify other console variables to build bigger hierarchies.
Warning
Cycles in the assignments are not detected and can cause crashes.
To register a new variable group, add a new
.cfg
text file to the
GameSDK\config\CVarGroups
directory.
sys_spec_Particles.cfg
[default]
; default of this CVarGroup
= 4 e_particles_lod=1
Version 1.10
1148
Lumberyard Developer Guide
Console Variable Groups e_particles_max_emitter_draw_screen=64
[1] e_particles_lod=0.75
e_particles_max_emitter_draw_screen=1
[2] e_particles_max_emitter_draw_screen=4
[3] e_particles_max_emitter_draw_screen=16
This creates a new console variable group named sys_spec_Particles
that behaves like an integer console variable. By default, this variable has the state
4
(set in the line following the comment in the example).
On changing the variable, the new state is applied. Console variables not specified in the
.cfg
file are not set. All console variables need to be part of the default section. An error message is output in case of violation of this rule.
If a console variable is not specified in a custom section, the value specified in the default section is applied.
The documentation of the console variable group is generated automatically.
sys_spec_Particles
Console variable group to apply settings to multiple variables sys_spec_Particles [1/2/3/4/x]:
... e_particles_lod = 0.75/1/1/1/1
... e_particles_max_screen_fill = 16/32/64/128/128
... e_particles_object_collisions = 0/1/1/1/1
... e_particles_quality = 1/2/3/4/4
... e_water_ocean_soft_particles = 0/1/1/1/1
... r_UseSoftParticles = 0/1/1/1/1
From the console
In the console you can type in the console variable group name and press tab. If the variable value is not represented, it will print the value of
RealState
.
sys_spec_Particles=2 [REQUIRE_NET_SYNC] RealState=3 sys_spec_Sound=1 [REQUIRE_NET_SYNC] RealState=CUSTOM sys_spec_Texture=1 [REQUIRE_NET_SYNC]
By calling the console command sys_RestoreSpec
you can check why the sys_spec_
variables don't represent the right states.
From C++ code
From the code you can use the member function
GetRealIVal()
and compare its return value against the result of
GetIVal()
in
ICVar
.
Version 1.10
1149
Lumberyard Developer Guide
Deferred execution of command line console commands
The commands that are passed via the command line by using the + prefix are stored in a separate list as opposed to the rest of the console commands.
This list allows the application to distribute the execution of those commands over several frames rather than executing everything at once.
Consider the following example.
--- autotest.cfg -hud_startPaused = "0" wait_frames 100 screenshot autotestFrames wait_seconds 5.0
screenshot autotestTime
-- console -crysis.exe -devmode +map island +exec autotest +quit
In the example, the following operations were performed:
• Load the island map.
• Wait for 100 frames.
• Take a screenshot called autotestFrames.
• Wait for 5 seconds.
• Take a screenshot called autotestTime.
• Quit the application.
Two categories of commands are defined: blocker and normal.
For each frame, the deferred command list is processed as a fifo. Elements of this list are consumed as long as normal commands are encountered.
When a blocker is consumed from the list and executed, the process is delayed until the next frame. For instance, commands like map
and screenshot
are blockers.
A console command (either command or variable) can be tagged as a blocker during its declaration using the
VF_BLOCKFRAME
flag.
The following synchronization commands are supported.
Optional Title
Command
wait_frames
num
:
Type
<int>
Description
Wait for
num
frames before the exeution of the list is resumed.
Version 1.10
1150
Lumberyard Developer Guide
CVar Tutorial
Command
wait_seconds
sec
:
Type
<float>
Description
Wait for
sec
seconds before the exeution of the list is resumed.
This tutorial shows you how to modify existing and create console variables (CVars). CVars can be used to control many configurable behaviors in Lumberyard. You can also use them in your game.
Note
This brief tutorial is intended for programmers. Most of the content uses code.
To create a console variable
1. In your code editor, open the
Code\GameSDK\GameDll\GameCVars.h
file, which declares all gamespecific CVars.
2. Locate the
SCVars
struct. Inside the struct, declare a new variable, as in the following example.
struct SCVars
{
int g_tutorialVar; //add this line
//... pre-existing code ...
};
The variable you added will be used to store the current value of the variable. If you need to store fractional numbers, you can also add a variable of the type float
.
Next, you will register the CVar with the game engine so that its value can be changed by using the console.
3. In the same
Code\GameSDK\GameDll\GameCVars.cpp
file, locate the
InitCVars
function.
void SCVars::InitCVars(IConsole *pConsole)
{
m_releaseConstants.Init( pConsole );
REGISTER_CVAR(g_tutorialVar, 42, VF_NULL, "This CVar was added using the tutorial on
CVars"); //add this line
//... pre-existing code ...
}
4. Specify a default value and help text for the variable. You can initialize the variable with any value that is valid for the type with which the variable was declared in the header file. The preceeding example specifies 42 as the default value and some help text that will be shown to users.
5. When your game unloads, be sure to un-register the variable. In the
Code\GameSDK\GameDll
\GameCVars.cpp
file, locate and use the
ReleaseCVars
function, as shown in the following example.
void SCVars::ReleaseCVars()
{
IConsole* pConsole = gEnv->pConsole;
pConsole->UnregisterVariable("g_tutorialVar", true); //add this line
Version 1.10
1151
Lumberyard Developer Guide
CVar Tutorial
//... pre-existing code ...
}
6. After you finish making changes, don't forget to compile your code.
You can now change the value of the CVar that you created by using code, the console, and
.cfg
files.
From code
To access the value of the variable in your game code, use the g_pGameCVars
pointer, as shown in the following example.
int myTutorialVar = g_pGameCVars->g_tutorialVar;
From the console
To change the value of the cvar from the console, use the syntax
cvar_name
=
cvar_value
. The following example sets the value of the g_tutorialVar
console variable to 1337.
g_tutorialVar = 1337
From .cfg files
It's also possible to change the default CVar value from one of the
.cfg
files. Whenever a CVar is assigned a value, its previous value is discarded. Therefore, the last assignment is the one that is current.
The following list shows the order of initialization for console variables.
1. The value specified in the
GameCVars.cpp
file when
REGISTER_CVAR
is used. (A change here requires compiling.)
2. The value specified in the system.cfg
file.
3. The value specified in the user's user.cfg
file.
4. Any value assigned at game runtime.
Tip
To change the default value of an existing CVar without having to compile, add a line to system.cfg
file to override the default.
Version 1.10
1152
Lumberyard Developer Guide
As we continue to improve Lumberyard, we want to thank everyone in our developer community.
Without your participation in the forums, your messages, and your bug reports, Lumberyard wouldn't be as strong as it is.
• Keep sending your feedback to
.
• If you haven't spoken up on the forums yet, we would love to have you.
• You can also keep up with new changes on our blog and leave comments to let us know what you think.
Version 1.10
1153
Advertisement
Entity-Component System
Modular Behavior Tree
AI System
Cloud Canvas
Components and EBuses
Gems
AZ Modules
The Entity-Component System is a design pattern for organizing game objects. It allows you to create flexible and reusable game objects by separating their data and behavior into components.
Cloud Canvas is a service that allows you to easily integrate AWS cloud services into your Lumberyard game. This allows you to create games with features like cloud saving, multiplayer, and more.
Gems are self-contained code modules that you can use to add new features to your Lumberyard game. They can be used for a wide range of purposes, such as adding new gameplay mechanics, implementing cloud features, and more.
How can I find job-related messages?
To help me find the messages, please tell me what you are looking for. Are you looking for a specific section, the text itself, or a summary?
Login to continue