GameInstance, managers and... where are the ticks?

Hello.

I have been playing around a bit with the editor and only recently wanted to go at it in earnest with a couple of friends.

As some may have guessed we need to have some manager classes for all kinds of things and for this purpose the UGameInstance class looks really promising.
It is initialized once(not counting running editor) and exists across levels. Info and docs respectively:

https://docs.unrealengine.com/latest/INT/API/Runtime/Engine/Engine/UGameInstance/index.html

It all seems good except there is no tick function on the UGameInstance class. Not only that but after taking a look at the AGameMode class it seems the UGameInstance class could use more than just at tick function. Being able to tell when a level is loaded would be nice as well. I would not regard that as duplicate behavior of the AGameMode class as each of them could/should make use of this. Also the AGameMode seems to only exist on the server side in a multiplayer game.

After some more digging around I learned that the UGameInstance could implement the FTickableGameObject to get a tick function. The other of the tick however cannot be changed and to make matters worse is done so after the actors.

It seems the UGameInstance was only first introduced in 4.4 and as is stated in the links its purpose was for cross-level storage of data and it seems to have been stuck with only that purpose in mind. I have searched around trying to find a solution to this but have been unable to find any (at least properly supported ones). I find game managing and the likes much more obvious and essential than storing some game data across levels which could be handled on disk(not that it should) and the lackluster UGameInstance is odd.

So far I can think of two ways of trying to handle ticking in a UGameInstance subclass.

  1. Modify the source code and recompile the engine which is something I would rather not. It also seems silly having to do this for something so basic and simple yet essential.
  2. Create a special tick actor which has components that each calls a different tick function on a custom UGameInstance subclass. With this the tick group can be specified as well. This seems reasonable although the UGameInstance is still lacking and this should really not be neccesariy (I know I have mentioned this several times by now). I can see some issues with this though. One is that there are only a handful of tick groups defined and done so with an enum leaving no option for expansion unless the source code is tinkered with. Unless I remember wrong the first ticking group is in use by the actors among other classes. In other words is is not possible to have a tick before the actors. Another problem is that an actor gets destroyed when a level is unloaded which means the actor would have to be recreated. What happens in between? Would there simply be no ticks? What about having no level loaded at all not regarding a transition. Can this actually happen? What to do about updating a loading bar on level transition? Something somwhere needs to continually refresh it.

I would like to hear opinions of others on this and possible better ideas/solutions for it. I canā€™t imagine creating a game without this functionality and I find it odd that it wasnā€™t until 4.4 the UGameInstance class was introduced in the first place. I have used the Unity editor to some degree as well and it too lacks anything like this as well. It did however allow an arbitrary number of ticking groups to be set simply with an integer which despite being a bit ugly did work. Based on this I may just be the odd one here and there are some other better ways for doing said things.

After I wrote this I forgot to mention we are working on this part in c++ not blueprint:P

Interesting question :slight_smile:

For my project I defined some functionality within actors that call methods from my game instance each tick. That works fine.

About ticking groups I do not know enough to give you an advice.

But as I remember, there is always a map loaded even when transition takes place and you can ā€œpreserveā€ actors through this travel (read about that here: Keeping Actors Between Levels - C++ - Epic Developer Community Forums).

I know thatā€™s not much but perhaps it helps a little.

Yeah I just remembered that shortly after and read about the preserving thing. With how the UGameInstance was mentioned I sort of discarded the idea but the Unity thing I wrote about got me thinking since it has the exact same thing. Still not very elegant as I mentioned:P

try that out for the time being. I do hope the UGameInstance would be more developed at some point not too far in the future. It is the perfect place for this stuff but nothing have happened for a long time so I guess I should try to not hope:P

EDIT: Where do you keep the references to the actors? The actors needs to be instantiated at some point if they do not already exist.

Itā€™s pretty easy to get yourself a nice ā€˜tickā€™ function inside GameInstance.




//.h file

void Init() override;

void Shutdown() override;

bool Tick(float DeltaSeconds);

FDelegateHandle TickDelegateHandle;

// .cpp file

bool UYourGameInstance::Tick(float DeltaSeconds)
{
    // Do your logic

    return true;
}

void UYourGameInstance::Init()
{
    // Register delegate for ticker callback
    TickDelegateHandle = FTicker::GetCoreTicker().AddTicker(FTickerDelegate::CreateUObject(this, &UYourGameInstance::Tick));

    Super::Init();
}

void UYourGameInstance::Shutdown()
{
    // Unregister ticker delegate
    FTicker::GetCoreTicker().RemoveTicker(TickDelegateHandle);

    Super::Shutdown();
}


3 Likes

I see. UObjects can be used like that as well. The delegates be nice for other stuff later on. Nice to know about. give it a try. UObjects also seem to exists across levels as well so all seems well. Thanks:)

