450 likes | 694 Views
Data Driven Development. The Technology Behind Live-Ops. About Me. Daniel Menard Co-founder and CEO. First Spin Out. Products and Services. Services. Stamina Based Survival + Build Up Quantitative React to Players. Products. Power Based Short Burst + Long Tail Qualitative Reviews.
E N D
Data Driven Development The Technology Behind Live-Ops
About Me Daniel MenardCo-founder and CEO
Products and Services Services Stamina Based Survival + Build Up Quantitative React to Players Products • Power Based • Short Burst + Long Tail • Qualitative • Reviews
Commit Graphs Game Launch
Commit Graphs Game Launch
Effects on Tech • Code Quality • Analytics • Ongoing Production
Code Quality • Now a major concern • Must be able to add and remove features easily • Maintenance dwarfs production
Analytics • Key metrics and balancing • Log everything • Free solutions available • Prioritize analysis capabilities
Analytics • Real-Time Data • Time Lagged Data • No Data • Wrong Data
Ongoing Production • Only require designers to add content • Good tools • Configuration data • Changes informed by analytics • Regular Patches • Regular QA • Submit to App Stores
Tightening the Loop 7 day review 1-30 days
Data Driven Development • Decouple data from logic code • Create a data model for your game • Game becomes it’s own “runtime” for your data • Configuration files
Why should you care • Data can be made accessible to all • Better code • Flat class hierarchy • Objects become containers for data
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 1 • Trigger • Key * • Requirement • Text • LUA Function • Shop Item • Key • Name • Price • Icon • Requirements • Costs • Trigger • Effects * • Shop Group • Key • Name • Items 1 * * • Cost • Text • LUA Function • Mutator * * • Effect • Text • LUA Function *
Over-Engineering • Be pragmatic • Balance customizability with schedule • Don’t reinvent the wheel, use scripting languages
Scripting Language • 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
LUA Binding • Tolua++ • Code generation from headers • Create regular C++ class • Make accessible to LUA
Example • enemiesData = CCDictionary:create() • -- BOOMER • data = 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 • functionparseNeighbourhood(neighbourhoodDefinition) • localneighbourhood = 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); • ifneighbourhoodDefinition.coinReward ~= nil then • neighbourhood:setCoinReward(neighbourhoodDefinition.coinReward); • end • ifneighbourhoodDefinition.toothReward ~= nil then • neighbourhood:setToothReward(neighbourhoodDefinition.toothReward); • end • returnneighbourhood; • end • locallevels = CCArray:create(); • localneighbourhoodDefinitions = loadFileSafe("Scripts/Data/neighbourhoods.lua", {ccc3=ccc3, ccp=ccp}); • forkey, neighbourhoodDefinitionin 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 • }, • … • }
Player Data • Player data depends on designer data • Designer data is expected to change • Isolate them from each other • Database-style keys
Downloader • 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
Considerations • Restrictions on downloading executable code • No DLLs • Scripts a gray zone • Bandwidth costs • No longer covered by the store
Requirements • Ability to segment contentby • Platform • Device capabilities • Test group • Security • Data Consistency
Our implementation • Simple HTTP Client • JSON ManifestFile • Package files • Cryptographic Signatures
Manifest File { • "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…" • } • ] }
Signatures • SHA-1 Hash, signed with private key • Public key in game memory • Ensures data consistency • Ensures data is yours
A/B Testing 1 50% 50% 2A 2B 3
A/B Testing • 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
Save File Transformation • Have a way to update someone’s save file • Format may change • Designer data may change • Do not risk data loss • Unit Testing • QA
References • http://www.slideshare.net/KostasAnagnostou/data-driven-game-development • http://www.igda.org/montreal/vid_liveops
Thank You! www.doublestalliongames.com dan@dblstallion.com@dblstallion