data driven development the technology behind live-ops
TRANSCRIPT
Data Driven Development
The Technology Behind Live-Ops
About Me
Daniel MenardCo-founder and CEO
First Spin Out
Products
•Power Based
• Short Burst + Long Tail
•Qualitative
•Reviews
Services
• Stamina Based
• Survival + Build Up
•Quantitative
•React to Players
Products and Services
Commit Graphs
Game Launch
Commit GraphsGame
Launch
•Code Quality
•Analytics
•Ongoing Production
Effects on Tech
•Now a major concern
•Must be able to add and remove features easily
•Maintenance dwarfs production
Code Quality
•Key metrics and balancing
• Log everything
• Free solutions available
•Prioritize analysis capabilities
Analytics
•Real-Time Data
• Time Lagged Data
•No Data
•Wrong Data
Analytics
•Only require designers to add content• Good tools• Configuration data
•Changes informed by analytics
•Regular Patches• Regular QA• Submit to App Stores
Ongoing Production
Deliver
GatherAnalyse
Adjust
Tightening the Loop
7 day review
1-30 days
•Decouple data from logic code
•Create a data model for your game
•Game becomes it’s own “runtime” for your data
•Configuration files
Data Driven Development
•Data can be made accessible to all
•Better code
• Flat class hierarchy
•Objects become containers for data
Why should you care
Designer Data
LevelsBalance SettingsItem Definitions
Player Data
ProgressionInventoryAchievementsHigh Scores
Runtime Data
HealthScoreCombo Counter
Class Separation
Anti-Pattern: Configuration Classes
•Classes which extend and only override defaults
•Configuration should be moved to data class and injected
•Create new classes only when consuming different data
Data Model
Shop Item- Key- Name- Price- Icon- Requirements- Costs- Trigger- Effects
Shop Group- Key- Name- Items
Requirement- Text- LUA Function
Effect- Text- LUA Function
Trigger- Key
Cost- Text- LUA Function- Mutator
1
*
1
*
*
*
*
*
*
Spectrum
Virtual Machine
Scripted Bindings
Domain Specific
Language
Configuration Files
Entirely Hardcoded
Over-Engineering
•Be pragmatic
•Balance customizability with schedule
•Don’t reinvent the wheel, use scripting languages
•Pick one and stick with it• LUA, Javascript, Python, many available
•Make sure you can interop easily
•Use it as a configuration language too• JSON, Lua Pickle
Scripting Language
• Tolua++• Code generation from headers
•Create regular C++ class
•Make accessible to LUA
LUA Binding
enemiesData = CCDictionary:create()
-- BOOMERdata = BoomerData:create("Boomer1")data:setWeaknessDamageType(DamageType_All)data:setEnemyType(EnemyType_Boomer)data:setImpactType(ImpactType_Explosion)data:setCanBeThrown(true)data:setIndependent(true)data:setSoundPrefix("Boomer")data:addAnimationFile("boomer_animations")data:addAnimationFile("boomer_explode")enemiesData:setObject(data, data:getKey():getCString())
Example
function parseNeighbourhood(neighbourhoodDefinition)local neighbourhood = NeighbourhoodData:create(neighbourhoodDefinition.key);
neighbourhood:setCollectionMapPosition(neighbourhoodDefinition.collectionMapPosition); neighbourhood:setCollectionTimeMs(neighbourhoodDefinition.collectionTimeMs); neighbourhood:setImagePath(neighbourhoodDefinition.imagePath); neighbourhood:setMapPosition(neighbourhoodDefinition.mapPosition); neighbourhood:setSoundKey(neighbourhoodDefinition.soundKey); neighbourhood:setZOrder(neighbourhoodDefinition.zOrder);
if neighbourhoodDefinition.coinReward ~= nil then neighbourhood:setCoinReward(neighbourhoodDefinition.coinReward); end
if neighbourhoodDefinition.toothReward ~= nil then neighbourhood:setToothReward(neighbourhoodDefinition.toothReward); end
return neighbourhood;end
local levels = CCArray:create();
local neighbourhoodDefinitions = loadFileSafe("Scripts/Data/neighbourhoods.lua", {ccc3=ccc3, ccp=ccp});for key, neighbourhoodDefinition in pairs(neighbourhoodDefinitions) do levels:addObject(parseNeighbourhood(neighbourhoodDefinition));end
Example
return{ { key="Neighbourhood1", collectionMapPosition=ccp(741, 1120), collectionTimeMs=(60 * 60 * 1000), imagePath="Images/UI/Map/map_redlight01.png", mapPosition=ccp(191, 795), soundKey="Env_RedLight", toothReward=1, zOrder=4 }, …}
Example
Player Data
•Player data depends on designer data
•Designer data is expected to change
• Isolate them from each other
•Database-style keys
•Necessary because Apple delivery is slow• 1-3 weeks spent in review• Android is much better
•Necessary to keep binary small• 50-100MB over-the-air limits• Universal apps
Downloader
•Restrictions on downloading executable code• No DLLs• Scripts a gray zone
•Bandwidth costs• No longer covered by the store
Considerations
•Ability to segment content by• Platform• Device capabilities• Test group
• Security
•Data Consistency
Requirements
• Simple HTTP Client
• JSON Manifest File
•Package files
•Cryptographic Signatures
Our implementation
{"manifest_version": 1,"name": "Big Action Mega Fight","version": "2","url": "http://update.dblstallion.com/bamf/manifest.php?{...}" "files": [
{"name": "patch1.dz","url": "
http://update.dblstallion.com/bamf/patch1.dz","signature":
"TWFuIGlzIGRpc3Rpbmd1aXNoZWQsIG5vdCBvb…"}
]}
Manifest File
• SHA-1 Hash, signed with private key
•Public key in game memory
• Ensures data consistency
• Ensures data is yours
Signatures
A/B Testing
1
2A 2B
3
50% 50%
•Always maintain a control group
•Can test multiple options (not just 2)
•Need a lot of time to determine winner
• Some groups will never merge back
A/B Testing
•Have a way to update someone’s save file
• Format may change
•Designer data may change
•Do not risk data loss• Unit Testing• QA
Save File Transformation
•http://www.slideshare.net/KostasAnagnostou/data-driven-game-development
•http://www.igda.org/montreal/vid_liveops
References