Jump to content

  • Log In with Google      Sign In   
  • Create Account

Banner advertising on our site currently available from just $5!


1. Learn about the promo. 2. Sign up for GDNet+. 3. Set up your advert!


Getting the rid of managers


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
14 replies to this topic

#1 Krohm   Crossbones+   -  Reputation: 3509

Like
0Likes
Like

Posted 21 October 2011 - 11:59 AM

Thank you very much Gamedev for providing me food for thought. This is a follow-up on Questions about managers to avoid hijacking the thread.

It's a real shame, but I do have a few managers. I tried to not call them that way, but I couldn't figure out anything so I just gave them a quick name and carried on. I sometime split them with "moderate" success but they resist in existing. I am really ashamed to say but they are truly ugly! Not only they are "some sort of managers" but they don't even got a nice design.

Pearl number 1: ImageManager. This resisted because I'm lazy and I don't want to check out the file again. I suppose I might change it tomorrow to ImageLoader. This is not so bad after all. Only thing it does: reference-count image loads.

Pearl number 2: BasicManager : protected CallMapper, protected base::ImageManager.
/*! The "basic" manager deals with "basic" resources. ...*/
If I look back, I cannot recall what taken me there... this thing does pretty much nothing but manage "waves"... which are probably what you're thinking about right now. There is some processing involved. There's quite a bit of interaction between this thing and the scripting systems as well as shader management. I therefore suppose WaveSomething could be a better name (I'd probably also make it a component instead).


Pearl number 3: AdvancedManager : protected BasicManager, protected FlexMaterialManagerInterface
This was really big some time ago so I split out a GameWorldSystem class. I'm fairly happy with the GWS class, it seems it has its right to exist. Tomorrow I will rename FlexMaterialManagerInterface to FlexMaterialLoaderInterface.
What does this manager do? It loads "more advanced resources". Very informative.
This has quite a lot of interactions with the scripting subsystems, the management is not always trivial as I'd like to. I expect to need more logic here in the near future (so it will be even less trivial) the requirements of this future expansion are not quite clear yet. So far I've been leaving it as is waiting for more focused semantics to rise from the thing.

Since I'll need to touch this last one "soon" I guess it's a good time to begin thinking at it. Suggestions are welcome.

Sponsor:

#2 frob   Moderators   -  Reputation: 26635

Like
2Likes
Like

Posted 21 October 2011 - 01:48 PM

It's a real shame, but I do have a few managers. I tried to not call them that way, but I couldn't figure out anything so I just gave them a quick name and carried on. I sometime split them with "moderate" success but they resist in existing. I am really ashamed to say but they are truly ugly! Not only they are "some sort of managers" but they don't even got a nice design.

As in the other thread, a class that manages stuff isn't a bad thing. It can be a good thing. The issue is when you try to turn it into a singleton.

Pearl number 1: ImageManager. This resisted because I'm lazy and I don't want to check out the file again. I suppose I might change it tomorrow to ImageLoader. This is not so bad after all. Only thing it does: reference-count image loads.


Great, it does one thing, you can create as many as you want even if you only happen to need one.

Pearl number 2: BasicManager : protected CallMapper, protected base::ImageManager. /*! The "basic" manager deals with "basic" resources. ...*/
If I look back, I cannot recall what taken me there... this thing does pretty much nothing but manage "waves"... which are probably what you're thinking about right now. There is some processing involved. There's quite a bit of interaction between this thing and the scripting systems as well as shader management. I therefore suppose WaveSomething could be a better name (I'd probably also make it a component instead).

Yes, it does not do one task. It does multiple ambiguous tasks.

Is it a custom container for images? Is it a custom container for wave objects? Does it coordinate the the availability of resources?

Define what the thing actually does (without the word manage) and it should help. If you cannot, it is possible that you have given it too many responsibilities. Break it up into smaller individual tasks.

Pearl number 3: AdvancedManager : protected BasicManager, protected FlexMaterialManagerInterface
This was really big some time ago so I split out a GameWorldSystem class. I'm fairly happy with the GWS class, it seems it has its right to exist.

Seems like a renamed version of other stuff.

There is often a simulator class, and it contains instances of lots of pieces that make up the simulator. Sounds like your own re-discovery of this.

Tomorrow I will rename FlexMaterialManagerInterface to FlexMaterialLoaderInterface.
What does this manager do? It loads "more advanced resources". Very informative.

Why can't your other resource manager handle this?

The tasks of pre-loading, loading, caching, unloading, and otherwise getting blobs of data into and out of your game is a very common task. It is very frequently implemented as a factory method that works with your own serializers and deserializers.

It does not really matter the type of object if you use a factory. You want to load an animation named foo. You want to load an audio clip named baz. You want to load a model asset named bar. You want to load a UI element, or shader, or whatever else. All of them do exactly the same thing: possibly precache, load, potentially cache or share, and unload.

Any "more advanced resource" is still just a resource, isn't it?

This has quite a lot of interactions with the scripting subsystems, the management is not always trivial as I'd like to. I expect to need more logic here in the near future (so it will be even less trivial) the requirements of this future expansion are not quite clear yet. So far I've been leaving it as is waiting for more focused semantics to rise from the thing.


What is a script in your system?

Often a scripting system can be implemented very simply as a state machine.

The script writers get a very basic state machine. There are nodes and transitions. That's it.

Each node can call functions and use data that you expose in your source code or data. It does the thing. Then when whatever condition is specified in the transitions are satisfied, that transition is followed and the machine moves to the next state.

It can be extremely easy to implement, and insanely powerful for script writers who want to invent new ways to break the game.

Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#3 Krohm   Crossbones+   -  Reputation: 3509

Like
0Likes
Like

Posted 22 October 2011 - 03:26 AM

You go straight to the point here!

As in the other thread, a class that manages stuff isn't a bad thing. It can be a good thing. The issue is when you try to turn it into a singleton.

I think I've got this. Problem is this IS a singleton. I use hashes a lot, the system probably won't run correctly if more than one of those is loaded (it will just load up stuff multiple times).

W1) Is it a custom container for images? W2) Is it a custom container for wave objects? W3) Does it coordinate the the availability of resources?

