Comments on: Lessons Learned While Implementing an Achievement System Yes you're right. I used plain old ints on another projects since then. They worked perfectly. Yes you’re right. I used plain old ints on another projects since then. They worked perfectly.

]]>
By: Franz Taptanium/2011/05/11/lessons-learned-achivement-system/#comment-3972 Franz Taptanium Fri, 13 May 2011 10:06:05 +0000 hence the requirement that AchievementData be Plain Old Data. no constructor, no destructor, just data. initialization would happen via an explicit InitAcheivements() function call sometime during startup and you're done. hence the requirement that AchievementData be Plain Old Data. no constructor, no destructor, just data. initialization would happen via an explicit InitAcheivements() function call sometime during startup and you’re done.

]]>
By: Richard Fine/2011/05/11/lessons-learned-achivement-system/#comment-3961 Richard Fine Thu, 12 May 2011 21:34:51 +0000 the ctor of static global's are called outside of main. this can be the problems: http://blog.barthe.ph/2009/07/30/no-stdlib-in-dllmai/ ask jason gregory, he will say you the same(when he has the same opinion like his book, page 198 :D), singletons should not be created as statics. No ctor order, no dtor order and so on... Maybe there should be a blogpost for the singleton topic...? the ctor of static global’s are called outside of main.
this can be the problems:
AchievementData is local to the file (file-scope), hence can never be used by another user, unless she puts the code itself in the achievements.cpp file. In other words, it is more private than a singleton. The <strong>only</strong> interface available for external use are those functions exported in the header file. I don't understand the comment about using AchievementData on the stack. It is clearly allocated in the static segment, and noone can get hold of it elsewhere since it is static (visible for the compilation unit only). With respect to allocation, I don't see a benefit of dynamically allocating this data. Keeping it in the heap or in a static segment should make no difference. It is only one of these. I don't think we discussed thread-safety here, but if it ever became a problem, notice that we can deal with that easily since there is a very small interface exported. AchievementData is local to the file (file-scope), hence can never be used by another user, unless she puts the code itself in the achievements.cpp file. In other words, it is more private than a singleton. The only interface available for external use are those functions exported in the header file.

I don’t understand the comment about using AchievementData on the stack. It is clearly allocated in the static segment, and noone can get hold of it elsewhere since it is static (visible for the compilation unit only).

With respect to allocation, I don’t see a benefit of dynamically allocating this data. Keeping it in the heap or in a static segment should make no difference. It is only one of these.

I don’t think we discussed thread-safety here, but if it ever became a problem, notice that we can deal with that easily since there is a very small interface exported.

]]>
By: Ed Bartley/2011/05/11/lessons-learned-achivement-system/#comment-3950 Ed Bartley Thu, 12 May 2011 20:00:07 +0000 assuming AchievementData is POD i don't see anything wrong with this code. making the code more complex because "what happens when someday..." doesn't seem like a very productive use of time. how about minimal complexity to meet the needs of the code TODAY and if those requirements change THEN you can worry about these things? assuming AchievementData is POD i don’t see anything wrong with this code. making the code more complex because “what happens when someday…” doesn’t seem like a very productive use of time. how about minimal complexity to meet the needs of the code TODAY and if those requirements change THEN you can worry about these things?

]]>
By: TomP/2011/05/11/lessons-learned-achivement-system/#comment-3907 TomP Thu, 12 May 2011 02:26:06 +0000 You actually mentioned in the article that you considered whether senders would use known enum types for messages. Why'd you decide not to, in the end? You actually mentioned in the article that you considered whether senders would use known enum types for messages. Why’d you decide not to, in the end?

]]>
By: Ed Bartley/2011/05/11/lessons-learned-achivement-system/#comment-3900 Ed Bartley Wed, 11 May 2011 21:58:15 +0000 :)

]]>
By: AM/2011/05/11/lessons-learned-achivement-system/#comment-3891 AM Wed, 11 May 2011 18:56:11 +0000 I remember a tweet by Carmack once, something along the lines of "Sometimes the elegant method is a function. Not a routine, not a method, not a callback. Just a function." I really think that applies here. Too much C++ can keep things from being flat and modular, and while I will be the first to extol the benefits of it for something like infrequently-accessed smart pointers or threadpool classes that need to be easy to use...or templates for something like GLUCAT or related math libraries, I think this sort of system is better off using a plain global. And a lot of helpful, well-written documentation. I remember a tweet by Carmack once, something along the lines of “Sometimes the elegant method is a function. Not a routine, not a method, not a callback. Just a function.” I really think that applies here. Too much C++ can keep things from being flat and modular, and while I will be the first to extol the benefits of it for something like infrequently-accessed smart pointers or threadpool classes that need to be easy to use…or templates for something like GLUCAT or related math libraries, I think this sort of system is better off using a plain global. And a lot of helpful, well-written documentation.

]]>
By: Pal-Kristian Engstad/2011/05/11/lessons-learned-achivement-system/#comment-3888 Pal-Kristian Engstad Wed, 11 May 2011 17:27:21 +0000 Jare: I agree totally. <code>void TriggerAchievement(const char *achievementName);</code> is all I need in a matter of achievements (and I use both local and 3rd party achievements). Jare: I agree totally.

