# Keeping per-client data, when using singleton-based states

In my game, I deal with a lot of units. Every unit implements a state machine, and changes states quite often. As a result, I'd like to keep my states as singletons, since I want to avoid the creation of one and the same state over and over again.

This works quite OK for most case, except when I need to introduce some time intervals, e.g. in 5 seconds the unit has do something. Of course, everyone knows that singletons cannot keep per-client data, which is exactly what I want to achieve. The state should be aware of the time elapsed since it was initiated for a specific unit.

One way to do this would be to keep timers within the units themselves, but that doesn't make a good abstraction.

Another one, which I am currently working on, is to keep the per-client state, i.e. timers on a Dictionary/Hash within the state. When a client initiates the state, the timer gets activated, and a dictionary record gets set. Every time when the specific timer is needed, the dictionary is queried with the id of the specific client. Then on state exit, the record is deleted.

Which is in general the proper way to deal with these problems?

This is pretty much why "don't use singletons" is recommended every time the subject comes up.

I'm not sure what you mean by "per client," so I'm translating that as "per instantiated object in your application." If you elaborate on how your application is organized I might be able to get more specific.

The first sin you committed was premature optimization. How many units is "a lot?" Why do you want to avoid creating new state objects? Afraid of typing, estimated memory constraints, measured performance on a test with "a lot" of states, just felt like it?

Solution 1) Get rid of the singletons. Make your states proper objects and allocate them, only if you have measurable speed problems go further than this.

Solution 2) If you measure that your allocations are eating your performance then make a pool of those states, pre-allocated, and whenever you need a new state get one from the pool and initialize it.

Solution 3) If your states carry no data (other than the timer) and are merely logic? You can then keep the singleton, use a local timer, and pass the timer to your singleton as a parameter. Yes, you will need to allocate the timer, which is why I recommended #1 first.

Solution 4) If your states also have data and not just logic, see Solution 1.

If your states are parametric, e.g. "waiting until time T" instead of just "waiting", then they shouldn't be singletons. Conceptually, each combination of parameters is really a separate state, and it doesn't make sense to create separate singletons for, say, every possible time a unit might want to wait until.

If you also have other states that don't require any parameters, and want to implement those as singletons, then it's up to you to come up with an interface that hides the difference from the outside. That is, of course, assuming that you do want to hide it, which might not be the case.

Note that, strictly speaking, things like the position of each unit, and any other properties they might have, should also be considered part of the state of the unit — the "state objects" you have really only represent a part of the unit's state (or the state of a part of the unit; you could think of the "state machine" as a literal machine that exists inside the unit and sometimes interacts with the rest of it). These additional state variables are what allows you to represent a state like "stand still" as a simple state, without having to parametrize it as "stand still at position X". If you find that a lot of your states are of the form "do something until time T", you might indeed want to consider equipping your units with a timer property, and changing those states to "do something until the timer is triggered".

You can make an object to store the relation between manager and unit instance

struct InstancedUnitRelationWithManager
{
public Unit TheUnit;
public float TheTime;
}


and in your manager add a list of relations for each object...