W1) No, I used inheritance just because it cut some corners here and there, and I was too lazy to route the calls to a nested object. There indeed was some sense in this choice, ideally those objects would all make up a big "execution environment" providing all the features. Of course that's the same thing by composition... I will look at the code next week and re-factor.
W2) It has some logic involving 'ticking' the waves each time step. Originally, that was not even planned to exist, I was just performing some cleanup and I pulled it out of a bigger class.
W3) No, an external component does.

Although what this does is pretty clear, my main problem with that is finding a name which is short and descriptive. Mainly jargon.
I'm not quite sure I can split it again as it's like 300 LOC.

Seems like a renamed version of other stuff.

There is often a simulator class, and it contains instances of lots of pieces that make up the simulator. Sounds like your own re-discovery of this.

I don't quite get the point here. Yes, it's just another "piece of something"... so? And what is this "discovery" thing you're referring to?

IM1) Why can't your other resource manager handle this?
IM2 The tasks of pre-loading, loading, caching, unloading, and otherwise getting blobs of data into and out of your game is a very common task. It is very frequently implemented as a factory method that works with your own serializers and deserializers.
IM3) Any "more advanced resource" is still just a resource, isn't it?

IM1) It was originally part of other managers. It has been pulled out to support some external utilities involving material mangling (mainly the filters).
IM2) Problem was that some resources are terribly complex. I had one whose factory method took about 12 parameters. I initially just grouped those parameters in more logical matters - one of those turned out to be the FlexMaterialLoaderInterface - I eventually got this down to 4, then figured out that those things could have been useful in a broader topic. They were originally intended to be temporary duct tape but they have been there for a while.
IM3) Yes of course but I don't think I am well aware of what I should do. Perhaps I'm just stuck in the drawn picture. Those objects provide the factory methods. The need to link them together arisen by the interactions of the 'advanced' resources with regards to the basic ones. It's mostly historical and somewhat redundant now that scripting is more pervasive. Yes, I will think at this.