EDIT: Oh yeah forgot one thing. What about the tick group? Need to be able to set it properly though. When is that ticker going off?

You can also use multiple inheritance (justified in this case, Iā€™d wager) and inherit from both UGameInstance and FTickableGameObject(iirc).

Using the delegate handle mentioned above is a little prettier, though, since multiple inheritance has its problems. Just thought Iā€™d offer option B :slight_smile:

A staff answer on this topic.

EDIT: Just read your post a little more. Whoops, you already knew about this! Have you tried modifying the tick group of this?

Yeah I had already the FTickableGameObject in mind but I wanted a tick before actors if possible. Still when is the tick for the delegate happening? It seems you can adjust a delay so it just tick at some default interval independent of everything else?

I have checked if that is possible however I have not found a way to change the tick group of either the FTickableGameObject nor the ticker delegate

We have a pretty solid Manager system. GameInstance is definitely the place to do it. Iā€™d like to share source code for this but it doesnā€™t entirely belong to me, so Iā€™ll ask first.

Basically, create a BaseManager class that inherits from UObject and FTickableGameObject. In your GameInstance Init() function, setup those managers and ensure they are registered with the GameInstance, and that they can only tick when registered:



bool UBZGame_BaseManager::IsTickable() const
{
	return bPrepared;
}


When the GameInstance runs ShutDown(), you can destroy the Managers. We also make our Managers UPROPERTYā€™s to take care of Garbage Collection, and create them in the Constructor of the GameInstance:



UBZGame_GameInstance::UBZGame_GameInstance(const FObjectInitializer& ObjectInitializer)
	: Super(ObjectInitializer)
{
	GameObjectManager = ObjectInitializer.CreateDefaultSubobject<UBZGame_GOCManager>(this, TEXT("GameObjectManager"));
}


Important Note: When you want to ā€˜Getā€™ a Manager, you should ALWAYS get it from the GameInstance and pass in some kind of World Context Object. If you donā€™t, Multiplayer PIE sessions screw you over. Also, a nice Static Blueprint function for accessing the Manager from anywhere can be useful:



	UFUNCTION(BlueprintPure, meta = (DisplayName = "GOCM", CompactNodeTitle = "GOC Manager", Keywords = "GMM Game Instance Manager", HidePin = "WorldContextObject", DefaultToSelf = "WorldContextObject"), Category = "Game")
	static UBZGame_GOCManager* GetGOCManager(UObject* WorldContextObject);


Hope this helps :slight_smile: Doing it this way means you donā€™t have to ā€˜Tickā€™ your gameinstance and subsequently declare delegates for all the Managers. Instead they tick themselves as and when they need to (you may not always want your manager to tick, for example)

1 Like

Can you elaborate on this? Iā€™m assuming you only have one manager (of any given type) in the game instance, so what does the Getter do with the world context object?

To TheJamsh. This was what I wanted all along the problem is when to tick the managers or more precisely the order compared to other tickgroups. I wanted to have at least 2 different ticks, one prior to everything else if possible and one near the end of the whole cycle.

I am also interested in an elaboration of the context object for multiplayer purposes. I have seen this done in the unreal code a few times. I presume the object is to help identify who(which machine or world instance etc.) is asking for them. How would you go about implementing it?

Ah yeah that might actually just be caused by the way we did itā€¦ basically we declare a ā€˜staticā€™ variable of UGameInstance in our GameInstance, and ā€˜setā€™ that in the GameInstance. Effectively the GameInstance declared a variable of itself somewhere as a static and stored it. The Managers all stored a reference to that Static variable, the idea being that when you ā€˜Getā€™ the Manager from anywhere in Blueprint or Code, you donā€™t have to ā€˜getā€™ the game instance and pass it in as a variable.

Unfortunately because it was Static and because PIE shares the same Memory, it meant that all PIE instances create the Managers, but they all referenced the first static variable. Whenever the clients updated their local managers, they were actually updating the Serversā€™ manager. Caused me all manner of problems when my Quadtree kept dividing up segments because each Client kept telling it toā€¦

I should have been more clear really, what I meant was you pass in a world context object so that you can get the game instance, or just get the local game instance first and reference those managers. Of course it doesnā€™t matter in Standalone, only PIE.

As for TickGroups there are a few you can use, though I donā€™t know if (for safety reasons) you can actually tick an object twice. I *think * partially because of this:



TStatId UBZGame_BaseManager::GetStatId() const
{
	return UObject::GetStatID();
}


EDIT: Just re-read and it sounds like you want to tick before all actors have ticked. Try looking in LevelTick.cpp in Runtime/Engine/Private and see if you can hook in somewhere thereā€¦ that I believe is the source of all things ticking :stuck_out_tongue:

Yeah it was probably a bit unclear since my first post was sort of several questions and some whine combined.

