Normally in the Pawn class you put the functions the pawns use.
But if you have a lot of functions and a lot of pawns loaded simultaneously, this I suppose will increase the memory consumption.
So if I move a lot of those functions into a class with a single instance, for example Gameinfo, I can call those functions from the pawn and save memory.
I’m already doing some stuff like that, but I’m hesitating to move more functions. So the questions:
Does anyone do this?
Is memory saving effective with, for example, 1000 pawns?
Can there be a bottleneck if many pawns call the same function in gameinfo at the same time?
I don’t have any definitive answer for you. The best thing I can suggest is testing it for yourself and seeing what “stat memory” and “stat game” tell you. I’d be interested in hearing what you discover.
I have strong doubts that more functions on a class will increase memory in anything else than a fully negligible way, even if you have thousands of instances of that class. from my understanding class variables increase the size of that instance because they have their values stored in the instance, but why would functions have such an effect if nothing is really stored about them?
if more functions would indeed increase memory anyway I’d opt for turning the functions into static ones - that way they are not part of each instance anymore, and it’s surely more practical to make the functions static than move them to another class (and change all the calls to that function)
but even so (and getting highly speculative here), I suspect you’d save no more than kilobytes worth, or perhaps megabytes. and this is RAM we’re talking about, not VRAM. nothing compared to the 8+ GB you’d expect your most basic users probably. this to me this falls into near-useless micro-optimization that’s immensely more hassle than its worth.
but like Nathaniel3W said, better test yourself with memory stats (and of course report back!)
Yes, trying it and comparing it is the only way to get rid of doubts, but I have to move many functions and adapt them to pass the reference of the pawn that calls them.
huh, that’s quite a lot indeed. still probably not very significant but at least worth looking into
still curious if moving any functions will do anything or if it’s just member variables taking up the data.
I guess moving a handful of functions to another class or making them static will already give you some kind answer if you’re comparing against 1000 pawns
Not sure, perhaps are the skel components what are wasting ram. I’m moving to gameinfo functions that aren’t called very often.
Anyway the 1000 pawns (or 2000 or more in the future) now are in a sleeping mode when they are far, but I’m planing to store their variables and properties in an array and delete them. Then doing a regular read to locations in these array, spawn the npc when is near and reconstruct using the properties saved.
I tried that time ago and worked well, and reading the array was faster than having 1000 paws hidden and unticked. But I need to have the code for the pawns finished, if not I need to add to the system the pawn new variables, arrays, etc… and it’s tedious. So I use the sleeping mode for now.
The array method can be used in the save/load game functions too, which I haven’t done yet for the same reason, due to the need to have the variables in the pawns synchronized with the save/load functions.
Also the garbage collector don’t like very much the array method.
Is this a single-player game? Do you really need all of the pawns loaded all of the time? Can you put the pawns in streaming levels that you load and unload as the player moves around?
It’s single player, and for now the NPCs far are in sleeping mode (hidden, no tick, etc), but I have plan to store their properties, destroy them and then re-spawn when the player is near.
Putting the pawns in stream levels are another solution for those who don’t need to save interactions with the player.
But these techniques in Assassins Creed can be used with UDK?
About these videos showing millions of NPCs, time ago I talked with one of the creators (using another engine), he told me that the skeletalmeshes (for the far NPCs) were reemplaced with staticmeshes, and the animation were done using different meshes (for example 4 meshes to use for the run animation, like the old times using sprites).
I didn’t see it practical to do it with UDK in my case, because the bottleneck is in the movement around the map. It wouldn’t do much to lighten the meshes.
I use a method of moving at intervals every few seconds actors who are far away. For example with the boats, I have about 40 of them circling the island constantly with no noticeable impact on performance.
They follow a path, and when they are far away or not visible, they move only once every few seconds with a setlocation(). The interval varies according to the distance if they are visible.
At first I did not use this method, they moved every tick, and the performance was excessive.
Putting the pawns in stream levels are another solution for those who don’t need to save interactions with the player.
I’m working on a new expansion that will have NPCs in streaming levels and the NPCs have data that can be saved and loaded. The way I do it is this:
The persistent level has an actor that contains an array of names. This is an index of all the NPCs in the game. Every name in the array is the name of an NPC in a streaming level. (Just the name–not a reference to the NPC itself. You’re not allowed to reference actors in a different level.)
Every NPC in every streaming level has an int variable to remember its own position in the NPC index.
Every time I need to reference an NPC somewhere in the game (such as a quest where you have to deliver something to an NPC in a different town) I use a reference to the NPC index instead of a reference to the NPC itself (because you’re not allowed to have direct references to actors in another level).
Any time I need to save changes to an NPC, I use that same index. Then when a streaming level gets loaded, the NPC calls PostBeginPlay, and it can look itself up to see if it has any changes that it needs to take into account.