S1) What is a script in your system?
S2) Often a scripting system can be implemented very simply as a state machine.

There was a state machine based script system in the beginning. There also was another scripting system (I'd likely not elaborate on that, unless it's absolutely necessary). I eventually got mad at the two things and melted them together. Think at a dumb version of UnrealScript. I plan to go back to state-based systems a day but I will likely layer those on top of the current scripting.

#4 L. Spiro   Crossbones+   -  Reputation: 17284

Like
1Likes
Like

Posted 22 October 2011 - 04:03 AM

I have a very limited time in which to reply so I can only cover a small portion of your concerns.
As I have said before, singletons and globals in general create security risks, though I am not speaking only from that standpoint but also from the design standpoint.

So let’s assume singletons are not welcome, and you are wondering what you can do to make sure that no more than 1 instance of a class exists. Well I designed the in-house engine of a company long ago and I thought that it was common sense not to make 2 CGame instances. A CGame class would create a sound device and some other things that needed to be done only once.However, one of my coworkers was a programmer, but not a game programmer. For debug issues he was making a second game instance.

To my amazement, my sound manager still worked as expected after having been initialized twice, but still this was not a logical course of action. So I finally added debug only code that checked to see if a second CGame instance was made. That fixed the problem quite effectively, because most developers work in debug mode until near the end of the project. So there is a way to ensure that only one instance of your class is created, even without using a singleton, and without creating global variables that can be exploited on release. These global variable exist only in debug mode, so they act to both protected from incorrect behavior and doing so without creating security leaks in release mode.
In my design, singletons are not needed for sound managers etc., because the CGame class, which must be created in order to use my engine, creates that pointer itself, and every state of the engine receives a pointer to the game class and can therefore reach the sound manager, or whatever other manager there needs to be.


L. Spiro

#5 patrrr   Members   -  Reputation: 1113

Like
0Likes
Like

Posted 22 October 2011 - 04:33 AM

So let’s assume singletons are not welcome, and you are wondering what you can do to make sure that no more than 1 instance of a class exists.


If you want to make sure that no more than 1 instance of a class exists, why not use a singleton? That's what they're meant for, after all. If singletons are "not welcome", but it's OK having classes that can only function properly when there's max one instance, then that's just hypocrisy.



#6 DarklyDreaming   Members   -  Reputation: 366

Like
0Likes
Like

Posted 22 October 2011 - 05:42 AM


So let’s assume singletons are not welcome, and you are wondering what you can do to make sure that no more than 1 instance of a class exists.


If you want to make sure that no more than 1 instance of a class exists, why not use a singleton? That's what they're meant for, after all. If singletons are "not welcome", but it's OK having classes that can only function properly when there's max one instance, then that's just hypocrisy.


Singletons are to be used for a case where there can only be one instance of the class without causing erroneous or incorrect behaviour. It's not a catch-em-all insurance policy against having > 1 instances. Sure, it can be used that way, if you really want -- just like globals can be used for things that aren't truly needed globally.

It's just not a terrific idea to do so. Especially when it comes down to: "I think there should never be need for two instances of this."
"I will personally burn everything I've made to the fucking ground if I think I can catch them in the flames."
~ Gabe

"I don't mean to rush you but you are keeping two civilizations waiting!"
~ Cavil, BSG.
"If it's really important to you that other people follow your True Brace Style, it just indicates you're inexperienced. Go find something productive to do."
~ Bregma

"Well, you're not alone.

There's a club for people like that. It's called Everybody and we meet at the bar."

~ Antheus


#7 frob   Moderators   -  Reputation: 26635

Like
1Likes
Like

Posted 22 October 2011 - 01:20 PM

Getting back to the GWS object, that is just fine. Many games will have a main simulator object and will work just fine with it. Your re-discovery is not an issue.


As for the singletons, the business world and TDD advocates naturally solve it by their basic philosophies. Many game developers get stuck in the emotional rut that there is only one game window shown on the screen at a time, therefore singleton.


Most well-designed games I've worked on don't have this issue.