The actors use the PG_PrePhysics tick group which is the first one so yes the only way to tick before actors is to modify unreal source code. I try to avoid this for the time being and see how it turns out.

As for specifying a tickgroup I do not know how the StatId is supposed to be used if it is for this purpose at all.

I took a look at the FTickFunction but I cannot grasp entirely how it is supposed to be used. When looking at the derived classes it seems to have ā€œDiagnosticMessageā€ and ā€œExecuteTickā€ which can be overriden. I presume the docs are outdated and hence they are missing from the ā€œFTickFunctionā€ page. I presume I would have to create my own struct that inherits from the FTickFunction and the overriden ā€œExecuteTickā€ should call the tick function on the gameinstance or managers whichever is chosen. But where is the FTickFunction supposed to be created? In the game instance like with the delegate example earlier?

I have another question relating to multiplayer now that you mentioned some things about it. If I need to do some stuff in the managers or somewhere else in when a level is loaded where should I do this? The game instance is the most logical place for this as well but as I mentioned in the first post is lacks functions for this which are present in the AGameMode class. As we know however it only exists on the server side. I had thought about the player controller being the next thing in line but there may be several of these and it is an illogical place for this sort of thing to be handled. Have I missed something else that can be derived from somewhere?

EDIT: I see so without the static variable there is no problem then. Also I think you can get access to the game instance with the UGameplayStatics but you probably already know of this or had other needs back then:P

Yeah the only thing thatā€™s persistent between levels is the GameInstance, which is generated Server & Client side. Also it doesnā€™t play any role in Replication since itā€™s such a founding part of the game session.

Player Controllers are created when a play logs into a level, so you could potentially override ā€˜PostInitializeComponentsā€™ in the PC and do your logic there. What exactly is the problem your facing that requires all this btw? Might be able to help more or propose something else.

Thanks for posting this TheJamsh and if you are able to share more that would be great. This is an area I am particularly keen on understanding more. Iā€™m sure eventually I muddle my way through it but it would be great to see some examples of proper ways of doing this.

At this point in time there is none tbh. I did however figure the need for ticking at different times for some future game logic that would best be updated in the same game loop cycle. I do plan to add some custom event stuff that needs to update towards the end. As for the last part about loading level I could come up with many things that you would want to load besides the level itself. It was more of a thing that I expect be needed soon. We only just started with the project but having a solid but basic framework is nice to work with.

Letā€™s say you want to grab some stuff from a database that you want to have for when you load a level then what would you do? Even if you donā€™t need to load stuff but just have code to run which is used by the level such as scripts etc where would you put these? The game instance has no idea of when a level is loaded and check it either except if you put some sort of conditional inside a tick function which would be odd. If the script is not fired by triggers in the level itself is what I am hinting a bit at. I donā€™t know if I am just thinking about it in a strange way but I do think having the level events and such from the AGameMode on the UGameInstance would be neat.

It may seem a bit silly to be concerned about some stuff that is not currently necessary however I do recon having knowledge of and implementing ticking behavior properly early on would be for the better. It is a small thing after all and I would not have expected it to be this problematic. It is nice to cover your bases early on especially if it doesnā€™t require much effort and then avoid alot of headaches trying to change things later which could involve any number of hacks:P

I hope this would be changed sometime in the future perhaps but as there are workarounds like with spawning actors and use their tickgroup stuff I guess it has very low priority or maybe havenā€™t even been considered. Well I wouldnā€™t know really just a guess:P

Hello, I have have been busy the last couple days. Just wanted to say thanks for the help.

I suddenly remembered that there are a couple example projects. I checked out the ShooterGame one and it pretty much covers everything. So for anyone reading this and wondering about some things go check out the example projects first. Happy coding!

Hi, Iā€™ve check out the Shooter Game sample but couldnā€™t find a solution. Especially, the problem of having a tick before and after all actor tick. How did you solve this problem? Thanks.

Some stuff that might be useful from my experience:

  • GameInstance: has no Tick() because it persists between levels. Not sure it makes sense to Tick() when there is no world to do anything with.

  • GameMode.Tick() - tick stuff here that you want to Tick() in the GameInstance (like a persistent net connection in the GameInstance).

  • GameMode.BeginPlay() - if your GameInstance needs to do anything when the game starts, and all actors are ready, call it here.

  • GameMode.InitGame() - this event is called before any other functions, including all Actorā€™s PreInitializeComponents(). Do stuff here before anything in the world initializes.

  • Actor.PreInitializeComponents() - get stuff done before any components are initialized.

  • Actor.PostInitializeComponents() - get stuff done after all actor components have been initialized.

BTW, what are you doing that ā€œmust be done before and after all actors Tick()ā€? It probably doesnā€™t need to be done. Just handle it next Tick().

Three year old bumpā€¦ cā€™mon people.