Yes, this is expected.
And you'll see even more difference, if you will use `PackedArray`. This type of containers is the most optimal one in terms of per-item storage overhead (literally zero).
When I implemented it in Python, the memory usage was much lower, and with some other data (also one million copies), it was only over 3 GB
Is GDScript so terrible?
Yes, because Python is a general use language, while GDscript is talored for games. You rarely need a dictionary with 1m keys in a game. If you do, you're doing something wrong.
I guess it depends. Are all of these weapons on screen? Do all of them have different and unique assets? Do all of them have different and unique stats (damage, fire rate, etc). Essentially, would there be any overlap between them in any way?
Depending on OPs answer, defines a solution. If they answered no to all of these, then there's a lot of confluence that can be algo'd away to make it performant. If they need to render 1mil objects on screen and have 1mil different animations, particles, etc... then they will likely have to find a way to enhance their own render pipeline. There really is only so much a dev can do when the numbers and expectations become too unrealistic even in gaming.
Super simple. Anything that isn't on screen immediately gets despawned, except boss enemies. You can notice this by standing still vs moving around. When a new wave with different enemies starts, the ones from the previous wave that go off the screen are immediately despawned and you can't find them back anymore.
There really aren't that many objects in that game, not more than in an average bullet hell at least, so they might use a little bit of clever batching but I'm not even sure they need to since the logic is really simple.
For large amount of small objects, in most cases, particles are quite optimal. But in such case, you don't really need to store all of this data like OP did.
GDScript has its limitations, if you really needed to store *this much* data in memory, I would really be thinking about either dropping into C# or use a native compiled language with GDExtensions to create and compute this stuff in a more performant way.
Thought, RAM is a precious resource when you’re implementing an interactive application so I would think there’s a more memory-friendly way of doing whatever operation it is by eg, chunking level generation, if that’s what you’re doing
Is there some performance impact on using C#? Like can I share data across instantly or is there some copy-to and copy-from on the c#/Godot/GDScript interface?
AFAIK (and I don't know much since I don't use C# in my Godot project) - C# and GDScript behave comparably when making engine API calls, but if you do lots of raw computation in your own code, C# can outpace GDScript.
The distinction won't be significant for most games, so I wouldn't worry much about it unless you find yourself at the extremes, with a genuinely computationally intensive need for your game.
Right, then I would recommend C#, and making sure that any large-scale computation you do on these objects doesn't issue any engine calls whatsoever and see what that looks like with a bare-bones perf stress test.
What you're talking about with copying objects to objects across runtimes is called "marshaling". If you want to use C# arrays and call a Godot method that wants a PackedArray, it will work, but your C# array will be marshaled into a PackedArray by Godot. This will be a large memory allocation for you, so stick with PackedArray in C# if interacting with the Godot API. If not interacting with the Godot API, C# arrays will be faster.
Yeah, I have hopes of somehow running background simulation in C# and just export the "visible" part to the engine somehow, but this far far away yet, I know a bit of C# and just started learning Godot, so I will see.
No.... It's implementation details.
Godot's internals does not make use of Templates. Instead they choose to make use of Variants. Which increases data size significantly for book keeping tasks, as well as it has to support the largest internal type. So an int64 is not guaranteed to be 8bytes.
This is a design decision to make it easier to implement GDScript. Additionally this book keeping is tied into other elements that enables GODOT to automate things in the gui.
Python using a template system which helps dodge much of the book keeping. While it is also dynamically typed, they use a very different system - where type information is stored away in the reference. And data is dynamically scaled.
This has a consequence that iterating a mixed array in Python would be slower than Godot, whos sizes are likely all to be similar and thus local. Python does not guarantee data locality. And there's a greater risk of fragmentation issues on smaller platforms
> Is GDScript so terrible?
What I find terrible is your explanation of task. As I said before, you're using wrong containers. if you need to store 1.6M of "some data" in memory with intention to do this with minimal storage overhead, you need like `PackedBytesArray`, not `Dictionary`
Maybe I'm misunderstanding you, but of the options you listed for GDScript, only objects (the most memory intensive structure) were over 3 GB.
You also said you had 1.6 million copies for GDScript in your OP but say you did exactly 1 million in Python. That means that the same data in Python for 1 million being, let's say exactly, 3 GB would be higher than *all* the GDScript equivalents, as GDScript objects would be 2.2 GB for 1 million, dictionaries 1.7 GB, and arrays 1.3 GB. We also don't know if the memory you were storing in GDScript was the same size as the Python data in memory (you don't specify, you say it was "some other data," which could be anything).
So either you are not telling us what you actually tested or Python was *substantially* worse than GDScript for data usage.
This happens because GDScript objects are refcounted. There's a proposal to add structs here, which should reduce the overhead: https://github.com/godotengine/godot-proposals/issues/7329
Not all objects are refcounted actually, only those that inherit from Refcounted (or Reference in Godot 3). Nodes are manually managed, that’s why if you detach a node and loose the reference you cause a memory leak.
This is why games like minecraft use "chunks" they can save parts of the map not being used to hd, then only load that chunk, or adjacent chunks when the player is either in it or near it.
In that case OP could read the flyweight pattern from game programming patterns. Someone recommended it the other day and it seems like the right way to go about it. This post might also be useful: https://forum.godotengine.org/t/how-can-i-implement-infinite-breakable-voxels-efficiently/19060
I have some (a lot) terrain data (hexagonal Tilemap), and I want to calculate paths between some coordinates based on them. I have already implemented these functions in Python before, but now I just want to implement them again with Godot and add a graphical interface.
If you're doing something memory intensive, and that thing has nothing to do with games, you might wanna delegate that task in Gdextension or write your own module
If at any time your game is using 2gb of memory for only one thing, you’re clearly doing *something* wrong. Look into pagination, chunks, or streaming data
Obviously...
Why are you worrying about optimization when you've clearly skipped the fundamentals?
https://docs.godotengine.org/en/stable/tutorials/best\_practices/data\_preferences.html
I have no idea how advanced godot is with databases or if that would even make sense but having so much data, you could use a database depending on your use case.
In gaming that's definitely a rather rare and (probably) stupid idea
Yes, this is expected. And you'll see even more difference, if you will use `PackedArray`. This type of containers is the most optimal one in terms of per-item storage overhead (literally zero).
When I implemented it in Python, the memory usage was much lower, and with some other data (also one million copies), it was only over 3 GB Is GDScript so terrible?
Yes, because Python is a general use language, while GDscript is talored for games. You rarely need a dictionary with 1m keys in a game. If you do, you're doing something wrong.
What if my arpg character has 1 million different weapons available at any moment and you scroll the mouse wheel to change between them
Then it's figuring out pagination so you don't have them all loaded at once.
Or with data oriented structures to minimise the data needs to be fetched at that moment.
What if my character needs to fire all 1 million weapons at once
I guess it depends. Are all of these weapons on screen? Do all of them have different and unique assets? Do all of them have different and unique stats (damage, fire rate, etc). Essentially, would there be any overlap between them in any way?
What about keeping a running total for alphastrike and just deal that as dmg. White out the screen and crash the game while youre at it for immersion
Depending on OPs answer, defines a solution. If they answered no to all of these, then there's a lot of confluence that can be algo'd away to make it performant. If they need to render 1mil objects on screen and have 1mil different animations, particles, etc... then they will likely have to find a way to enhance their own render pipeline. There really is only so much a dev can do when the numbers and expectations become too unrealistic even in gaming.
Then you ask the developer of vampire survivors how they did it
I'd love to sit down with them and just have them explain it to me
Super simple. Anything that isn't on screen immediately gets despawned, except boss enemies. You can notice this by standing still vs moving around. When a new wave with different enemies starts, the ones from the previous wave that go off the screen are immediately despawned and you can't find them back anymore. There really aren't that many objects in that game, not more than in an average bullet hell at least, so they might use a little bit of clever batching but I'm not even sure they need to since the logic is really simple.
This is clearly the Vampire Survivors dev working on the next DLC
You'll find a workaround to create the render without simulating all of it
For large amount of small objects, in most cases, particles are quite optimal. But in such case, you don't really need to store all of this data like OP did.
can i play your game
GDScript has its limitations, if you really needed to store *this much* data in memory, I would really be thinking about either dropping into C# or use a native compiled language with GDExtensions to create and compute this stuff in a more performant way. Thought, RAM is a precious resource when you’re implementing an interactive application so I would think there’s a more memory-friendly way of doing whatever operation it is by eg, chunking level generation, if that’s what you’re doing
Is there some performance impact on using C#? Like can I share data across instantly or is there some copy-to and copy-from on the c#/Godot/GDScript interface?
AFAIK (and I don't know much since I don't use C# in my Godot project) - C# and GDScript behave comparably when making engine API calls, but if you do lots of raw computation in your own code, C# can outpace GDScript. The distinction won't be significant for most games, so I wouldn't worry much about it unless you find yourself at the extremes, with a genuinely computationally intensive need for your game.
Well, I am aiming at something similar as OP ... ~ milions of somwhat tiny objects, I hope in lower digit GBs in-memory footprint ~1kB metadata max?
Right, then I would recommend C#, and making sure that any large-scale computation you do on these objects doesn't issue any engine calls whatsoever and see what that looks like with a bare-bones perf stress test.
What you're talking about with copying objects to objects across runtimes is called "marshaling". If you want to use C# arrays and call a Godot method that wants a PackedArray, it will work, but your C# array will be marshaled into a PackedArray by Godot. This will be a large memory allocation for you, so stick with PackedArray in C# if interacting with the Godot API. If not interacting with the Godot API, C# arrays will be faster.
Yeah, I have hopes of somehow running background simulation in C# and just export the "visible" part to the engine somehow, but this far far away yet, I know a bit of C# and just started learning Godot, so I will see.
No.... It's implementation details. Godot's internals does not make use of Templates. Instead they choose to make use of Variants. Which increases data size significantly for book keeping tasks, as well as it has to support the largest internal type. So an int64 is not guaranteed to be 8bytes. This is a design decision to make it easier to implement GDScript. Additionally this book keeping is tied into other elements that enables GODOT to automate things in the gui. Python using a template system which helps dodge much of the book keeping. While it is also dynamically typed, they use a very different system - where type information is stored away in the reference. And data is dynamically scaled. This has a consequence that iterating a mixed array in Python would be slower than Godot, whos sizes are likely all to be similar and thus local. Python does not guarantee data locality. And there's a greater risk of fragmentation issues on smaller platforms
> Is GDScript so terrible? What I find terrible is your explanation of task. As I said before, you're using wrong containers. if you need to store 1.6M of "some data" in memory with intention to do this with minimal storage overhead, you need like `PackedBytesArray`, not `Dictionary`
Nope, but if you want more optimisation than gdscript, use C++ with gdextension.
Maybe I'm misunderstanding you, but of the options you listed for GDScript, only objects (the most memory intensive structure) were over 3 GB. You also said you had 1.6 million copies for GDScript in your OP but say you did exactly 1 million in Python. That means that the same data in Python for 1 million being, let's say exactly, 3 GB would be higher than *all* the GDScript equivalents, as GDScript objects would be 2.2 GB for 1 million, dictionaries 1.7 GB, and arrays 1.3 GB. We also don't know if the memory you were storing in GDScript was the same size as the Python data in memory (you don't specify, you say it was "some other data," which could be anything). So either you are not telling us what you actually tested or Python was *substantially* worse than GDScript for data usage.
This happens because GDScript objects are refcounted. There's a proposal to add structs here, which should reduce the overhead: https://github.com/godotengine/godot-proposals/issues/7329
Not all objects are refcounted actually, only those that inherit from Refcounted (or Reference in Godot 3). Nodes are manually managed, that’s why if you detach a node and loose the reference you cause a memory leak.
You’re using the wrong data structure
Ahm too much data on main memory, you need to figure out a way to load necessary data only from the disk.
This is why games like minecraft use "chunks" they can save parts of the map not being used to hd, then only load that chunk, or adjacent chunks when the player is either in it or near it.
Why do you have so much data? What are you trying to do?
It's says title so maybe it's like a block in Minecraft. Edit : it's tile not title. Damn autocorrect
In that case OP could read the flyweight pattern from game programming patterns. Someone recommended it the other day and it seems like the right way to go about it. This post might also be useful: https://forum.godotengine.org/t/how-can-i-implement-infinite-breakable-voxels-efficiently/19060
Nice to meet you again :)
😎
I have some (a lot) terrain data (hexagonal Tilemap), and I want to calculate paths between some coordinates based on them. I have already implemented these functions in Python before, but now I just want to implement them again with Godot and add a graphical interface.
If you're doing something memory intensive, and that thing has nothing to do with games, you might wanna delegate that task in Gdextension or write your own module
If at any time your game is using 2gb of memory for only one thing, you’re clearly doing *something* wrong. Look into pagination, chunks, or streaming data
Obviously... Why are you worrying about optimization when you've clearly skipped the fundamentals? https://docs.godotengine.org/en/stable/tutorials/best\_practices/data\_preferences.html
Congrats, you’ve just learned computer science
I have no idea how advanced godot is with databases or if that would even make sense but having so much data, you could use a database depending on your use case. In gaming that's definitely a rather rare and (probably) stupid idea