Some experiments to help you:
One great trick to split screen and certain graphical effects is to run two different view windows at once. Can you run two windows? If not, why not? There is no physical reason why you cannot run multiple windows on the screen; that is exactly what it is made for. What about split screen within a single window? If not, why not? Your display area is normalized to a rectangle, why should it matter if the rectangle is only a portion of the physical screen? Why should you be restricted to a single rectangle instead of two or three or nine? The restriction is artificial and probably unnecessary.

One of the best in-house engines I worked with had two views on screen; one showed the regular game, the other was exactly the same view with alternate visualization: overdraw, physics objects, physics motion displays, and x-ray vision were the most useful to me. Any fundamatal reasons your game engine cannot do that? Why not?

Can you have one game instance run multiple simulations internally? If not, why not? It can make network play easier to debug since you can eliminate the difficulties of networking and simply hae direct IPC between the systems. You should be able to have a collection of game simulations all running currently (even if it is slow). Automted testing (either test scripts or stress tests) could start 30+ instances of the simulator and run them all at once.

Can you have multiple instances of your resource manager? If not, why not? When debugging and stress testing it is sometimes useful to have multiple instances. Sometimes it is useful to have one instance pulling from the main resource location and a second instance pulling from a debug resource location.


At home I use TDD so this isn't an issue because everything must be instanced rather than globals or singletons. One way to do this is have everything come from the game simulator. The simulator has clocks. The simulator has resource loaders. The simulator has everything neccesary to run the game. The simulator has an interface for display, but does not have a view (that is secondary to running the game). Now create and run two or more independant simulators.

Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#8 Krohm   Crossbones+   -  Reputation: 3509

Like
0Likes
Like

Posted 23 October 2011 - 12:48 PM

In my design, singletons are not needed for sound managers etc., because the CGame class, which must be created in order to use my engine, creates that pointer itself, and every state of the engine receives a pointer to the game class and can therefore reach the sound manager, or whatever other manager there needs to be.

Thank you very much! It's exactly the same rationale I used to design mine! Everything is a part of the bigger core object. The object is instantiated using a global systemwide lock so no chance of double instantiation can happen. It's always good to know I'm kinda on a good path.

I begin being positive perhaps there's no real problem after all. Besides naming. I'd still want some suggestions for the WaveSomething... perhaps WavePooler would do ?_?

WM1) Can you run two windows? WM1A) If not, why not? There is no physical reason why you cannot run multiple windows on the screen; that is exactly what it is made for. WM2) What about split screen within a single window? WM2A) If not, why not? WM2B) Your display area is normalized to a rectangle, why should it matter if the rectangle is only a portion of the physical screen? WM2C) Why should you be restricted to a single rectangle instead of two or three or nine? The restriction is artificial and probably unnecessary.
...
WM3) One of the best in-house engines I worked with had two views on screen... Any fundamatal reasons your game engine cannot do that? Why not?


WM1) No. The system was able to do that in very old versions.
WM1A) It just collected dust with no apparent benefit. It was originally implemented as it was deemed useful WRT previous experience - it was a different field. As a side question - how's going with sharing renderers across multiple windows? As far as I recall direct3D9 is a bit quirky on that, for GL I am not sure but I think not (it's bound to the Device Context which is a per-window property). If this involves creating multiple renderers... that's going to be a big no. I think your statement is a generalization a bit too broad. I don't recall a single PS3 game I've played showing multiple windows per screen. I have also seen some games not only assuming a single window but also allowing a single resolution - I don't see this being a problem for me in the real world for the next years.
WM2) Not currently supported. Plan is to just expose an additional renderer control (it will likely be script-driven).
WM2A) Not necessary now.
WM2B) I disagree with this. What is this normalized rectangle? How do you deal with it on 4:3? What on 16:10? What about stretching. No way. I work in physical inches, or perhaps pixels. If the user (script) wants to cut it in ratios, that's his/her choice. Design units are in pixels at 96dpi. The alternative, offset-scale normalized coords seems unnecessarily convoluted. Perhaps it's just me, but I didn't like the normalized coord approach at all in the past. I couldn't stand the stretching.
WM2C)Of course when it is scripted there will be N (I don't care). This day is not now. I disagree with your statement; I don't quite see the connection with the original problem.
WM3) Yes, each day got only 24 hours, priorities and trade-offs will have to be made; I think that is a major fundamental reason.

