 This is so awesome, I'm giving so awesome, I'm giving QM, QM, QM, I grew up in Jersey, I grew up in high school, so we went to high school, so we like come here and like steps and like push the buttons and like as much as the buttons, so my name is Katie Solerio, so my name is Katie Solerio, I am a software engineer at L.A., software engineer at New York, and I'm a recur center alum from Interteam, all of Interteam, I see NERC, people in here in the arts, hey, hey, hey, yeah, so I'm talking about, so I'm only talking about, I'm only talking about in-text adventure framework. This is my handle, this is my here on my tech blog, which I put on Tumblr, because on Tumblr I was very young, I was very young by my time, and so what do I mean by modeling, what do I mean by modeling framework? I honestly, I really enjoyed talking about it, I still have to try to make it so hard to take a link, that would actually kind of describe this song and I clearly failed, but basically what I want to talk about is the problem that I recently, representing the state of the game, of in-va-jame, of in-va-texture game, of in-va-project risk, that I've been working on for a family, or in-va-jame, mainly for writing text adventure games. So first, we're going to start off, we're going to end the link into one text building out to what it is, why I'm writing on, and get a list of requirements in a framework or state, and then I'll design up patterns, or line patterns, or ending patterns depending on how you like things, and show you how to work with the one I ended up going with. And I'll take about 30 minutes, I'm going to sit down, and do some stuff, do some stuff, my work, we like it as well. First time in live coding, first time in live coding in front of people. Text adventure is a game with text only input, and text only on, there's a bunch of classic ones, and I wanted to write a text adventure game, because A, I grew up playing classic adventure, and B, because games are cool, and I wanted to make a game without having to worry about problems. So I started writing a Harry Potter game in text adventure, game in Python, and we're going to use that as an example to illustrate how text adventures work. This is a screenshot of a Harry Potter text adventure, from the summer of 2013, and so when you play text adventure, there are some things that you should note. First of all, the game has a state in the game, so at this point in the game, there is a room, the room has a name, the room contains a cat to cat your life, there's a player, the player is in the office, there's a cat in it, and every time I'm saying is or has or contains, that's a state, and those states can change, the player might not always be in the room, the cat might not always be alive, but there are rules about how the states change. So if you try and take the cat, which would change the cat's state from being in the room to being in your possession or inventory, the game doesn't let you do that. If instead you try and take the invisibility cloak, you can't, which changes your state, the room state, the cloak state, however you want to think about that. If you've ever played a twine game or another choose-your-own-adventure game, in the 90s when I was growing up, there were choose-your-own-adventure books. You might already be familiar with this kind of setup. The difference between a choose-your-own-adventure and a text adventure is just that in a choose-your-own-adventure, you're presented with a set list of choices of what you can do, and in a text adventure as a player, you can just type whatever you want, and I don't want to sound like I'm not going to choose-your-own-adventure games. I'm currently reading a book about choose-your-own-adventures where twine authors play games that other twine authors have written and talk about it, and there's a huge variety of gameplay styles that you can get in a choose-your-own-adventure. The free-input thing is important because it puts constraints on how you can model state. To condense everything that I just said on the last slide into a diagram of what the program is doing, when a player uses or types an input, the game has to figure out what they're talking about, which means parsing that input into an instruction for the game. Once it thinks it knows what the player wants, then it has to try and do that thing. So in this case, you type catch this Pidgey. This Pokemon-themed game knows that you mean catch Pidgey, and it has to decide, is there a Pidgey near you? I don't know nothing about Pokemon. Is this Pidgey low-level enough that you can catch it? I don't know. This is all coming from me watching other people play Pokemon Go. Presumably, there are rules about whether or not you can catch Pidgey, and the game itself has some state. The Pidgey is either floating in mid-air above this table or in your possession. Between the game logic has to figure out whether or not you can do the thing, and then finally it delivers some output. You caught the Pidgey, great. One thing to notice about all of this is that the parser, the logic code, and the game state are all specific to this particular text-eventure game. This parser knows words like Pidgey, which you wouldn't have in a Harry Potter text-eventure, and the game logic presumably has rules for to catch that might be different in a different game. The difference between a game and a framework is that a framework, like Django or Flask or whatever other framework you want to use as an example, is just a set of tools for creating many text-eventure games. Creating a set of tools that make it easier to do a programming task is something that programmers have been doing for decades. In and of itself, it's a great idea to have a framework for making games. In fact, the world already has at least one framework for writing text-eventure games. Right now, the industry standard is, as far as I know, Inform7, which is the latest in a series of Inform frameworks. They all compile down to C, and Inform7 is unique in that it has this natural language-like syntax. I'm solving a solved problem. If I want to write arbitrary text-eventure games, I could just go use Inform. But I want to write my own framework, first of all, because it teaches me things, and second of all, because I don't think in Inform7 style naturally. This is some actual Inform7 code that I grabbed from the docs. It says, the wood-slided crate is in the gazebo. The crate is a container. To me, this reads like an English description of a scene that you might read in a book or something, which is great, but that's not how I think about building things when I program. When I program, I want to make an object, and I want to relate that object to other objects, and I want to give that object attributes, and I want to call functions to do all of that. And so, yeah, I could totally learn to think in Inform7 style, but that's less fun than reinventing the wheel in Python, so let's not do that. Let's write our own framework. All right, great, so we're going to write a text-eventure framework. How is that different from writing a game? And the short answer is not. From a player's perspective, it shouldn't matter whether you're playing a game built from a framework or a standalone. It should all work the same way. That means we have to do all the same things with the player input, and the difference is that the game maker has to be able to initialize the parser and the rule system, however you build that, and the state system, however you build that with metadata custom to their game. So a Harry Potter game will have spells that another game won't have. The parser will have game-specific words. Like, don't panic might be something that means something to a hitchhiker's guide game. And most importantly for this talk, the in-game objects have to be programmable with arbitrary abilities and behaviors. So in my Harry Potter game, I had password-protected rooms. In a Doctor Who text-eventure, you might have rooms that are bigger on the inside. We could keep coming up with examples all day. So implicitly on that last slide, I kind of assumed that we're going to model the game state as a set of game objects, talking about rooms, for example, like a wand in a Harry Potter game, a cat, a cabinet, a pidgey. And that's not how choose-your-own-adventure games work. So fundamentally, choose-your-own-adventures don't need to know or care about individual objects in a game. So at each point in choose-your-own-adventure, you're in a global game state. And to progress the game, you're presented with some links. You click on a link and you move to another global game state. And the game system doesn't need to know about objects. It just needs to know, I'm in this state, so therefore I deliver these links. And basically what that means is that to choose your own adventure, the game is a directed graph. And each state is a node, and each link is an edge. And all it needs to care about is which edges lead out of which node. And so fine, that's how choose-your-own-adventure games work. Maybe we can do this with text adventures. And so this is like straw man graph out of the scene that I showed from my text adventure. When you start off in state one where the cat is in the office, the cloak is in the cabinet, the player is in the office, and I know that I can transition from state one to state two where the cloak goes into the player's inventory. So I put an edge there. But state three where the cat is in the player's inventory is not allowed. No edge. Great. And if that was the entire game, that's fine. But this is where the ability for free input in a text adventure is important. So in a choose-your-own-adventure, the player's just delivered a set of valid edges to choose from. But in a text adventure, when you input your own command, which can be whatever the heck you want, you're essentially asking to progress to a new state. And you're asking the game, can I move to this state? And that's not super difficult in this scenario where there's only three states and one edge. But my actual text adventure game has 50 rooms and 100 objects, and I'm not even done with it. So in reality, this picture would look like this. The point where I try and pick up the cat, the state is really players in Filch's office. Filch's office contains the cat and the cabinet. The cabinet contains the cloak, the player is holding their wand, the player's house is Gryffindor, Neville Longbottom is outside the room of requirement, et cetera, et cetera, et cetera, et cetera, for like all of the 50 rooms and 100 objects in the game. And then there's a ton of edges probably leading out of the state. And generating the complete graph of states and edges in between them would be a total nightmare for a game maker. Like even in a moderately sized text adventure, this is totally impossible. So let's not do that. Let's model state as a set of game objects. So the key takeaway here is that in a text adventure framework, you probably want to be modeling your state as discrete objects, and they need to be programmable with arbitrary behaviors and attributes. Great. So now I'm going to go into a bunch of patterns that I tried out. And this is intentionally a straw man. This is what I did in my text adventure game. I divided all of my game objects up into three giant classes. I said an object in the game is either a room or it's a player, which could be an NPC, or it's a thing because object is actually a meaningful word in Python, so I can't use that. And so of these types, rooms have descriptions. They have inventories. They might have a password. They connect to other rooms. Let's not even talk about things. Players have locations, inventories, et cetera, et cetera. And the problem is that even in the unfinished game, there's huge variation of behavior among these three-core types. So things, for example, the cat isn't really a player because it doesn't have dialogue. It's definitely not a room. So okay, what's left? Thing. All right. The cat is alive, which makes it different from all of the other things I have in the game so far, like a wand and a broom. And now there's this cabinet, which can contain other things, so it has an inventory. The cat can't do that. The wand can't do that. Thing is just like a mess in terms of like polymorphic behavior that you're trying to store in this one class. And then, of course, the class itself is huge because you have to put the code for each behavior in that class. And to cap it all off, they're huge. It's not dry because all three classes actually need inventory code because some things have inventories and all rooms and players do. So let's talk metrics. If you go into my adventure, my text-adventure game repo and you sort all the modules in it by lines of code and number of commits, which are basically proxies for complexity and effort, respectively, you'll notice that the module with the room class is super complex and also a huge time sink. By far, most of my commits are modifying rooms and it has way more lines of code than anything else. The final names are positioned roughly to scale. So like, yeah, these are all, rooms is just like bad in terms of both. So the rooms class was unstable as well as complex, which basically means that maintaining and extending the scheme is impossible. All right, so there's no inheritance tree in here, which is something, I guess, maybe, but that's like a super dubious pro considering the scale of the cons, which is that this is unmaintainable. You cannot work with this. And to cap it all off, it's not even fully abstracting the stuff that you can do with game objects, right? Because the options that you're limited to are the ones that me, as the frame maker, have encoded in this giant monolith class that I can't maintain, so when you submit a bug report, this is just terrifying and horrible and awful and nope. All right, so I can't extend what I did for the text adventure game, but maybe I can encapsulate individual behaviors in classes and then have my game objects inherit from whichever classes they need to have the correct set of behaviors and attributes. And on the surface, this may sound like another straw man, but I actually dug around in some inform docs, and it seems like this is how inform works under the hood. This is not, this is like actually used in production. All right, so let's start from an extremely naive place and take that scene from my Harry Potter game and try and construct an inheritance tree of behaviors that will work for it. So here I've represented inheritance as upward-facing arrows, so live entity inherits from locatable entity, which inherits from entity, and instantiation is downward-facing arrows, so a cat is an instance of a live entity. And so this is already better than the monolith horror world because each of these classes is small. Each of these classes just has one thing that it does, and they're super-maintainable. And also, you can make arbitrary behaviors by just writing a new class with that behavior code in it. Great. However, inheritance trees are hard. So say you want to make a sorting hat. Well, it's definitely not alive because it's a hat, so it shouldn't inherit from live entity. And it also makes a point of telling people that all of the houses are equally valid, so it shouldn't inherit from character entity, which like has household loyalties. It can contain things, so maybe it's a container, but also it has dialogue, which is currently now on character entity, which I just said the sorting hat could never be. Great, it just doesn't go. Furthermore, I split this inheritance tree at live and not alive, but some live entities can contain things and some not alive entities can contain things. So the code for can carry things and can contain things is probably extremely similar, if not identical, but because of where I split the tree, you're duplicating that code. All right, so you're probably all shouting at me why I forget the tree. There's a way around this problem, and the way around this problem is to flatten out the tree, so that each of the behavior-encapsulating classes is standalone and does not inherit from each other. You're basically turning this into a set of mix-ins. And so this keeps the benefits of each class being small. You can easily make a sorting hat by just making a class that inherits from the classes that contain the things that are relevant to the sorting hat. Yeah, and all of the behavior code only appears once. Let's try. I'm actually not utterly disgusted by this. This is how you can do inheritance and not how to be a straw man. And it seems like this is how Inform does things. So in the docs that I was reading, the example that they had was a chocolate bar, and their chocolate bar class inherited from classes called food and small and inflammable, and all of those sound like they're tiny classes that are just describing one small behavior, each mix-ins. However, right now we're proposing a system where each game object inherits from at least a few, if not many parents, and we're all Pythonistas. We all know multiple inheritance is hard. In this blog post, Ned Batchelder is talking about some gotchas that he noticed when he was trying to use mix-ins with his unit tests. And he was having trouble because anytime you have multiple parents, then you have to specify an order in which to search for methods that you inherit from the parents. This was a thing that I learned when I was preparing the stock. In classes, in Python, classes have a class attribute called DunderMRO that will just tell you what it thinks the MRO is for that class. So that's cool. Every programming language has a set of rules for determining the MRO for a class. So Python does left to right depth first. So in this case, you would look at the leftmost parent of the class and then that parent's leftmost parent, et cetera, et cetera, et cetera, until you hit object and then you go back. And so for this, the MRO of descendant of A and B looks like that. First you go to the class itself, right, because the method might be there, and then A and then parent of A and then B and then parent of B and then object, finally. Great. So if you call expelliarmus on instance of descendant, assuming that expelliarmus is not actually defined on descendant, then the copy from A will be used. And that's the problem that Ned Batchelder ran into with his unit test mixins. He was expecting to inherit from unit test case first and then his mixin, but he really wanted his mixin to override his behavior, so it had to go first so that it was the first parent when Python was looking for the method that he was calling. Great. So we don't care about that, right, because we're not... We're using this dry pattern where every behavior only appears once. So in theory, that was a... Why are we talking about this? Expelliarmus is only going to appear once. You don't have to worry about one copy overriding another. Sure, but presumably you want to use an init, right? So when you create instance of descendant, which init gets used? And the short answer is that the init on B and parent of B are completely unreachable, because if you don't specify an init on descendant, if you say you put a call to super in the init to descendant, super calls the parent's copy of that same method, but super follows the MRO, so super will go to A. A super call in A will go to parent of A. There's no way to actually call Bs in it or parent of B, so in this case, you can never initialize an instance of descendant with X sub B or X sub parent of B specified. So if you're creating a custom class that inherits from a bunch of small classes, you can't necessarily guarantee the order in which the game maker is going to put those classes. Or as a game maker, you can't guarantee that you'll put those classes in the same order every time. Maybe you're using a different combination of the mix-ins, et cetera. So you can't guarantee that the in its on any of these sub classes can be reached, which is probably okay. Put all your initialization in your speaking object class. That's fine. On all inheritance can be okay. It's dry. You can create arbitrary behaviors. That's great. That's already like worlds better than the monoliths. I don't really want my game makers to have to think about MRO, though. I want them to just think about their game and not have to worry about how Python is working under the hood. So I'm like meh on this. It's okay. If I have to use it, I'll use it. But fortunately, the game community has already thought about modeling state as arbitrary sets of behaviors, because this is a problem that game makers in 2D games or graphics games have to deal with all the time. So some other people who are smarter than me have invented a design pattern to resolve it called entity component system, and it's great. So an entity component system, or ECS, entities represent whole things, so say a cat, and then components store groups of attributes that represent the traits of a cat. So you might have an alive component on your cat, you might have a color component on your cat, a mood component, et cetera, et cetera. One of the tenets of ECS is that entities should never store any information about themselves. They're just a UUID that you tack these components onto, and the components hold all of the state. An analogy that I like is that entities are nouns and components are adjectives. So the S of ECS is for a system, and systems provide a service interface so you can make changes to entities with a specified component profile. And systems are where you put behaviors. So I've been using a system per component class, and then I use that system whenever I want to make changes to a particular component type. So for example, I have a container component and a container system, and the container component is like just an inventory attribute, and then the container system stores the code for moving things in and out of that container. And that's super important if you want to make a performant ECS system because attributes belong to components and not entities. If you want to find an attribute for that entity, you have to load that component into memory and then get the attribute off that. So systems will let you cache attributes, so you don't have to do that all the time. Second of all, if you're putting methods on the components, it's the same problem where if you want to call that method, then you have to actually access that method, which involves finding the right component on the entity, which is not great. Not that that super matters in a text game, but still, this is the right way to do things. Great. So the problem with ECS is that it doesn't look very pythonic. So the behavior that I would expect from a Python object is that all of its attributes is accessible from the object itself, and that's strictly not possible with ECS, where the main tenet is you don't put the attributes on the entity. So this is how if you are using a standard Python ECS framework, you would figure out if the cat is alive. And that's hella clunky and a huge pain in the ass. And I installed an ECS package when I was first considering this design pattern. I just installed an ECS package and tried to play with it and got super frustrated super quickly. All right. On the whole, I think this is better than inheritance, and that's just personal opinion. But the thing that edges it out over inheritance for me is that it has the same benefits, right? Like it actually supports full abstraction. It's actually dry. But the cons are things that I can fix rather than things that the game makers have to worry about. So, like, yeah, it looks clunky in Python, but I can write my own ECS package that makes it prettier in Python. And, like, yeah, perhaps performance can be a problem, but it's a text, A, it's a text game, and, like, B, I can design my ECS framework so that it goes smoother. And I did, in fact, write my own ECS package. So, just as a quick shameless plug, the first box is that code that I showed on a fire slide that made me angry. In my ECS package, which we're going to play with in, like, two minutes, it actually fakes the attribute being on the entity. In an extremely non-performant way, but, hey, if you want to figure out if the cat is alive, you just do cat.alive and get true or false. Great. Furthermore, the other ECS packages in Python that I've used have been super bare bones, which means you have to instantiate, like, however many components you want to put on your entity, and then individually attach them to the entity, which is also hella annoying. So I wrote a factory maker. So you can just do a cat. You can say a cat is a collection of a name component, a description component, a container component, et cetera, et cetera, and then make a bunch of rooms or cats or whatever. Rooms, great. Cool. So I'm going to leave this up for a sec and get myself set up. Here are some resources for entity component system if you're interested. So the first two links are just articles about the pattern. The third link is my ECS system, and, like, yeah, yeah, yeah, I'm shameless. But it's mostly up there because I wrote a really long readme that's basically an article about ECS. And then the last link is an ECS package that my friend is writing in Ruby. And it's gorgeous code. But also, he collected a lot of articles about ECS. So, like, the first two are from his, if you want to read about this pattern, Luckier section. Actually, I'm going to leave this one up while I get myself set up. This is my framework and my ECS system. So before I, yeah, working, awesome. Great. So when I wrote the proposal for this talk, I was like, I'm going to live code. And then I read a tweet that was like, you should never live code in a talk ever. Audiences never follow it. You're just doing it to show off. So I thought about it, and I was like, why do I want to live code? And like, I feel like it was 30% to show off. Maybe more. But also because I felt like I should, you know, like I've given X many public talks already, like why haven't I live coded? This is a thing that like real talk people do. Yeah, I don't know. It was silly. And I kind of forgot about the part of it should be useful for the audience. So I am going to live code a little bit, but so I think the whole point of my talk, or what I hope is the point of my talk, is well, first of all, I wanted to kind of show that by working on your own personal project, you can fall into rabbit holes and learn fun things. Like I read an entire book about refactoring and metrics for refactoring, which is where the lines of code as a proxy for complexity thing came from. So I think that's like point one, like write code, dear thing. But point two is that I think entity component system is a really good solution for a text adventure framework. And so when I was making my slides, one thing that I was having difficulty with was like really proving that ECS is easier than inheritance. Like I can say that and I can like throw up slides with code on them and talk over it, but that's not really showing it. So what I'm going to do as my live coding is just play around with my ECS framework and make some things, and hopefully that will illustrate that this is easy to work with. And it can be fun to work with. Yeah, so that's my goal. Hopefully I'll like mess around for 10 minutes and then we'll have 10 minutes for questions. All right, this is not working for me. Command what? Yes, yes, yes, yes. Give me a sec. First of all, I have to make it so that I can see what I'm typing. So my entity component system package is called Braga, which is kind of terrible, but Braga is both a maker guide and a character in a comic book that I read. So I am personally fond of this name. Not descriptive if you don't read comics. Okay, so the first concept in Braga that's important is a world because you need all of your entities to know about each other. You need all of your systems to know about the entities in your world. So let's make a world. And world. Right now there are no entities in this world. And there are no systems in this world. But I can make an entity. Great. Yeah, so remember how I said entities are just a UUID. Here's a UUID. And there are no components on this entity, so it's super exciting. Now the world knows about it. Great. Okay. So to make it actually able to do anything, you've got to write a component. And the way components work are their classes. Like kind of what you would expect in an inheritance-based system, you write a class for your behavior. So this is my standard example. And I'm not quite sure why. I think because I can put method. Yeah. Nope. Ignore me. So I'm just going to make it a live component. All right. So I can do something like this. And then I'll have this property that's just sitting in space. But why would I ever do that? I want to have an entity that can have this property. So let's make an entity. I'm going to stick an alive component on this entity. Oops. Is that how that works? That's not how that works. Great. Yay. Live coding. Aren't you getting so much out of this? Yeah, probably, actually. So this is, I don't even know why I'm doing this example because this is the pattern that I don't like, right? This is the pattern of making components and then nope. Oh, right. Because I got rid of the add component method on entity because I never used it ever. All right. New strategy. Let's make a factory. So this is a thing that is not in other Python ECS frameworks. I give it a list of components that I want the cat to have. And now I can do cat factory.make. And if I do cat.alive, it has an alive component. Yay. This is cool, but let's look at my world. Yeah. So I made a bunch of entities from my world and the world knows all about them. But the world does not know about my cat because I just made the cat straight from the factory. So remember I just made a component class. Say I want to, you're not going to work, are you? Say I want to be able to initialize an alive component with some values. This is kind of gross, I will admit. Basically what I'm doing now is telling, oh, I see, there's an extra space. Yay. Now I'm telling my cat factory, no, stop, let's do this again. I'm telling my cat factory to recognize alive as a keyword argument that you can pass in. So now I can do something like dead cat. And now dead cat.alive is false. That's pretty cool. And now, actually let's assign, okay, so world cat, give it the cat factory and alive equals false. Great. So world cat is an entity with UID starting in 19E. World.entities has a cat starting with 19E. And world cat is not alive. Great. Okay, so that's generally how you would make some entities and assign them all to a game. And that's fine. But here's the cool part. Cool. So I actually used... How am I doing on time? I got like 15 minutes? 15 minutes. Oh, awesome. Yes, because we're ending at 12.10. Great. Okay, so I'm going to wrap it up shortly so I can actually take some questions. But let's just start this from the beginning. I made a text adventure. And it's super tiny. So there's a room. I can... You are currently dueling Justin Finch-Fletchly, which I haven't bothered like writing words to describe, but if you... You can cast Expelliarmus at him and you have some chance of success, which is, hey! Apparently large enough that I can hit it without upping my Expelliarmus skill. Great, so now if I do inventory, I am holding some poorly formatted wands. That's a sentence I was not expecting to utter today. Right. So all of that code is here, and this is tiny again, yeah? Some components. I'm not talking into the mic. Here are some components. They're pretty standard. They're all just like setting some things... Setting some attributes. And then here are some systems. And this is the actually interesting thing. This is like where all the logic for the game lives. So it turns out that like game people are super into having methods called update, which is not a pattern I was hugely familiar with. Then I started reading all this ECS stuff and they're like, update this, update that. I was like, okay. I think I'm going to ditch this pattern because I don't... I'm not... I know I'm not really using it. All of this code here, which is just adjusting the cache, so self.inventories is an attribute on systems that's storing the inventories of the game objects so that it doesn't have to like get them from the component every time. And like all the update it's really doing is just like sanitizing the cache and the attributes in the entity, which is something I just do in move. So basically, this is all of my move code here and this is all of my like equipping code here to like actually make the dual game. Should I show this? It's terrible. Whatever. To make the dual game, I have 74 lines of code, which is not a lot at all and all it really is is just making calls to Braga to make the entities and initialize them with the attributes that you want them to have and then making some systems and then having a while true loop which I really shouldn't be doing, but yeah, like there's not a lot of code and it is a game that does some stuff. Great. So I think I have like five minutes for questions. And for certain key words? Yeah. I'm doing... I have a system that like manages aliases for words. Yeah. But it's like it's very silly. Like the first word that you input, it takes us like a minute. I have not since I switched... I've not run into performance issues since I switched to ECS. I had some hilarious bugs when I was working on the game but that was because I didn't really know what I was doing. Container is a good one. Container is, I would say, cleaner than equipment. Certainly cleaner than name. So, yeah. So like I said before, I don't want to have to fetch the inventories from the entities. So I put a dictionary on the container system where the keys are the entity UUIDs. And I think, yes, yes. Sure. The keys of the entity UUIDs and the value is a set of items that are in that container. This is because I haven't quite figured out how to work update yet. Ignore that. Oh, aspects. Right. Okay. So the system is this attribute which is a cache for all the inventories. When you start up the system, it finds all of the movable objects and adds them to the inventories of the location that they're stored in. And then the move command does some validation. So you can't be moved unless you're movable. And if the thing that you're trying to move it into is not a container, then you can't do that. And then it just changes the attributes on the components here and updates its cache. And then calls update which pushes an attribute called inventory onto the container entity. And this aspect thing was a thing that I meant to live code and then I didn't. Aspects basically let you find entities with a particular component pattern. So right now I'm basically only using all of that as a keyword for aspect. But presumably I could say I want to operate on all of the entities that don't have a container component and then change this to none of. Yeah. So I basically initialize each system with a cache and with a set of entities that it cares about. And then the methods will change the attributes, update the cache. Yeah. Yeah. I can show you a command in my two minutes remaining. Does anyone mind if I? Cool. So I lied a bit. It's like a little more than like 75 lines code. This is the commands. The state bit is 75 lines code. So where is something that moves something? Confiscate wand. Here we go. So all of the systems that are associated with the world are in the system's dictionary. And so here when I actually succeeded at X-Baliarmus, I call move on the container system with the destination and the thing that I'm moving. Great. But he goes through stuff like this. Interactive fiction. Yeah. Oh, cool. Yeah, sure. I have a feeling that my game will never be done. Because like, it's like I picked Harry Potter because there's like so much stuff you can do, right? Like I think next to my agenda is potions. Nice. Cool.