 Ah, let's talk about how we can achieve persistency with players' data. Sometimes we have to save this players' data somewhere, or we have to make this data persistent. So let's say we have HP, so health, and score. And the main question with that is that we have to make the player aware that their actions are actually meaningful in the future. So if they do something in one level, it will go through the next level and they will be aware that, okay, if I do something here, I can be rewarded and I can build up this score and I must be careful with my actions because maybe I can be punished and my health won't be as high as it was. I won't be with the maximum health in the next level so I must be careful with what I'm doing. In Godot Engine, this is kind of tricky because the big deal with Godot Engine is that if we have scenes, like let's say we have three levels, right? So we want the player to pass through these three levels and maybe we are going to use the get scene. Let me write this down here. The thing is that we can use this getTree.ChangeScene method and we also have this changeScene2 method. So this method that you can see here. So we can use that method, this method, to make the scene change to the next scene that you want. So you can pass a path to a packet scene in your file manager or with the getScene2 method, so this other one here, you can pass a packet scene file, packet scene. With these two approaches, what we can do, what the Godot Engine will do is that it will clean up the whole scene tree just saving, actually it only frees the first node of the scene tree and then it will take it out of the scene tree and load this new one that we are passing. So if we pass a packet scene, it will load this one and insert it as the root node of the new scene. And if we pass a packet scene path, it will load the packet scene and et cetera. But then with that, what will happen is that everything that was in this scene tree that we are testing or that the player is playing is that will be lost because it was freeze from memory. So the main problem that I'm addressing here is that we will lose player's data if we change the scene or if the player quit the game as well. So the idea is that we want to make this data persistent even between play sessions. Before we get started, first I want to say that this video is being sponsored by my patrons, one of them being God of Grantees that is on the chat now. So thank you so much for your support. And also I'd like you to follow me on each IO. So go there, follow me, the link will be available in the description after I finish this live stream. But that said, let's go to God of Engine. So yeah, that's, so I am very prepared. Let me open the GitHub desktop here because we are going to use GitHub features so we can pass through all these approaches quickly. Let me switch to this repository. So the first approach that I want to show you is this player resource approach. Let's do the trick. Yeah, so let's open God of Engine again, play persistent data. So the first thing that I want to show you is an approach that I often use when I want to sync some other nodes with the player's data. So let me address this approach. So this is the player's data resource approach, okay? What this do is that we create a resource for the player. Let me open the player data here. So this is the resource. This is what will be the container for the player's data. So let me explain how resources work in God of Engine. In God of Engine resources are one time loaded object. So there is only one instance of this object available in memory. And every time we make a change in this object, in this resource, it will reflect on the other objects that are using this as a reference. So in this specific resource, this player's data resource, I have here a signal that is the updated signal that is emitted every time a property is updated. So every time we change the value of a property. And we have the max value, the health, and the score properties. Since this is a resource, I can export the resource to other nodes. So in God of Engine, God of Engine can be broken down into two types, general types. So we have the nodes and we... So in God of Engine, we have the nodes and we have the resources. These are the building blocks of God of Engine. Resources are basically data containers and nodes will use this data. So for instance, when you have a sprite node, what we have is that this node will use a extra resource. So we have these resources and we have the nodes. Nodes use resource and resources are loaded only once. So basically what we can do is that let's play the game. So this is a pretty simple game. We'll use the same game between all the approaches that I've shown. And you can see that here the score is being updated when the player pickups some coins. And the health bar is being updated as well when the player took damage. And when we switch, these properties are maintained. So we keep these properties in memory because we are using this resource. How this happens? How this is kept in memory and how we managed to not lose these resources. If we go to the level one scene, basically what this... We have the interface and we have the player. So let me also open the player scene and the interface scene. So basically both the player and the interface are users of this resource that I called players data. That is this resource that we can see. I think that you guys can't see. So I will throw it there. Okay, so both are users of this player data resource here. So what I did is that, okay, the pickup area that is the node responsible for picking up coins and stuff like this, we'll have a reference for this resource. So here we can see that it has a reference for this. The pickup area we'll use this resource is that it has a reference to this resource. So all it does is that it will take this resource and when something enters in this area, it will get the score of the scoring and add to the score of the player's data. Then we also have the heart box which also has a reference to this player's data. And what it will do is that whenever something enters in this area, in this heart box area, it will disable the collision shape and it will actually disable the collision shape and then it will decrease the player's data health. So basically what this approach does is that it uses this feature of resources that they are only loaded once until we go to duplicate the reference or something like that. And every node that uses this resource will be using the same resource. So if something happens to one of the reference, all of the reference will be in sync. So if we go to the user interface here, the user interface also uses the display's data resource and it connects the updated and the died signal to itself. And whenever the player's data is updated, it will also update the interface. So since they are all using this resource, they will be all in sync as I showed you when playing the game. So basically this is what happened in the background. When the player gets a coin, the pickup area will update the score of this player's data. And since this score is updated, the player's data will emit a signal and then the interface will get the signal and update itself as well. So this is what is happening here. And since we can pass this reference between scenes, actually since all the scenes are using this reference, so between the two levels that are both using the player's data resource, this is maintained between these levels and even between these screens. So in the game over, the end of the game screen, the score is maintained as well. So to summarize, the player's data resource is very easy to set up. You saw, it's basically a resource, a bidding resource. And we can extend this resource, let me open this script. So basically it's just a resource that is not too much complicated with that. Resources aren't even in the scene tree, they're in the memory somewhere else. So we are basically making reference to them and they are kept in memory until everyone that was supposed to use this resource is not using it anymore. So until everyone that uses this resource is not in memory anymore, this resource will be kept in memory and updated. This is why we can transition between scenes, we can use the get scene.changeSyncTo method and we won't lose their player's data because it is always in the memory until we don't have a reference to it anymore. So the advantage of this approach, it is easy to sync with the UI. We basically just have to add this reference to the UI and connect a signal and make it update whenever this resource updates its properties. Only the nodes that actually access, that actually needs this resource, that actually needs to know that this resource exists will make a reference to it. So we don't run into the problem where we have spaghetti code getting someone else to make a reference for us and then accessing this other thing and basically making a couple between these two classes. And this is an advantage for me because it makes sure that if we make a change, it will be easy to find where we should update the classes and what are the classes that should be updated. It is also very nice for multiplayer. So for instance, if we, let me change this. So for instance, if we want to have a multiplayer game with player's data being saved for both players, we basically just need to duplicate this resource and set it up on the second player's UI and area, et cetera, you just need to override the player one data that was supposed to be on the second player to the second player's data. Basically, we just need to do that. We will just have a new player resource, a player's data resource. Also, there is another advantage with this approach. So basically, if we want to save it to the player's disk for some reason, basically everything that we have to do is using the building resource savers. So we can use resource saver.save self. I think that we have to pass a path, actually. Let me see that. Yeah, we have to pass a path and then the resource. So we can basically use user slash slash player data.scene and then we'll pass self and it will save the player's data. And to load, we can use the same path and load this resource. This is not optimal for games with competitive play. Like if we have a competitive game, this won't be a nice approach because it will be on plain text. So the player will have access to this resource on the file system and they can change the data there. So this is not optimal though. But for a simple approach for saving data and stuff like this, this is a very simple way to achieve that. Now, there are some drawbacks for this approach as well. As I said, if there is no reference to this resource, so if there is, if no node is using this resource, the player's data resource, goodot will free from memory and the player will lose all the data. So let's say, for instance, the main menu doesn't have any reference to this resource. So if the player managed to go back to the main menu in the middle of the play session, so let's say here, we open the main menu, Godot will free this resource from memory and the player will lose the progress in the game. So the player will lose the score, the health, et cetera. So this is very dangerous and is actually very hard to maintain a consistency of player's progress because we will have to make sure that every possible scene that the player can open will maintain this reference in the memory. So this is a drawback of this approach. Another drawback of this approach is that every user of this data, so let's say the user interface, every user of this data, so every node that uses this player's data, will have to maintain a reference to it. So we will have to add this line of code, this line of code that I'm showing here, on every node that will actually use this resource. So it can be quite troublesome to add this over and over whenever you need. So for instance, if I open the player scene here, there are two nodes that are using this and there are two references in the same scene to the same resource, which can be something bad, a bad architecture, I don't know. But yeah, this is an approach that actually I would use for like a simple game for a game jam or something like that. Next, let's talk about, let me go to this scene. Let's change. Okay, so let me, let's explain this singleton now. So as the guys were saying in the chat, we also have the ability to use the singletones. So singletones are a design pattern that we have available in Godot Engine, we have building available in Godot Engine. And basically singletones have two advantages. They are globally accessible and they are globally accessible and they are only loaded once. So resources are also loaded only once, but they are not globally accessible. So I say that one of the drawbacks of the, so we can use this singleton approach and we can basically just use it just as if we are using, it's very similar to that resource approach that I just showed you. So if I change to the singleton approach and if we compare these both branches, so let me compare this to the player's resource, we'll see that basically we eliminate the player's data reference because as I said, singletones are globally available, so we don't need to make a reference for them in the script. That's basically all that I did. I removed all the reference to the player's data resource and instead I used the player data singleton. So you can see that all that I did actually to the playersdata.gd file was changing it from a resource to a node. So if we go to growth engine here, yes, reload, clear. This is the new player, this is the playersdata file, the playersdata script and it is exactly the same with this option that instead of extending a resource is now extending a node. And the way that you can turn a node or a scene into a singleton is by going up here into the project, project tab here, project settings. We can go to the auto load and basically we can pass a path to the file that we will auto load that will be turned into a singleton. And then we'll pass a name to this file. So in this case, I say that the new name, the name of this singleton will be playersdata. And once we do that, Godot will create, will create a global variable that we can use with this name, so with playersdata name. So there where I have the pickup area when it was a, before the singleton approach, it had a reference to this resource and now it doesn't need a reference to the playersdata resource because now it was turned into a singleton. And basically we just need to access the singleton and address it properly. So if I save this and we play the game again, everything is the same. So we have the score, we have the health bar. If I take damage here, it will update. If I pass you the new scene, it will maintain this data. And let me just show you what happens. So if, okay. So we have here the scene and if you go to the remote scene, we have what is happening when we are playing the game. So you can see that we have the root node and then the level, which is the scene that is currently. So basically what we can see here in the remote scene is that we have the level that is the current scene that we can see here. But as a sibling of this scene, we have the playersdata. This is how singletones work. So let's pay attention to this scene tree here, to this tab here, to this dock that we have here on the left. When I change to another scene, if you change this node here, you saw a change from level one to game overseeing. This is actually what clears the data if we don't have a singleton or a resource or something like that, to keep the playersdata intact. So to maintain this playersdata outside of this cleanup that happens when we change scenes. So we have this playersdata as a sibling of the root node, of the scene that we are actually playing. And since this cleanup doesn't affect the playersdata, we maintain the playersdata between the sessions. But there are two main disadvantages of this approach, of the singleton approach. First of all, if we quit the game, as imagined, we will also lose the playersdata. So we can see that now score is reset to zero and everything will be reset because singletons are nodes and when we finish up the execution of the game, all nodes are free from memory and we will use all the data that the player did. But let's talk about the advantages and disadvantages of singletons. You saw that since they're very similar to this resource approach, they have many of the advantages of the resource approach. They are very easy to synchronize with the UI. Basically, the UI and all the nodes just have to make a reference to this singleton. Actually, they don't make a reference. The reference is globally accessible. They just have to access this variable that is holding this singleton. So it's very easy to sync the users of this data. So if one user changes this data, it will affect all the other users very simply. It is a centralized solution. So if we have to make any changes, we know where it should change. We just need to go to the file that is using this singleton and change whatever we want to change there. The data is very persistent until we close the game. So differently from the resource approach, which as soon as we lose a node, so as soon as there is no one making a reference to it anymore, the resource will be freed from memory. With singletons, we don't run into this risk, which is very, very risky. So with singletons, we don't have to be concerned about that. No one has to be making a reference to this singleton. It will be just be kept in memory no matter what until we close the game. So it will be always available. So singletons in that sense are a better approach than the player's data resource. Now some drawbacks. It's very hard to identify who will actually use this singleton. Why? Because it's very tempting when we are using global verbals that we will make every class access it and when we do this access to this singleton, to this global object. If we make a change in this object, we'll have to figure out everyone that is using it, everyone that will ever use it and update the interaction. So let's say, for instance, let me go to this singleton player's data game. So let's say we change this signal name. So let's say instead of updated, we say player data updated. Now we have to figure out everyone that was using updated instead and then go to the file and update them. So you can say that this can be done quite simply using the replace, finding files. And then we can basically search for updated and replace and then we can basically update them accordingly, right? But what if you have another type of file? What if you have a building file, a building script that is making a reference to this singleton? As we can see, if we search in finding files, it doesn't search for same files, it just searched for data scripts and shader files. So you will have to update it. In this specific case, you would have to update this manually. And another disadvantage of the singleton approach is that it is global. This is very arguable because globals can be good, globals can be bad. But for the sake of this video, I think there is a consensus that making something global accessible is a bad practice because, as I said, it's tempting to use global variables, global objects everywhere. So unless you have a solid code base and you know that once you make this singleton, it won't change later in your game. This can be risky to have it global accessible. And then comes the main disadvantage of this singleton approach when compared to the player's data resource, with the player's resource approach. Singletons, as I said, they are only loaded once and you can load them twice, et cetera. The pattern is you load singletons only once and everyone will make a reference to this singleton. Since this is a feature, a built-in feature of singletons, this makes it harder to implement multiplayer support because since there will be only one singleton, how will you manage to add support for a second player? You can say that in the player's data, we can make these resources arrays instead and basically we can use the indexing of the arrays as the indexing of the players as well. So let's say this maximum health will be an array, will be an array and then the first index will be the current amount. So this is a way to implement multiplayer support, for instance, but if you don't plan this ahead, so if you decide that you want to add support for a multiplayer after you actually finish the building of this architecture, every other node now will have to be aware that there was a changing in the architecture of the player's data script and now instead of making this kind of interaction like score, just updating the score, they will have to say, okay, the score at the first position will suffer from this operation. So yeah, it will be very tricky to implement multiplayer support if you are making this with a singleton approach. So I think that this is a drawback as well. So yeah, so we have some drawbacks, we have some advantage and just to make it clear, one approach doesn't exclude the other. So you can pretty much use every approach that I will show you here together and who knows, you can do whatever you want. But you can figure out a way to use both approaches. So the singleton approach, the resource approach together and the next one that I will talk next. I'll move on to the next approach, which is the save file approach. And this branch actually in this specific range, I think that is this one. Yeah, in this specific range, what I did is using both approaches. So I will use the singleton approach and a save to file approach. So let me show you how this happens. You go down here, reload. So basically what this does is let's go to the players data script here. All that it does now is that it added two methods to the players data singleton. So it added two features to the singleton. Basically these features are, it can load a file from the user disk and it can save this file as well. With this approach, we have something that we didn't have with the resource saving approach because with resource saver, we are not able to encrypt the data. So as I say, the player will open a plain text file and they can change whatever is the content of this file. But with this approach, we can actually save this file with an encryption key. It can be whatever key, but it can also be a randomly generated key or something like this. So we can pass whatever we want. Actually, there is another approach to that which is using just encryption. Yeah, so you pass a pull byte array instead of just a single word or a pass. And then you can store this to this file and then load it again and make the proper parsing. So this is a feature that has in this approach. And if we test this now, let's test the game. This approach, we have something that we didn't have with the other two approaches. Let's see what is. So if we play the game, we can... And you already saw this. So it won't be a surprise anymore. But take a look at the health and the score. I will take some damage here and then we will quit. I will test this again, play. And as you can see, the score and the health will keep, will work kept between the play session. So now we can keep the data saved even when the player quit the game. So this is the hardest persistency that we can get. Because with the other two, the player data will be persistent when the game was playing. But with this approach, the players data will be persistent even if the player closes the game. So this is a very nice feature. But nothing comes for free, right? So we have some drawbacks with this approach as well. So let's talk about them. Okay, so as I said, one of the advantages of this approach of saving the player's data to a file that will be kept in the player's disk is that we don't run into the risk of losing player's data if there is no one making a reference to this file as we were running into this risk with the resource file. We have this data saved, we have this data kept even between sessions. So if the player closes the game with the singleton or with the resource approach, the player will lose their data. But with this save load from this approach, they won't lose their data. And another plus of this approach is that it can save and load as many players' data as we want. So if we have two, three, four, five players playing at the same time, this saving file will be able to keep all of these players' data in memory and we can load it and parse it when we need it. But one of the advantages of this approach is that we need to parse data. So let's go back to good old engine here. Okay, so this is the parsing section of this approach. We will, first we will store all the player's data as a JSON file, turning this into a dictionary. So instead of saving a resource as we did with the player's resource, player data resource, the first approach that I showed you. And now we will have to turn all of this data into a dictionary and then we'll have to parse this dictionary to a JSON file using this method and then store it in the file that we are using. And when we load this file, we will have to parse all of this dictionary, all of these JSON file properties into the properties that we want in our game. So in this case, we'll have to go to the health, to the health key in this dictionary and then set it as the health property of this object, so on and so forth. And this can cause a lot of troubles. Let me explain you why. So we are making parsing, right? So what we are doing is that we will turn one type of data into another type of data that this file format or this dictionary or JSON file in this case, we'll understand. The tricky thing with that is that Ingotot engine, we have some types of data that only exist in gotot engine. So for instance, other types of files will not understand, will not be able to save this type of data. So for instance, let me go back to gotot engine here. Let's say we have a vector two, vector two var position. So let's say we want to save the position of the player, right? Here goes the trick. JSON files and most of the files that I know doesn't have support for vector two types of data. They don't have support for this data structure that we call vector two in gotot engine because this is a bearing type of gotot engine. So if we want to save this data to a JSON file, let's add a new property here called position. What we'll have to do is to create a new type, use a type that is supported by this file type. So in this case, by JSON files and try to create an architecture in which we can rely for parsing this data later. So let's say we can create a, I don't know, an array. I think that JSON files support array. And then we will say that the first position will be the X position of the this vector. And then the second position of this array will be the Y position, Y property, the Y property of this vector two. So let's say here we'll call position.x position.y. And then at the bottom, we'll have to make the same. So position.x is equal to dictionary.x. Actually, position, position. And then the first index of this position and then the Y property of this vector two will be the second position of this array. So why this is actually a problem? So the first thing that comes into my mind when we are talking about this parsing, this type of conversion into this file because as I showed you that some types of data are not supported in JSON files, for instance, the thing is if you have a change into the engineering of your game, so let's say you change the type of a property in your game, now you'll have to have another method of another way, another type of conversion to parse this new data. So going back to Goro, let's say, instead of having a vector two, we will actually have a dictionary, for instance. No, this doesn't make sense, but let's say we have an array or something like this. Now, arrays don't have X and Y values. So we would have to update this, right? So we'll have to make something like this will be the X, this will be the X one, and then this will be the one. And now we changed how we are parsing this data between these properties, and we'll also have to update this there as well. Now, can you think how troublesome this can get? This is one of the reasons why we often add a version property in most of the saving files that we have. So one of the ways that we could work around that is having a version property in this dictionary, in this JSON file, that will say what was the version of the game that this saving file was created with? So let's say we have the game running into version 1.0, so 1.0, and then we save this file and we save in this version property of this dictionary that the version is 1.0. In our game, we would have to have two types of parsing. So we would have to make so that when we are parsing this data file, we will have to identify what is the version that we should use, so what is the difference between one version to another, and then we will have to make sure that we can parse this file in two versions. So let's say in one version, you identify that that is the 1.1 version, you can parse this property as a vector two, so you make the parsing as a vector two, and then you identify, you can make something like a match statement like this, let's say, okay, so here we could have match dictionary version. So, and when you have another type of, when you have a change in the parsing, you would have something like this to make sure that you are parsing the data correctly, and this would also have to be made when you are saving the file. So, something like here, and you have to add like a version property here, which would be something like get the game project, something like the project file, game properties.version, and you have to make sure to read this version file and et cetera, et cetera, to make sure that you don't lose compatibility of saving later on. So this is one of the disadvantages of this approach. Another disadvantage of this approach is that it is highly, as I said, it is highly dependent on the way that you architecture your game. So the way that you parse this file will be different depending on the, if you have some changes in the feature, you'll have to be very aware of how the project will scale so you can have the proper way to handle this file parsing. Another disadvantage that I see on this approach is that it is quite low level. So when you are making this approach, you'll have to be both into a mindset of gaming, of game development, programming, of game development logic, and also on computer handling file system logic because they will now be merged into the same thing. And this can be tricky to handle. This approach also is kind of corruption prone because if something happens between this parsing, so let's say if we manage to not complete the saving and the player just killed the application before we are able to save this file to the disk, the file will be corrupted and the player will lose the data. If the player do something strange in the disk that affects this file, the file will be corrupted as well. And also each object that we use this file will have to parse it into a different way probably. So let's say we have two or three users of this file, each one of them will have to parse it on different ways to get different properties or something like this. But to be honest, overall, this is a good approach and I will definitely, I think, I mean, this is the only approach that you can use to maintain the player's data persistence between sessions without running the risk of players modifying the properties. And as I showed you here in this file, there is nothing preventing us from using all of these approaches together. So for instance, this approach is actually the singleton approach with two extra methods, which is this load data and this save data. So yeah, basically it's up to you to decide what is the best approach or what is the best mix of approaches that you can use to address this problem. As long as you can make the player's data persistent, you can create this feeling of progression to your player. So you can give the player the feeling that the actions actually have a meaningful impact in the future because this is a very important feature to have your game to make your player feel like they can make something and this thing is important and they actions actually have value. So now let's go to the chat and see what we have here. Storing Vector 2 into JSON works for me. How? JSON file don't have support for Vector 2, don't do that? No, you have to make it parse. JSON files don't have support for... I think that actually when we use this to JSON, maybe it parsed it properly, but I don't know, converts a variant var to JSON text and return the result. Oh, let me make a test on it because this will be interesting because if we manage to parse, let's say the player's data, right? So the resource, the resource file, this will be a quite good approach. Actually, it will merge all the approaches that I showed you into a single file. So let me see if we can store a resource. So this will be quite tricky. Let me do everything here and let's export resource var player data. And let's create this resource. So I will go here because if Godot can manage to parse all of its data types into a JSON format, this is amazing. This is a plus that I didn't ever thought about. So let's create a new resource here. Yeah, we already have it. So open, I will create... No, let me duplicate this because this is not meant to be load. The okay player resource will be the name. So player resource, duplicate. And then this will be the actual script of this. Player resource, we will make this a resource. We will take rid of this. It doesn't have a ready and we won't be saving this resource like this. We use the single tone for that, right? So let's open this single tone. Can you guys, yeah. So let's open the single tone and then we will drag and drop this resource there. Player data. Oh, I was supposed to delete from this other part. So this one, this is a resource. Then this, and in this player data we'll drag and drop this resource here. And actually, I don't want to save anything. I just want, I just need to make sure, I just want to have a print of how this resource will actually be converted to a JSON file. So print to JSON player data. This is what I want to get. Save. Yeah, see, yeah. Basically, this is just a pointer to the resource. So, yeah, I am kind of booming now because I thought that it will convert the actual file. So let's open this in the file manager. Player data, what is it? Players, resource node player, data resource. Yeah, so I thought that growth will actually convert all of this data. But in runtime, what were the values that would be here in runtime and convert this to a JSON file. And after that, we will be able to read this JSON format and parse it as a JSON using the parse JSON file that we have here. Parse JSON. So this parse JSON actually returns a variant, right? So, and this to JSON, what is it? To JSON. To JSON also receives a variant. Variant is a type that growth has in its building types that can be anything in the engine. But unfortunately, it didn't work. I thought that it would basically just create a file similar to this, but as a JSON file. So all of these data will be available as a JSON file that could be parsed using this parse JSON method here. What is it? Using this. And then we will be able to parse this data like seamlessly as a single file, a JSON file, and as a resource. So this would be actually very cool to have, but can I do that? I think that we can do that, but this goes beyond the scope of this live stream. Growth stores them in the stream, like, okay. Yeah, when using resource, it uses references, I guess. Yeah, I wonder what are the other types of good old that we can actually use? I think that for every object, I think that good old will actually parse it as a reference, just a single reference. But I think that for, let's say, AABB, let's see what it brings for AABB. All right. All right, so let's try it right. Right to right. And then here we will be printing this right data. Nice, nice, that's very, very, very convenient actually. So I think that this is, I like that. So I think that for every format, there is not an object. So for every type, there is not a object. Mainly, I don't know why they call, they say that it could be a variant because objects are not converted that well. But for every building type, so for every one of these, we can parse them as a JSON format. This is very nice to have, actually. You could use to JSON function inside your player data, which creates an anonymous object. In the player's data resource, the good source code, yeah, when using resource. Yeah, so I think that the only type of data, the only data structure that Godot doesn't actually parse properly, let me see something. No, I think that it will actually be just an object, yeah. Yeah, I think that Godot can convert any of the objects because they're, I don't know why actually, should be very honest. But yeah, that was it, I guess. So let me close Godot now. Close this, what? This cartel changes. Yeah, so that was it. These were the three approaches that I often take regarding making the player's data persistent. I will be making this live stream a video format later, and I will add the timestamps and all these good things. So yeah, I hope you guys enjoy it. I don't know if I will keep this format. It will be cool to know if this is a good format to watch because this is, I'm making this because I had, I made a tweet later and people suggested that live streams could be a good approach and I made this format to see, to test if live streams would be actually a good approach. So yeah, thank you so much for watching. Let me see if there is something else that I want to tell you guys. Yeah, don't forget to subscribe. Don't forget to subscribe and not subscribe. Follow me on each. But also don't forget to subscribe to the YouTube channel and that kind of good stuff. So that was it. Let me take you rid of this safe text here. So that was it. Thank you so much for watching. Keep developing and see you the next time. Bye-bye.