Can you have one game instance run multiple simulations internally...The simulator has clocks. The simulator has resource loaders. The simulator has everything neccesary to run the game. The simulator has an interface for display, but does not have a view (that is secondary to running the game).

Yes, totally awesome and... what's the difference between my system and yours? And what's the deal of running it multiple times in the same process? Why not just ran them sequentially... in parallel chunks? It sounds like write about "accuracy" as a mathematician might write about: I don't see the point of having more than adeguate accuracy. I understand nothing of what you're writing about. Please try to be more concise and propose real world examples (excuse me, but I am not well aware of what you do).
I don't want to write an "engine"... I want to get the job done. I will implement "nicely" whatever it takes to get the job done. Everything else will wait. Long term investments will be considered... in a long term perspective. OP is NOT about a long term perspective it is about a simple solution to a problem I have. Now.

#9 Codarki   Members   -  Reputation: 462

Like
0Likes
Like

Posted 25 October 2011 - 04:16 AM

Pearl number 1: ImageManager. This resisted because I'm lazy and I don't want to check out the file again. I suppose I might change it tomorrow to ImageLoader. This is not so bad after all. Only thing it does: reference-count image loads.

Sounds like an ImageCache.

I'll suggest to extract the construction of resources away from these classes. Then you have ImageCollection / ImageCache, BasicImageLoader and AdvancedImageLoader. Or maybe just free functions for construction of resources. Or, If the construction is complex process, you could try builder pattern where you can pass short lived builder objects around that can retain the state until the result is finished. These builders can even be polymorphic.

A lot of times people subclass just to be able to add different constructor, while the public interface of the end result remains the same.

#10 Krohm   Crossbones+   -  Reputation: 3509

Like
0Likes
Like

Posted 28 October 2011 - 12:52 AM

The actual construction is in a derived class.
Nonetheless, I might want to figure out something else in the future, I will think at this.

#11 Red Ant   Members   -  Reputation: 463

Like
2Likes
Like

Posted 28 October 2011 - 03:26 AM

When I read the title of this thread a jolt of enthusiastic excitement went through me ... until I realized that you're talking about a programming issue.

#12 patrrr   Members   -  Reputation: 1113

Like
0Likes
Like

Posted 28 October 2011 - 04:20 AM

Singletons are to be used for a case where there can only be one instance of the class without causing erroneous or incorrect behaviour. It's not a catch-em-all insurance policy against having > 1 instances. Sure, it can be used that way, if you really want -- just like globals can be used for things that aren't truly needed globally.

It's just not a terrific idea to do so. Especially when it comes down to: "I think there should never be need for two instances of this."


Exactly, and if the implementation of a class relies on side-effects or some kind of global state which makes it not safe to instantiate more than once, why not make it a singleton? Then you're at least honest with your limitations. Note: I'm not saying you should make such a class.


The object is instantiated using a global systemwide lock so no chance of double instantiation can happen.


So this means that for all intents and purposes, it is a singleton, but enforced externally? I might even argue that is worse.

Singletons are crappy, but sometimes they are needed, and sometimes they minimize incorrect usage of a class. Substituting a singleton with something else that enforces oneness just ignores the underlying issue.

#13 frob   Moderators   -  Reputation: 26635

Like
1Likes
Like

Posted 28 October 2011 - 02:27 PM

The object is instantiated using a global systemwide lock so no chance of double instantiation can happen.

So this means that for all intents and purposes, it is a singleton, but enforced externally? I might even argue that is worse.Singletons are crappy, but sometimes they are needed, and sometimes they minimize incorrect usage of a class. Substituting a singleton with something else that enforces oneness just ignores the underlying issue.

Not at all.

There are many system-wide unique resources. There are global mutexes and semaphores. There are individually named files on the file system. There is volatile information about larger systems such as machine state.

Locally constrained uniqueness is often enough for small programs that need it, but they are not everything. At the smallest end of the scale you have interlocked memory and IPC communication methods. Externally contstrained uniqueness is absolutely critically on larger systems that span networks, such as resources controlled by remote databases.

