420 likes | 604 Vues
Reflection for Tools Development. Jeremy Walker. Senior Tools Programmer Ubisoft Vancouver. Table of Contents. Understanding the Costs of Tools Development The Ultimate Technique for Data Driven Solutions A Reflection-Powered Infrastructure for Tools. 1. The Problem. 2. Reflection.
E N D
Reflection for Tools Development Jeremy Walker Senior Tools Programmer Ubisoft Vancouver
Table of Contents Understanding the Costs of Tools Development The Ultimate Technique for Data Driven Solutions A Reflection-Powered Infrastructure for Tools 1. The Problem 2. Reflection 3. Content Framework
1. The Problem Understanding the Costs of Tools Development
Hard Coded vs. Data Driven Systems Data Driven System Hard Coded System Animation Animation Animation Tools Hard Coded Animation System Animation Build System Animation Serialization Animation Engine
What's the Cost of Great Workflows? Sounds Animation Scenes Animation Tools Sound Editing Tools Scene Editing Tools Sound Build System Scene Build System Animation Build System Animation Serialization Sound Serialization Scene Serialization Sound Playback Engine Scene Rendering Engine Animation Engine
Great Workflows for All Types of Content SHARED SHARED SHARED SHARED SHARED SHARED Videos Materials Cameras Cut Scenes HUD Scenes Animation Curves Front End Input State Flows Scripts Music Skeletons Sequences Particles Props Shaders Models Levels AI Textures Characters Sounds SHARED SHARED SHARED SHARED SHARED SHARED SHARED SHARED SHARED SHARED SHARED SHARED
The Keep-It-Simple Approach SHARED SHARED SHARED SHARED SHARED SHARED Materials Scenes Props Particles Cut Scenes Cameras Input HUD Scripts Front End Videos Animation State Flows Textures AI Levels Models Curves Skeletons Characters Music Sequences Shaders Sounds Hard Coded Hard Coded Hard Coded Hard Coded SHARED SHARED SHARED SHARED SHARED SHARED Hard Coded Hard Coded Hard Coded SHARED SHARED SHARED SHARED SHARED SHARED Hard Coded Hard Coded Hard Coded Hard Coded Hard Coded
The Monolithic Engine Approach Materials Particles AI Textures Characters Input Cameras Front End Models Cut Scenes Levels Animation Shaders Scenes Scripts HUD Curves State Flows Videos Music Skeletons Props Sequences Monolithic Engine Sounds Animation, Sounds, Scenes, Input, Front End, Cameras, Particles, Characters, Textures, AI, Levels, Models, Shaders, Materials, HUD, Props, Skeletons, Music, Sequences, State Flows, Curves, Videos, Scripts, Cut Scenes Animation, Sounds, Scenes, Input, Front End, Cameras, Particles, Characters, Textures, AI, Levels, Models, Shaders, Materials, HUD, Props, Skeletons, Music, Sequences, State Flows, Curves, Videos, Scripts, Cut Scenes Animation, Sounds, Scenes, Input, Front End, Cameras, Particles, Characters, Textures, AI, Levels, Models, Shaders, Materials, HUD, Props, Skeletons, Music, Sequences, State Flows, Curves, Videos, Scripts, Cut Scenes Animation, Sounds, Scenes, Input, Front End, Cameras, Particles, Characters, Textures, AI, Levels, Models, Shaders, Materials, HUD, Props, Skeletons, Music, Sequences, State Flows, Curves, Videos, Scripts, Cut Scenes
The Problem Low Development Cost Game and Genre-Specific Needs Adaptable To Change Stable Tools ? Reusable Systems Great Workflows
The Solution For all types of content: Minimize the cost of developing great workflows. Design reusable systems while accommodating game-specific needs. Develop stable tools that adapt to constant change during production.
The Package Release Cycle Source Code Release Candidate Release yes yes Testing Process Programmer Modifies Code Artist Gets Package Release Artist Requests New Features Automated Build Process OK? OK? no no
The Monolithic Package Release Problem Monolithic Package Source Code Monolithic Package Release
The Benefit of Decoupled Packages Package Source Code Package Release Package Source Code Package Release Package Source Code Package Release Package Source Code Package Release Package Source Code Package Release
The Lockstep Release Problem Animation Tool Source Code Animation Tool Release Lockstep Release Cycle Compile Time Dependency Run Time Dependency Sound Tool Source Code Sound Tool Release Compile Time Dependency Run Time Dependency Game Source Code Game Release
Reducing Cost and Complexity Scenes Scenes Materials Materials Characters Cameras HUD Props Particles Characters Particles Cameras HUD Props Monolithic Engine Sounds Sounds Animation Animation Decoupled Systems Decoupled Systems Hardcoded Engine Animation, Sounds, Scenes, Input, Front End, Cameras, Particles, Characters, Textures, AI, Levels, Models, Shaders, Materials, HUD, Props, Skeletons, Music, Sequences, State Flows, Curves, Videos, Scripts, Cut Scenes Hard Coded Animation, Sounds, Scenes, Input, Front End, Cameras, Particles, Characters, Textures, AI, Levels, Models, Shaders, Materials, HUD, Props, Skeletons, Music, Sequences, State Flows, Curves, Videos, Scripts, Cut Scenes Animation, Sounds, Scenes, Input, Front End, Cameras, Particles, Characters, Textures, AI, Levels, Models, Shaders, Materials, HUD, Props, Skeletons, Music, Sequences, State Flows, Curves, Videos, Scripts, Cut Scenes Reflection Animation, Sounds, Scenes, Input, Front End, Cameras, Particles, Characters, Textures, AI, Levels, Models, Shaders, Materials, HUD, Props, Skeletons, Music, Sequences, State Flows, Curves, Videos, Scripts, Cut Scenes Medium Cost Complex Reuse All or Nothing Great Workflow Low Cost Simple Very Reusable Great Workflow Low Cost Simple • Hard to Reuse Poor Workflow High Cost Very Complex Very Reusable Great Workflow
2. Reflection The Ultimate Technique for Data Driven Solutions
What is Reflection? From Wikipedia: “…Reflection is the process by which a computer program can observe and modify its own structure and behaviour.”
Case Study: C++ Compilation Function Declaration Discover Expose Function B calls Function A C++ Compiler C++ Compiler Function A Reflection Binding to Function Definition Validate Implement
Reflection for Language Interoperability Type Definitions Discover Expose C# Code C# Compiler Visual Basic Compiler Visual Basic Code Reflection Type Binding Validate Implement
Reflection for Scripting in Games Type Definitions Discover Expose Lua Script Script Adapter C++ Adapter C++ Classes Reflection Type Binding Validate Implement
Reflection for Serialization in Games Type Definitions Discover Expose Serialized Objects Serializer C++ Adapter C++ Classes Reflection Type Binding Validate Implement
Common Language Specification Type Definitions Type Binding Reflection • Type size and alignment • Native types • Classes • Enums • Allocate objects • Binary representation • Invoke constructor, get/invoke members • Get/set enum value
Reflection in Action Example: Print all fields of type “float” Output const Type* type = TypeOf<SimpleVehicle>(); const char* name = type->Name(); size_t size = type->Size(); printf(“Type: %s\n Size: %d\n”, name, size); Instance vehicle = type->CreateInstance(); vehicle.As<SimpleVehicle&>().m_MaxSpeedKPH = 193.12f; for (inti=0; i<type->NumMembers(); i++) { const Member* member = vehicle.GetMember(i); if (member->IsField()) { const Field* field = (Field*)member; if (field->GetType() == TypeOf<float>()) { Instance value = vehicle.GetField(field); printf(“Field: %s\n Offset: %d\n Value: %.2f\n”, field->Name(), field->Offset(), value.As<float>()); } } } Type: SimpleVehicle Size: 4 Field: MaxSpeedKPH Offset 0 Value: 193.12
Popular Approaches to C++ Reflection Macros Code Parser Type Definition Language
Reflection with Macros Macros Example • Pros • No external tools • Cons • Awkward to implement • Hard to debug • Run-time discovery class SimpleVehicle : public Entity { public: DECLARE_TYPE(); float m_MaxSpeedKPH; void Reset(booluseDefaults); float GetMaxSpeedMPH() const; void SetMaxSpeedMPH(float maxSpeedMPH); }; //In a separate .CPP file: DEFINE_TYPE(SimpleVehicle) BASE_CLASS(Entity) FIELD(“MaxSpeedKPH”, m_MaxSpeedKPH) METHOD(Reset) PROPERTY(GetMaxSpeedMPH, SetMaxSpeedMPH) DEFINE_TYPE_END()
Reflection with Code Parser Code Parser Example • Pros • Easier to implement • Compile-time discovery • Cons • Slow pre-build step /// [Class] class SimpleVehicle : public Entity { public: /// [Field(“MaxSpeedKPH”)] float m_MaxSpeedKPH; /// [Method] void Reset(booluseDefaults); /// [Property] float GetMaxSpeedMPH() const; /// [Property] void SetMaxSpeedMPH(float maxSpeedMPH); };
Reflection with Type Definition Language Type Definition Language Example • Pros • Easiest to implement • No slow pre-build • Cons • Can’t reflect existing classes class SimpleVehicle : Entity { float MaxSpeedKPH; void Reset(booluseDefaults); float MaxSpeedMPH { get; set; } };
Exporting Type Definitions for Game Generated Binder Code C++ Reflected Types (game-side) Reflection System (game-side) Code Parser Types.xml C++ Class Types.xml /// [Class] class SimpleVehicle : public Entity { public: /// [Field(“MaxSpeedKPH”)] float m_MaxSpeedKPH; /// [Method] void Reset(booluseDefaults); /// [Property] float GetMaxSpeedMPH() const; /// [Property] void SetMaxSpeedMPH(float maxSpeedMPH); }; <type name=“SimpleVehicle”> <field name=“MaxSpeedKPH” type=“float”/> <method name=“Reset” returntype=“void”> <parameter name=“useDefaults” type=“bool”/> </method> <property name=“MaxSpeedMPH” type=“float” hasget=“true” hasset=“true”/> </type>
Exporting Type Definitions for Tools C++ Reflected Types (game-side) C# Proxy Generator Reflection System (tool-side) Types.xml Code Parser Types.xml C# Proxy Class <type name=“SimpleVehicle”> <field name=“MaxSpeedKPH” type=“float”/> <method name=“Reset” returntype=“void”> <parameter name=“useDefaults” type=“bool”/> </method> <property name=“MaxSpeedMPH” type=“float” hasget=“true” hasset=“true”/> </type> [ProxyType(“SimpleVehicle”, 0x81c37132)] public partial class SimpleVehicle : Entity { public float MaxSpeedKPH { get { return this.Instance.GetField(“MaxSpeedKPH”).Get<float>(); } set { this.Instance.GetField(“MaxSpeedKPH”).Set<float>(value); } } } public float MaxSpeedMPH { ... } public void Reset(booluseDefaults) { ... } }
Primary Uses for Reflection in Tools Types.xml Serialization Client-Server Remoting Reflection System Generated UI (PropertyGrid, TreeView, etc.)
Client-Server Remoting Tools (Client) Game (Server) Type Definitions Type Definitions Discover Discover Expose Expose Generated C# Proxy Classes C# Proxy Generator Remoting Client Remoting Server C++ Adapter C++ Game Classes Reflection Reflection Type Binding Type Binding Validate Validate Implement Implement
Problems and Workarounds Type definitions out of sync Detect type checksum mismatch Detect problems early Auto-synchronization of type information Auto-migration of data
Problems and Workarounds Tools tightly coupled to the game Avoid overuse of generated proxy classes Use generated UI where possible Use polymorphic proxy classes Tools Code Base Class has proxy has no proxy Derived Class A Derived Class B Derived Class C
Problems and Workarounds Excessive memory usage Strip type information based on usage Auto-detect unused reflected types
Other Uses for Reflection Marshalling events for multi-processor architectures Client-Server Remoting for Online Serialization of saved game data
3. Content Framework A Reflection-Powered Infrastructure for Tools
Content Framework Tool-side Game-side 3rd Party Content Framework Asset Explorer Asset Repository Package System Build System Asset Previewing Asset Manager Reflection
Promising Results Fast tools development Great workflows for all types of content Decoupled systems with improved reusability and resilience to change