void TriggerAchievement(const char *achievementName);

is all I need in a matter of achievements (and I use both local and 3rd party achievements).

]]>
By: Ed Bartley/2011/05/11/lessons-learned-achivement-system/#comment-3883 Ed Bartley Wed, 11 May 2011 15:24:02 +0000 Yeah, it would have been easier to implement an abstract achievement class from the game engine core and then just register the game specific achievement class with the game engine. Then almost all game specific classes would have visibility as you mentioned. Lesson learned: Don't go with the first solution that seems to more-or-less fit the problem. Yeah, it would have been easier to implement an abstract achievement class from the game engine core and then just register the game specific achievement class with the game engine. Then almost all game specific classes would have visibility as you mentioned.

Lesson learned: Don’t go with the first solution that seems to more-or-less fit the problem.

]]>
By: Ed Bartley/2011/05/11/lessons-learned-achivement-system/#comment-3881 Ed Bartley Wed, 11 May 2011 14:44:01 +0000 Thanks for the feedback Wilhansen. I discovered boost::signals2 some years after writing this code. I haven't had an opportunity to use them yet, but I'll definitely give them a try next time. :) Thanks for the feedback Wilhansen. I discovered boost::signals2 some years after writing this code. I haven’t had an opportunity to use them yet, but I’ll definitely give them a try next time. :)

]]>
By: Ed Bartley/2011/05/11/lessons-learned-achivement-system/#comment-3879 Ed Bartley Wed, 11 May 2011 14:40:06 +0000 So why is this many-to-many? It seems like many-to-one. In which case, a global/singleton would have done the job. So why is this many-to-many? It seems like many-to-one. In which case, a global/singleton would have done the job.

]]>
By: Richard Fine/2011/05/11/lessons-learned-achivement-system/#comment-3877 Richard Fine Wed, 11 May 2011 11:54:48 +0000 Removing the left side of the function (in other words, making it global) helps too. :P But I definitely agree about keeping it simple. Such "elegant" systems are just making programmers write lots of code that does nothing more than look complex. It's like making cops wear 17th century clothing when they're in pursuit... :D Removing the left side of the function (in other words, making it global) helps too. :P

But I definitely agree about keeping it simple. Such “elegant” systems are just making programmers write lots of code that does nothing more than look complex. It’s like making cops wear 17th century clothing when they’re in pursuit… :D

]]>
By: Helmut Duregger/2011/05/11/lessons-learned-achivement-system/#comment-3871 Helmut Duregger Wed, 11 May 2011 07:54:02 +0000 observer pattern
. There is many more useful patterns out there.

Not sure if it applies here though. Jare’s approach seems much more straight forward for this. For collecting performance or other metrics, what Slagh suggests, seems good.

Of course it all depends on your needs and how many listeners/observers and sources you have.

]]> By: Jare/2011/05/11/lessons-learned-achivement-system/#comment-3870 Jare Wed, 11 May 2011 07:22:53 +0000 I'm not fond of callbacks because they destroy code and data flow. Multithreading gets interesting too. There's cache misses starting the code for each message handler, reading the working data for the new function (assuming fairly that it's some other listening system), and all the same going back again after the message is processed. Things might be a bit smoother if you dropped your message/event in lists by message and/or listener category somewhere and processed them in bulk at some later stage. I’m not fond of callbacks because they destroy code and data flow. Multithreading gets interesting too. There’s cache misses starting the code for each message handler, reading the working data for the new function (assuming fairly that it’s some other listening system), and all the same going back again after the message is processed.

Things might be a bit smoother if you dropped your message/event in lists by message and/or listener category somewhere and processed them in bulk at some later stage.

]]>
By: Wilhansen Li/2011/05/11/lessons-learned-achivement-system/#comment-3859 Wilhansen Li Wed, 11 May 2011 05:54:19 +0000 I quite like message centers like that. I saw a blog on a Unity message center pack that looked quite good, though I've lost the links. I'd try to make the message center take "structured" messages rather than just strings though, so you can add some context to the message, like who did the achievement, etc. I've generally implemented achievement systems as simple singleton managers, though a message center is a nice way of decoupling everything, as well as allowing other systems, like statistics trackers, to listen in on the events... I quite like message centers like that. I saw a blog on a Unity message center pack that looked quite good, though I’ve lost the links.

I’d try to make the message center take “structured” messages rather than just strings though, so you can add some context to the message, like who did the achievement, etc.

I’ve generally implemented achievement systems as simple singleton managers, though a message center is a nice way of decoupling everything, as well as allowing other systems, like statistics trackers, to listen in on the events…

]]>