We're sorry but this page doesn't work properly without JavaScript enabled. Please enable it to continue.
Feedback

Modelling complex game economy with Neo4j

00:00

Formal Metadata

Title
Modelling complex game economy with Neo4j
Title of Series
Number of Parts
163
Author
License
CC Attribution - NonCommercial - ShareAlike 3.0 Unported:
You are free to use, adapt and copy, distribute and transmit the work or content in adapted or unchanged form for any legal and non-commercial purpose as long as the work is attributed to the author in the manner specified by the author or licensor and the work or content is shared also in adapted form only under the conditions of this
Identifiers
Publisher
Release Date
Language

Content Metadata

Subject Area
Genre
Abstract
The challenge of modelling and balancing the economy of a large scale game is one of the biggest problems game developers face and one that many have tried to solve by simply throwing man-hours at it... But there's a better way! Learn how Gamesys did it by leveraging graph database Neo4j to model the in-game economy of our MMORPG "Here Be Monsters" and automate the balancing process. We'll discuss lessons learned, successes and challenges, and how a graph database enables our small team of game designers to stay agile and focused on delivering new content to players.
Product (business)AlgorithmHand fanGame theoryNatural languageProcess (computing)Virtual machineAliasingObservational studyCausalityMusical ensembleChemical equationDatabaseGraph (mathematics)JSONXMLUML
Mobile WebFacebookFront and back endsSoftware developerGame theoryReal numberDifferent (Kate Ryan album)Endliche ModelltheoriePower (physics)Analytic setMereologyDatabase2 (number)Multiplication signGraph (mathematics)Reading (process)State of matterProcess (computing)FamilySequelWaveBit rateTotal S.A.Data conversionXMLJSONUML
TheoryGraph (mathematics)Data modelEuler, LeonhardDatabaseView (database)Graph (mathematics)Endliche ModelltheorieData storage deviceKey (cryptography)Row (database)Software developerTable (information)Graph theoryDomain nameEuler, LeonhardGraph (mathematics)Natural numberMultiplication signGraph (mathematics)Basis <Mathematik>Web pageCASE <Informatik>QuicksortMereologySpacetime
Bridging (networking)Vertex (graph theory)MassBridging (networking)Process (computing)SoftwareDomain nameSoftware developerGraph (mathematics)Graph (mathematics)1 (number)Level (video gaming)Element (mathematics)CodecMereologyComputer animation
Game theoryDatabaseGraph (mathematics)Local ringMonster groupPhysical lawUniform resource locatorException handlingProcess (computing)Physical systemReal numberMotion captureStructural loadTwitterNetwork topologyMultiplication signStreaming mediaOnline helpFacebookCross-platformCore dumpData storage deviceLie groupObservational studyFrequencyShared memoryString (computer science)Computer animationJSONXMLUML
IBM RPGTerm (mathematics)Arithmetic progressionCategory of beingSpacetimeLocal ringGame theoryPower (physics)FacebookMultiplication signElement (mathematics)Forcing (mathematics)Computer clusterIBM RPGJSONXMLUML
Game theoryMereologyCombinational logicLine (geometry)State of matterMonster groupGraph (mathematics)QuicksortMeasurementCountingScaling (geometry)ExistenceFeedbackComputer animation
MereologyGraph (mathematics)Monster groupCombinational logicState of matterComputer animation
Graph (mathematics)HypermediaMonster groupGame theoryFood energyContent (media)Different (Kate Ryan album)State of matterMultiplication signBuildingComputer animation
Game theoryChemical equationSoftware developerGame theoryContent (media)Term (mathematics)TouchscreenDifferent (Kate Ryan album)Grass (card game)Process (computing)Sound effectPurchasingMathematicsWater vaporReal numberCuboidAddress spaceCAN busGradientNumberGreen's functionComputer animation
Error messageRamificationComplex (psychology)Level (video gaming)CognitionMereologyLimit (category theory)Sound effectDecision theoryGame theoryError messageDirected graphResultantProcess (computing)IBM RPGRight angleClient (computing)Multiplication signWeb 2.0Projective planeContent (media)Traffic reportingComputing platformGraphics tabletSoftware testingJSONXMLUML
Surjective functionBit rateGame theoryArmQuicksortWeb pageGraph (mathematics)Drop (liquid)Graph (mathematics)StatisticsBit rateInformationType theoryGraph (mathematics)Category of beingAlgorithmNumberEndliche ModelltheorieSet (mathematics)FlagMonster groupUniform resource locatorNetwork topologyView (database)CodeProcess (computing)Link (knot theory)MetreConnectivity (graph theory)Point (geometry)Event horizonMetropolitan area networkObservational studyQuantum stateDiagram
Game theoryChemical equationGraph (mathematics)Connectivity (graph theory)NumberDifferent (Kate Ryan album)Game theoryGraph (mathematics)OutlierMereologyChemical equationMonster group
Query languageResultantSocial classInstance (computer science)DatabaseFilm editingType theoryMultiplication signReal numberMathematicsChainFormal languageMathematical analysisMereologySimilarity (geometry)WordRadiusKey (cryptography)Pattern languageCategory of beingGraph (mathematics)Directed graphZirkulation <Strömungsmechanik>Pattern matchingBuildingLatent heatJSONXMLUML
QuicksortRight angleGraph (mathematics)ChainValue-added networkNetwork topologyQuery languageSet (mathematics)Direction (geometry)Graph (mathematics)Pattern languageInstance (computer science)TouchscreenNichtkommutative Jordan-AlgebraSquare numberSpacetimeDifferent (Kate Ryan album)Wave packetComputer animation
Network topologyDifferent (Kate Ryan album)Endliche ModelltheorieUniform resource locatorSquare numberType theoryGraph (mathematics)CircleNumber1 (number)Chain
Pattern languageMereologyDatabaseLine (geometry)Graph (mathematics)Theory of relativityEndliche ModelltheorieRelational databaseRecursionDiagram
Water vaporArithmetic progressionData modelComplex (psychology)Line (geometry)Group actionThread (computing)Game theoryMereologyEvent horizonInformationPrice indexSummierbarkeitNumberMultiplication signArithmetic progressionAtomic numberMonster groupSpacetimeHypermediaPoint (geometry)1 (number)Term (mathematics)Endliche ModelltheorieSmoothingGame controllerComputer animation
HierarchyMonster groupMonster groupHierarchyMereologyKey (cryptography)Set (mathematics)Multiplication signEncryptionCASE <Informatik>ChainQuery languageCombinational logicRight angleInsertion lossInformationState of matter
Process (computing)TouchscreenRight angleSubgraphSubstitute goodMonster groupGraph (mathematics)HierarchyGame theoryBit rateArithmetic mean
Monster groupBit rateoutputDrop (liquid)Monster groupCASE <Informatik>DivisorHierarchy1 (number)NumberSound effectNichtlineares GleichungssystemFlagEntire functionCalculationAverageArithmetic progressionDrop (liquid)Endliche ModelltheorieLikelihood functionGraph (mathematics)Bit rateAnalytic continuationLink (knot theory)State of matterPower (physics)SurfaceRight angleLevel (video gaming)Parity (mathematics)MereologySystem callProcess (computing)outputDirected graphJSON
MathematicsTouch typingCanadian Mathematical SocietyComputer fileNumberCASE <Informatik>Scaling (geometry)Entire functionLevel (video gaming)Game theoryConfidence intervalMultiplicationMultiplication signGraph (mathematics)Software bugProduct (business)Graph (mathematics)Revision controlProper mapGoodness of fitDatabaseVideo gameSoftware developerUniform resource locatorXMLComputer animation
DataflowStrategy gameSoftware developerSoftware bugMathematicsSoftware developerDifferenz <Mathematik>DebuggerComputer fileGraph (mathematics)DataflowGame theoryFront and back endsLocal ringSpecial unitary groupMereologyState of matterSoftware development kitValidity (statistics)Logic gateService (economics)Strategy gameComputing platformDifferent (Kate Ryan album)Computer animation
Local ringClient (computing)Set (mathematics)String (computer science)Attribute grammarTranslation (relic)Software testingElectronic visual displayIntegrated development environmentSocial classBranch (computer science)Latent heatAspect-oriented programmingServer (computing)Intercept theoremProcess (computing)Game theoryStructural loadWeightCategory of beingProduct (business)MathematicsDifferent (Kate Ryan album)MultiplicationSoftware frameworkFile formatComputing platformService (economics)TouchscreenMultiplication signMonster groupInternetworkingTexture mappingComputer programmingPlanningFamilyChainUniform resource locatorCodeLine (geometry)JSONXMLUML
Category of beingString (computer science)Convex hullComa BerenicesDigital electronicsComputer fileAreaDesign by contractInternationalization and localizationContext awarenessCodeFluid staticsLine (geometry)Category of beingLocal ringComputer configurationAttribute grammarCovering spaceString (computer science)Social classType theoryUniform resource locatorStatisticsStress (mechanics)Set (mathematics)WaveArithmetic meanPoint (geometry)Process (computing)Monster groupMatching (graph theory)XML
Bit rateMathematical optimizationAlgorithmWell-formed formulaGoodness of fitProcess (computing)Water vaporStatisticsMultiplication signNatural languageMonster groupResultantBit rateClosed setGame theorySet (mathematics)Error messageGraph (mathematics)DivisorNumberWeb 2.0Functional (mathematics)Point (geometry)Term (mathematics)Normal (geometry)Menu (computing)Marginal distributionDifferent (Kate Ryan album)JSONXMLUML
Bayesian networkNumberIterationProcess (computing)Set (mathematics)Different (Kate Ryan album)Maxima and minimaDistribution (mathematics)Game theorySelectivity (electronic)Fitness functionElectric generatorBit rateMonster groupAlgorithmError messageStatisticsIdeal (ethics)Multiplication signShape (magazine)Marginal distributionClosed setVector potentialTerm (mathematics)MassStaff (military)Functional (mathematics)CASE <Informatik>Optimization problemServer (computing)ResultantRational numberComputer animation
Uniform resource locatorComputer simulationMonster groupFitness functionGame theoryForceState of matterNumberSensitivity analysisMetropolitan area networkGraph (mathematics)JSONXMLUML
Bayesian networkGame theoryE-bookGame theoryDatabaseGraph (mathematics)Point (geometry)Military baseComa BerenicesTraffic reportingElectric generatorCovering spaceXML
Transcript: English(auto-generated)
Cool, well, we're gonna start and thank you everyone for staying around so late to watch my talk. And for today's talk, we're gonna look at one of our games in production right now and we're gonna show you how we actually model the game as a graph and we use the data we have in the graph database to answer some interesting questions we have about a game and help us automate some of the
balancing process that we had to do manually before. And then we're gonna look at some of the tools we also built around the game to help us get data into Neo4j as well. Some of the genetic algorithms that we've written to help us do some of the process, some of the stuff that we have to do manually before as well. My name is Yen Chui. I often go by the online alias of the Burning Monk
because I'm a big fan of this 90s rock band called Rage Against the Machine. They're the best ever, so you've heard it here. And we're for a company called Gamesys. We are based in central London and we are one of the market leaders in the field of real money gambling. But my team, we focus on slightly different style games where we build 3D model games
that you typically find on Facebook and mobile. I'm a backend developer there and I work on a backend for most of our games up to date. And across our games today, we have around a million daily active users coming back to our games every day to play. And between them, they generate somewhere around 250 million requests per day. And pretty much anything you do in our games
are recorded and analyzed. And for that, we capture around two to three terabytes of data for analytics every month, which doesn't take into account the amount of data that we have to manage to facilitate your actual gameplay. And for our databases where we keep our user data, we see somewhere up to about 25,000 ops per second
with an interesting twist in that everything you do in the game tend to modify your state in some way. So we see a very high read to write ratio, typically around one to one. So in order to meet our data needs, we do a lot of research in our own time to look at different database solutions and see how we can improve on things.
And as part of that, I talked to a lot of people. And from those conversations, it's kind of disappointing for me that I find the view the developers have of NoSQL is very biased and dominated by MongoDB, as well as other key value stores in general. And the graph database has largely been overlooked.
Even though for me, graph database is probably more the most natural way for you to model a domain. And something that we all tend to know intrinsically anyway. If I ask anyone of you to start, okay, to model this domain for me on paper, chances are you're probably gonna be drawing a graph with nodes and edges.
I haven't met anyone who instinctively start drawing tables of rows and columns and ask them to do this by hand. And graph databases are also built on top of very solid stuff. It's based on the graph theory which is invented by Leonhard Euler back almost 300 years ago.
And that was 275 years before the relational model was even defined. So at the time, Euler was trying to solve a problem that later on became known as the seven bridges of Konigsberg, where he needed to find a path through the city that would cross each of the bridges once, only once.
So the way he approached this problem was by first limiting any unnecessary features of the map so that you end up with just the land masses and the bridges that connect them. He then further abstracted away those details so that you end up with just nodes and edges and what we known as the graph is born. Now this technique should be very familiar to you
as developers because it's the same mental exercise of distilling entities down to their bare element, or entities and their relationships down to their very essence. And it's the same process that we go through where you model domains in software. And for the rest of the talk, I'm gonna use Heavy Monsters,
one of our games production, as examples to show you some interesting things you can do with a graph database. Heavy Monsters is a location-based game where everything is happening in the virtual world that's very similar to Medieval Earth, except all the monsters from your local folk laws and legends, they are real and they live in harmony with these elf-like natives
until one day this mysterious starry start to fall from the sky and wherever they land, they cause corruption amongst the local populations of monsters and cause them to start attacking people. So your job as the hero in the story is to impart capture these corrupted monsters
and cure them. There are over 500 different places you can visit in the game, all of which are named after real world locations that existed in that period of time. And on every continent you have a town where you can find loads of NPCs and shops and other players who are just hanging out. The game is episodic and is also story-driven,
whereby the storyline is broken up into seasons and episodes within seasons. Season one started in London and took the player all over to all over Europe before we moved the story to the Far East in season two and based around Nanjing, which is the ancient capital of China.
As you travel around the world, you see other players who are just finding items or doing quests and you can interact with them and talk to them. There's also a global chat system where you can go and ask for help if ever stuck on a quest or whenever we're running social engagement campaigns such as we give you some clues about location. So go to the place where you find the river
from the north of China, meets the stream from the south and you find some special treasure under a tree. So people will start engaging on these global chat systems as well as on Facebook and Twitter to share ideas, okay, where should we go to find this amazing thing? And then you can also ask the players that you see in the game to become your buddies, which works across the multiple platforms
that we have the game on right now. And as a game, we are very focused on making sure that we don't ever block you in terms of progress and force you to spam your friends to get past like many games that you find on Facebook these days. We find it very annoying and we don't want to pass this annoyance
onto our players. And the game is also localized in Brazilian Portuguese. And lastly, it's a RPG game. So you find the same gameplay elements from many other RPG titles you find in the gaming space. And as you travel around, you encounter a lot of NPCs as well as finding items. And the items that you find,
they can be combined together to make more powerful or interesting items using recipes. Now for this game, we actually done a lot of research to make sure that all the things you find in the game, they are where they should be in the real world. So through our players' feedbacks, we often hear that the players find the game educational as well as fun to play.
And when you encounter NPCs in the game, they can give you a story as they can give you a quest that you have to perform in order to drive you along the storyline. And often as part of doing a quest, you need to go and catch a monster. In order to catch a monster, you need to be at the right place and using the right combination of both bait and trap.
So if we take Ruby Dragon as example, he only exists in certain parts of the world. So if you wanna catch him, you have to first travel to that part of the world where he exists, and then you have to make a bait that he actually likes so that you can then lure him to your trap. And once you have to see it in doing so, you have to make sure that you're using a trap
that's strong enough against a powerful flying monster like the Ruby Dragon in order to actually capture him. There are plenty of monsters in the game, and every time we do release new content, we also introduce new monsters and new traps. And different monsters require different traps and baits. And besides all of these things you can do in the game,
you also have a homestead you can tend to where you can grow crops in order for cooking because your guy needs to eat to get energy to travel around. And you can also keep livestock. And then you can also build workshops and alchemy labs and whatnot in order to craft items. And you can take your livestock and put them through your workshop
to grind them into meat. And then you can take the meat you get back and cook them on your campfire to make steak and so on and so forth. And you can also just decorate and let your imaginations go wild as some of our players have done. And one of the interesting challenges that we face and many other game developers like us
is to making sure that the game is well balanced in terms of its content. There are many different aspects of this particular challenge, one of which is to do with the in-game economy. So if you take the camouflage box trap at the top of the screen here, for example, it's actually one of the earliest traps you make in the game. You can make it using a number of different ingredients,
including a bucket of paint. And to make the paint, you have to first make the items you need to make the black ink from octopus and you need to make some green dye by crafting grass and the water together. So now if someone says, I want to up the price of a basic ingredient like water,
that price change have to trickle all the way up the ladder. And when you consider how many things are made from water and then how many more things are made from those items, then you have a huge amount of knock-on effects you have to deal with. And if you don't address these knock-on effects, you're going to create arbitrage opportunities within your economy and players will be to make
lots of money by just grinding and they have less incentive to make real money purchases with us. And one of the problem with that is that, well, for starters, I'll be out of a job because my company won't be paying my salaries anymore. So the stakes are pretty high as far as I'm concerned. And as for game designer,
that means you constantly have to face this huge amount of uncertainty from all these knock-on effects. You just can't see the ramifications of your decisions. And for the players, this probably doesn't really matter that much because all that complexity is just part of the game, part of the intricacy of this particular game you're playing. But for us game developers,
it's level is complexities that we will need to manage. And managing it using our limited amount of cognitive resources is just impossible. You are bound to fail and trying to balance the game like this by hand is very slow, it's very repetitive, and worst of all, it's also very error-prone and the result you're gonna get back at the end
is gonna be very highly subjective. What feels right to one person can be completely off for somebody else. Now I've heard a lot of stories of how companies approach these kind of problems by just throwing bodies at it. You have from one of my ex-colleagues told me about a very long-standing M&O RPG that has been around for a decade or more
with a team of 100 QA engineers and part of their job is to play the game every day by hand for days and weeks and sometimes even months at a time and we pull back, how does the game feel? Does it feel balanced, does it feel right? We have a very small team behind the project. At peak, we have one QA engineer for iPad
and one QA engineer for the web and we want those guys to focus on testing the things that matter, the interactivities, whether or not there are any bugs in the client. They shouldn't be wasting their time testing the game content which should be shared across different platforms anyway. So we needed a way to work smarter and more efficiently
and we needed a more scientific and systematic approach and that is where Neo4j comes in. So if you take Bigfoot as an example, as you visit his Almanac page in the game which is a sort of in-game Wikipedia, if you like, you can see where in the world you can find him and you can see what baits he likes as well as a chance of attracting him to a trap
with that bait. You can also see what traps you need to make in order to catch him and your chance of success. If this monster drops a loot, you will find out what that loot is and applying the same modeling technique that we saw earlier, we can actually represent all of this information as a graph in Neo4j
whereby the monsters, the traps, the items and locations, they're all represented as nodes and connected by directed edges. You can associate an arbitrary set of properties with both nodes and edges. So for monsters and traps, they will have their stats and based on those stats, we can calculate that
the can-catch relationship between them has a success rate of 77.4%. We don't calculate by hand anymore. We are using genetic algorithms to work those out and we look at how we do that in F-sharp later on. Every item will have some properties as well depending on the type of item we're talking about
but usually they will include both the buy and sell prices as well as the number of flags that tells you whether or not you can sell the item or how you can use it. And since the Bigfoot drops a loot, we also specify in the relationship there the chance of him dropping that loot.
Now if you expand this graph to bring other nodes into the view, then you start to see other monsters as well. So here we can see to make the bait for Bigfoot, we need to craft a roaring goat recipe at the apprentice workshop that you have to build at home and in order to do that, you need to get some ingredients for it.
You can get the goat from McDonald's farm that exists in London. You can harvest honey from beehives that you build at home but you also need yeti fur, which is something that yeti drops as loot. So yeti is another monster that you have to catch with the same trap but he requires other bait so you can keep expanding your graph to bring other things
and see how everything is connected. And when you set all the way back, this is what the game looks to me as a graph where every item, every quest, location, they're all presented as nodes and the size of the nodes tells you how many, the number of connections that's coming in and out of those nodes. We have many outliers in this graph
whereby say common monsters like the sylph exist in many parts of the world and can be caught using a number of different traps and baits and similarly when you have base ingredients such as salt, which is used in many different cooking recipes. So now that we're able to model the game as a graph,
let's see how we can actually use that data to answer interesting questions and help us automate our balancing. So first thing we want to do is we want to be able to understand the impact of change. Now this is very similar to the kind of things people do in derivative pricing and finance. In fact, I know for a fact that the guys
at Credit Suisse is using Neo4j to do very similar type of analysis for real economy that we are doing here for virtual one. And if you take white bread as an example and to work out the blast radius of any price change involving white bread, let's look at what relationship that exists between an item and recipe whereby an item is used in a recipe
to craft another item. Now to find items that are made from white bread either directly or indirectly, we can write a Cypher query. Cypher is just the building query language for Neo4j where we're looking for, in this query, we're looking for items that are connected
to white breads through at least one instance of either is used in or craft relationships. A couple of things to note about this query is that all we're doing is we're applying pattern matching. We're looking for a specific pattern between nodes within our big graph. We can actually take the picture we draw earlier
and translate it almost one-to-one to a query that we can execute in Neo4j, which I think is a very powerful concept. It allows me to, it's very intuitive and allows me to think visually based on something that I would just draw on a piece of paper and turn that almost one-to-one to something that I can run against my database.
We can optionally filter the nodes on both sides of this relationship by type as well as by values of properties on those nodes. We can do the same type of filtering by type with relationships. And here we are saying that the type of relationship that exists between these two nodes must be either crafts or is used in.
Importantly, we also specify a cardinality so that we can capture indirect relationships so that if A makes B and B makes C, we also capture A and C as a result in our query, which we then return using the return keyword. So running this is gonna get back
something like a graph like this where we have the purple nodes as items, the red nodes as recipes. So from here, we can see that white bread in the sort of right center there is used directly in 10 recipes, but through sausages is then used in five more recipes.
So whenever someone wants to change the price of white bread, he will then have to go and change all the price for all 15 of these items. So let's see how that actually works, how the query actually works. Suppose we have a set of items that's connected to white bread like this. We want to identify the three nodes in this graph as items that are derived from white bread.
And since we're saying that between these two nodes, there need to be one more instance of these relationships between them, we can find the items that are made directly from white bread because we can find those relationships between these two nodes. And similarly, we can identify the other two items
that are made indirectly from white bread because somewhere between white bread and these two nodes, they exist, it's used in all-craft relationships. But not all of the items in the world can be priced based on some other things. Some of the items have to be priced manually based on other factors such as how scarcely available are they in the world.
And when you consider fruits, they don't just exist on their own. You have to find them on fruit trees. Whereas you travel around, you have to find the mango tree and to get some mango, you have them pick those mango from the tree. So in order to calculate the scarcity for mango and other fruits, we have to look at how they related to fruit trees.
So fruit trees exist in a spot, which is a location, and they forage fruit. So we can do something like this to help us calculate the scarcity for durian and dragon fruit. And just like the first example, all we're doing here is we're looking for a particular pattern that consists of three nodes
and two relationships connected by forages and existing relationships in opposite directions. And we again, we just hit a graph that we saw by hand earlier, translate it visually then directly to what I will execute on Neo4j. And here we also filtering the fruits based on name.
And when I run this, I'll get back something like this, whereby the blue squares are the locations and the purple circles are items. So straight away I can see that dragon fruit trees are in a lot of different places. But durian trees only exist in two places in the world.
What you don't see from this graph though, is that the existing relationship actually specifies the number of trees of that particular type that exist in that location. So our model takes that into account as well when calculating the scarcity for the fruits. And since durians are much more scarce in the world, they're also more expensive.
So it costs you three banknotes to buy a pack of five, whereas a dragon fruit costs you one banknote to buy a pack of five. Now let's look at the quest and understand how they relate to the items. Some quests will require you to go and gather some items, maybe to go to London and buy a gold from Bob,
the farmer, or to find some other item somewhere, or to catch a monster and get his loot in order to progress. And when you complete the quest, you sometimes also get an item as reward. And completing a quest also then unlocks the follow-up quest in the storyline. So we also have a recursive relationship here,
which is usually very hard to model in the relational databases. So if the custom support team comes to me and asks, okay, someone is asking, what quest do I get when I complete the Year of the Horse? We can just write something very simple like this by pattern matching against two quest nodes
that are connected by the unlock relationship. And we can tell them that, okay, once you've done that, you can unlock five more quests. And again, if we step back, this is actually what the quest lines looks like. It's a big ball of complexity that I don't wanna look at, but somewhere in that big ball of three, there's a single thread that takes you
from the very first quest in the game to the very latest. But just being able to visualize how all these quests tie together is actually not all that interesting. Now that we know that the price of an item is an indication of how difficult it is to obtain the item in the first place, be it it's more expensive to buy, or you have to craft it
by making a craft number of intermediate items first, which impacts the cost of the item. So its cost is now indication of its difficulty. And now since quests require items to have a cost associated with them, we can use that cost to price the quests themselves and give you indication of how difficult it is
for you to complete the quest. And once we've done that, we can then reorder the quest or change the items that the quest requires, or to just make the items more easily attainable so that as the player plays through the game in the main storyline, there's a smooth progression in terms of difficulty,
so it gives you cheaper quests at the start and more expensive ones later on. And we can also then make sure that the quests are cheap, that therefore it requires items that are not expensive. They shouldn't give you items that are expensive as reward. So something like this are things that games like World of Warcraft is really good at.
They take it much further in that they even hire user controls and features when you first start a game, because you're a newbie, you're not quite ready for all the things you can do in the game yet until you're much further into the game and you're ready to do the more advanced things. So at that point, they unlock more advanced features and user controls.
And first, well, we have the first price, the baseline items based on scarcity and other things. And then we're gonna calculate the price for items that are derived from both those baseline items. And then we're gonna use that information to enrich our model to price our quests.
And then we can do all the other things around identifying quests whereby the difficulty is spiking in the middle of a quest line and other mistakes so that we can correct them. And a big part of doing quests would involve catching monsters. And there are many other monsters that you don't have to catch as part of a quest line.
You can just go and do it in your own time. But to do that, you still need to have the right combination of bait and trap. And we know that some monsters drops loot, which can then be used as ingredient for making a bait for the next monster. So here we have a relationship such that a monster will drop a loot,
which is used in the recipe to craft another item, which is then used to attract another monster in the chain. So taking into account this information, we can now actually establish a hierarchy amongst a set of monsters using a very simple cipher query like this. And notice that we are specifying zero cardinality.
So this is the key for the cases where the loot itself is used directly as the bait for the next monster in the chain. And if we use Bigfoot as the monster too in our query here, this is what we're gonna get back. You can see Bigfoot on the right of the screen here.
And in order to catch him, you need to make a bait using the alluring goat. And to get ingredients for alluring goat, you have to first catch at least the yeti to get a yeti fur, but you also need to catch other monsters in order to catch the other ingredients as well.
So from this graph, it actually places Bigfoot at the top of this particular hierarchy of monsters. And you can do the same process to integrate through all your monsters in the game and substitute monsters in subgraphs with its own hierarchy and build up an overarching hierarchy of all your monsters in the game. And now you can use it in conjunction
with your quest hierarchy. So suppose you have a quest number one. When you finish it, you're gonna get quest number two. And when you have monster number two, when you catch him, you can use the bait, sorry, the loot to make the bait for monster number one. We can make sure we can detect cases whereby we're asking the player to catch monster one in quest one
and catch monster number two in the quest number two and flag that as a mistake because what you're essentially doing is that for quest number one, the player has to go and catch monster number two first in order to get the loot to make the bait for monster number one. And straight afterwards or soon after, you're gonna tell the player to, hey, guess what?
Now go and go back and catch monster number two again, which breaks the sense of progression and continuity for the player. But also you can end run into annoying cases whereby, okay, as a player, I spend all my bait, all my resources to make the bait for monster two so that I can get the loot drop to make bait for monster number one
and catch monster number one. And now you're asking me to go back and catch monster number two again, and I've used all my resources. Hey, screw you guys, I'm going home. And when you have a successful catch, we also give you some, you get the loot as well as some gold as reward.
So from here, from high level, we actually have an equation that needs to be balanced whereby on the left-hand side, you've got the input, which is the price of the bait, taking into account the effectiveness of each bait. And on the right-hand side, we're gonna give you some gold as reward for every catch, as well as you're gonna get a chance to get the loot drop,
so the loot itself has a price, and factoring into account the drop rate of that particular loot. And then we're gonna take the, and then we're gonna multiply that by the success rate of you being able to catch that particular monster, using average of all your, all the different available traps. So from this equation,
we can actually say that the gold reward we give you is derived from the price of the loot and the bait. And since we know that the loot is then used in the calculation for the bait for the next monster in the chain, now we can tie the whole entire monster hierarchy
together so that whenever you change one of its parts, we can flag up all the places that you need to change, because again, this is knock-on effect that's hidden within your monster hierarchy that will need to be identified. What's more, our model actually looks at the ecosystem of all the monsters as a whole, because when you introduce a new monster into a region,
you're essentially introducing a new competitor for food so that it impacts your likelihood of being able to attract any of the monsters that exist in this region. So now we've seen some use cases of how we can use our graph data, and let's see how the pipeline that we have in place
that gets our data into Neo4j in the first place. So for Hebit Monsters, we actually built a custom CMS internally known as TNT, where every item, quest, NPC, location, as well as any other game design related data are stored. And with TNT, we want to solve a number of problems
with our previous approaches. First and foremost, we want to have proper version control for our game design data, which given the scale and scope of the game, is very important because it's very difficult for us to track down any subtle game design bugs once the game has gone live.
And in order to achieve the level of agility we want, and still have confidence in the data that we are releasing constantly and regularly, we need to have clear visibility into data changes that's happening between releases, as well as accountability for those game designers that are making those changes in the first place. And in order to maximize the productivity
of our game designers, we also needed to allow multiple game designers to work on the data simultaneously without stepping on each other's toes. This may sound obvious, but you'd be surprised that some of the stories I've heard, there's a company, there's a game, again, and I'm an RPG game who has been running for a long time where the entire game design data
is captured in one giant XML file. And even though they've got a team of, I don't know how many game designers, only one person is allowed to make the change at a time. And firstly, people keep making mistakes when they're editing XML by hand. Secondly, they've got a physical token that someone has to go and grab and put on their desk
to say that, hey, I'm editing data right now, you guys, back off, don't touch the data. And again, that's just crazy. And this problem of having to be able to allow multiple people to edit data at the same time and still have version control and safety, it's the sole problem, we all know that. With developers, that's the problem that Git solves,
which is why we have built TNT on top of Git as a very thin layer on top of Git that supports Git flow branching strategy, which is something that all of our developers are using already. So it was easy for us to teach our game designers to follow the same approach. And before every release that involves data, the game designers actually sit down
with the developers over the front end and the back end to basically get a Git diff to look at all the changes that have changed, all the JSON files that have changed, and we talk through what changes are in order to catch last minute bugs that we find, because say a game designer misunderstood how a particular feature works,
or if someone has left some half done changes in there by mistake. And TNT actually works in tandem with another service we call the publisher that's responsible for doing validation, localization, as well as generating data in the different formats
as required and consumed by our different platforms, as well as exporting data into Neo4j, by the way. With the publisher, we're able to publish and load data that's generated from specific data branches that you're working on, and you're able to test them in isolation using our shared dev environment.
So as example, if you are a game designer and you're working on Questline that's going out in three months time, we want you to be able to publish and load your data and test your data in dev without affecting other people that are using dev to test the changes that's going out tomorrow or next week. And we also use this same capability
to allow us to release data changes into production to run smoke tests on without taking the game down and without impacting other players that are playing the game live at a time. And with localization, the traditional approach is for the client to actually ingest a get text translation file,
and wherever it needs to display some text on screen, you would then look for the translated text string and display that instead. But with Human Monsters, we have more text than the first three Harry Potter books combined, spread over hundreds of classes within our domain, so we decided to implement localization on a server so that we don't have to duplicate that effort
across the different client platforms. And with the publishing process, the server will first ingest a get text translation file, and then you use PostSharp, which is a framework for doing aspect-oriented programming on the .NET to intercept setter methods on any string properties on our DTO classes
so that when the string is matched, we actually replace the setter invocation with the translated string instead, as if we have called a setter with the localized string. And so at the end of this process, you actually end up with a whole set of localized DTOs that can then be serialized and consumed by the client
without the client having to make any changes at all. You just then repeat the same process. You have multiple translation targets, and for this, we actually wrote a very small localized attribute that's about 30 lines of code or so that applies to any string properties so that when you call a setter on it,
we will, the code in this attribute will run. You will check against a static context option to see, okay, are we doing publishing, so do we need to localize at this point? If not, then don't localize. Otherwise, we're gonna swap out the value that you're calling the setter with with the localized string
and proceed with the setter method invocation, and then after this, we just have one line of code to apply this attribute to all of our DTO classes that matches our naming convention. This couple of lines of code here just covers, well, covers about 95% of all of our localization work, and it was done inside an hour. What's even better, now it means
whenever we have a new type that needs to be localized, that has to happen automatically by convention. We don't have to do any more work. Another interesting challenge that we came up with was, well, how do we automate the process of tuning the trap and monster stats so that based on the stats,
we can achieve this desired catch rate between this trap and a monster, and our formula actually takes into account other factors as well. For example, some traps, they are strong against flying monsters, but they are weak against water monsters, and then you also have seasonal monsters such as Santa's gnomes,
which are only available during Christmas, and you can only catch them using a special trap, even though the monster itself is relatively weak. Stats-wise. It used to be that in order to hit the catch rate we want, the game designers have to do a trial and error, three different numbers and stats, and see until you get to the point where you've got some number that's close enough,
and it's good enough, and this approach is, of course, very laborious. It's error-prone, and unless you've got an amazing game designer, you're not gonna get anywhere near the optimal result. And most importantly, it's just not the best way you want your people
to spend their time doing all this manual trial and error. So for that, we ended up writing a set of genetic algorithms in F-Sharp to help us do this, and we exposed those functionalities via a web tool so that the game designers can go, choose a trap, choose the set of monsters they want, and what target catch rate they want for each monster,
as well as the error margin that they're willing to accept as potential results, and they just hit a button and wait for the answer to come back. And in simple terms, a genetic algorithm will start with a set of potential solutions, and then you will iteratively generate new solutions
using a selection and a mutation process, whereby the selection process would choose survivors based on some fitness function, and then the mutation would then generate a new set of solutions for each survivor, and you continue this iteration until you either found some answer you're happy with or you've exhausted the maximum number
of iterations you are allowed to run. In our specific case, we will start with a set of stats the game designer give us to tell us basically, okay, this is the ideal distribution of stats we want. So you have a pixie, for example. You want the stats for the pixie so that she's fast.
Maybe not very strong. And any answer that we generate with the genetic algorithms will be prioritized if the stats that's generated closely matches what the game designer specified in terms of the shape. And then we run the mutation the first time to give us some solutions,
and then the selection process will kick in and calculate the catch rate for each of the monsters using this set of solutions, and then you keep the solution if it's better than the solution that it was mutated from. And the mutation process then kicks in again for each of the survivors and generate a new set of solutions by tweaking the numbers in a number of different ways.
So when we are, okay, you add or subtract a small amount from each of the stats so that when you're close to the optimal solution, you hopefully get a slightly better answer. And you also add and subtract a large amount from each of the stats so that whilst you're very far away from the optimal solution, you hopefully get an answer that is noticeably different
so that we can detect it within our algorithm. And we continue to do this until either the maximum number of generations has been exhausted or none of the solutions survives the finished test so that we just know, okay, based on your criteria,
we're not able to find an answer for you. And we apply the same technique for auto-tuning our baits, which is slightly more involved because the attraction between a monster and a bait is location-sensitive. So in order to run our finished test, and it changes depending on the number of other monsters
that exist in that particular location. So for our finished test, we actually have to run full-on simulations of using each of the solutions at every location in the world and then have a way to average that out. It's much more CPU-intensive, but still the same principles apply.
And we have very similar tool for the game designers to use as well. And if you wanna find out more about graph databases and Neo4j, there's a very good ebook that you can download for free from O'Reilly at graphdatabases.com. And if you wanna read more about the stuff that we have covered today, I've got a very long post that you can go and read
that covers each of the points in detail. And with that, thank you very much for listening and don't forget to vote on your way back. Well, out I guess. Cool, thank you.