Just consider the classic problems of simultaneous updates, such as the computer science problem with two travel agents booking reservations simultaneously, have need of strong external uniqueness constraints.

There are very solid, established, and proven uses for such things. Enforcing uniqueness locally and globally is an extremely important design requirement for many programming problems.


The problem is not simply using it; there are many times when it is not just a good design but instead absolutely essential to proper function. The problem comes from using it unnecessarily.


The real questions to ask are:
(1) Does the problem require enforced uniqueness?
(2) If it is required, does the proposed solution adequately enforce it?

Very few problems require it.

Most of the time it is a non-issue. Don't write code that depends on uniqueness. Data driven designs, component based systems, and thinking with reuse in mind solve this in most cases.

But if it is needed, it is absolutely essential. For every problem you need to discover the necessary scope.

For example, your enforcement may be a single block of shared memory. It may be a single instance of a class within a single app. It may be a single instance of a service on a single OS instance. It may be a single item on a physical machine regardless of virtualization. It may be a mandatory pessimistic lock on a database record that needs to propagate across a server cluster.

Don't use it when it isn't required. But if a system does require it you better know the available tools so you choose the right one for the job.

Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#14 L. Spiro   Crossbones+   -  Reputation: 17284

Like
0Likes
Like

Posted 01 November 2011 - 11:56 PM


So let’s assume singletons are not welcome, and you are wondering what you can do to make sure that no more than 1 instance of a class exists.


If you want to make sure that no more than 1 instance of a class exists, why not use a singleton? That's what they're meant for, after all. If singletons are "not welcome", but it's OK having classes that can only function properly when there's max one instance, then that's just hypocrisy.

I am a little late but-

No, I want CGame be instantiated only once, not to be instantiated only once and be global in scope.

My engine will pass the game pointer to the 3 main objects that need it: Scene Manager, State Manager, and States themselves.

Access to the CGame class is restricted to these objects because these 3 objects are the highest-level objects under the CGame class, and they are the only ones that could possibly need to know about all the different systems running in the game (all of which can be accessed through CGame).


There is a design problem with using a singleton, but also one less subjective. If my engine relied on a singleton for the main game class, how would the users of my engine inherit from my CGame and make an instance of their own "CMyGame"?
If the user wants to make a singleton out of his or her own CMyGame, or just make an instance on the stack (preferred), that is his or her business. My engine makes no assumptions as to how the game class is stored; when something needs it it is passed as a parameter.

And the design issue is: How do you control which classes/modules have access to the CGame pointer?
So, you made this nifty system that uses singletons for the CGame. From the CGame you can access all other managers.
Now you have a small bit that just wants a sound manager. Well now he has to include the CGame file, and with that he must now link to the graphics library, the physics library, scene manager, etc.

Trying to avoid this by using a bunch of different singletons does not really improve your design. You still haven't restricted access from things that should not have access, so when your programmers get lazy they will just #include "SoundManSingleton.h" instead of just the components of the sound module they need. Inevitably, singletons lead to unnecessary relationships between classes.



I will take a system of constraint any day. I want to think logically about what every system needs and manually give it (and only it) to them. That is organization.


L. Spiro

#15 way2lazy2care   Members   -  Reputation: 782

Like
0Likes
Like

Posted 02 November 2011 - 08:54 AM

Exactly, and if the implementation of a class relies on side-effects or some kind of global state which makes it not safe to instantiate more than once, why not make it a singleton? Then you're at least honest with your limitations. Note: I'm not saying you should make such a class.


The singleton design pattern implies more than just that there be only one instance of the object.

http://blogs.msdn.co.../25/140827.aspx

Also to be noted, it should be the decision of the program, not the class to limit the creation of itself. If you want to limit the creation of certain objects you should make a factory class to handle that, not a singleton.

Also, I seriously question a single class that is not safe to instantiate more than once for anything important. It feels like a bit of a code smell. I could see it being useful in some cases, but if it is something that's coming up repeatedly I would be wary of it. See frob's first post for examples.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS