views:

356

answers:

5

I was thinking of adding some Achievements to our internal bug-tracking and time logging system. It's connected to an SQL Server back-end.

At first I thought that the system could be run on the database, using triggers to, for example, know when:

  • you've logged 1000 hours
  • created 1000 tickets
  • closed your own ticket
  • worked on a ticket that has been not touched in a while.
  • etc (you know - database-ish things)

But then I realized that I would also want purely front-end achivements

  • used the advanced search abiltiy
  • sorted by a column
  • reset settings to default
  • searched 500 times

It seems like the logic of every achievement must be hand coded. Could anyone imagine an some sort of Achievements Rules Engine, that you for example create scripts for?

And how to store them? If the achievement is:

  • change column sort order 50 times in one session

that would imply that every time they sort a listview column it updates the database.

Any thoughts on this Win32 application design problem? I don't think that the Gang of Four have an Achievements design pattern.


Note: It's a Win32 client application, not a web-site.


i definetly like the idea of an eventing system. Various actions the user takes can raise events through a single eventing object:

protected void TimeEntriesListView_ColumnSort(object sender, EventArgs e)
{
    _globalListener.RaiseEvent(EventType.ListViewColumnSort, sender, e);
}

protected void TimeEntriesListView_ColumnDrag(object sender, EventArgs e)
{
    _globalListener.RaiseEvent(EventType.ListViewColumnDrag, sender, e);
}

That object can then have logic added to it to decide which events it wants to count. But more reasonably, various event listeners can attached to the central event listener, and have their custom achievement logic.

+1  A: 

The backend achievements should be simple - they seem to be based on already tracked items. The front end, as you correctly stated, will require more tracking. One way you might want to do this is implement an analytics engine for your front end site.

Piwik at http://www.piwik.org might help here - it is a google analytics clone, that you host yourself. The idea would be to use it's logging capabilities to track when an achievement has been completed.

As for some form of scripting of the rules, you will always have to hand code them - you can perhaps make it simpler though, by creating your own small scripting engine, or implementing a custom Lua set.

Lokkju
It's not a web-site, but a full Win32 client application
Ian Boyd
+5  A: 

The trick isn't the coding of the rules, really, those are straightforward, and can perhaps be simple expressions (number_of_bugs > 1000).

The trick is accumulating the statistics. You should look at a form of Event Stream Processing to record your achievements. For example, you don't really want to implement the "1000 bugs" achievement with "select count(*) from bugs where user= :user" all the time (you could do it this way, but arguably shouldn't). Rather you should get an event every time they post a bug, and you achievement system records "found another bug". Then the rule can check the "number_of_bugs > 1000".

Obviously you may need to "prime the pump" so to speak, setting the number_of_bugs to the current number in the DB when you start the achievement system up.

But the goal is to keep the actual event processing light weight, so let it track the events as they go by with all of the events running on a common, internal pipe or bus.

A scripting language is a good idea as well, as they can easily evaluate both expressions and more complicated logic. "number_of_bugs > 1000" is a perfectly valid Javascript program for example. The game is just getting the environment set up.

You can also store the scripts in the DB and make an "achievement" editor to add them on the fly if you like, assuming you're capturing all of the relevant events.

Will Hartung
i definetly like the idea of an eventing system.
Ian Boyd
+1  A: 

How about storing the sql query associated with the achievement in the database itself, so adding a new achievement would only involve adding the name and the sql query for it.

for e.g.

you've logged 1000 hours - "select case sum(hours) > 1000 then 'true' else ' false' end from user where user_id = ?"

The UI based achievements would have to have the data stored in the db as well because you may use the same data for other achievements going forward.

Sijin
+3  A: 

I am also trying to figure out how to build an achievements rules engine.

I checked around rules engines and what are the basics of it. There is a good summary of that in wikipedia

Basically, you either have foward chaining when you, for example, check availability for something; otherwise, you use Event Condition Action rules. Its the latest that caught my attention.

So you could predefine a set of triggered events. In the engine you can define what are the checked conditions who are based on available metrics, and specify the association achievement.

This way seems more flexible, but you have to define the events, possible condition checks and metrics.

For example, you would have various events like TicketCreated triggered in the code.

In the rule engine you could have something like

Event: TicketCreated
Condition: UserTicketCount >= 1000
Achivement: "Created 1000 tickets"

or for "reset settings to default"

Event: SettingsChanged
Condition: Settings = DEFAULT
Achievement: "Reset to Default"

I haven't tried it yet, but I'm going to pretty soon. It's mostly theoric for now.

ceetheman
+1  A: 

I think one table to hold each event that you want to track. Such as "Performed a search". Then each achievement could have an SQL associated with it.

You could then build one trigger, on the Event table, which would compare the achievements that apply to that event, and add the achievement to the Achivement table.

Here are the quickie table designs:

EventItems:
UserId, EventName, DateOccured, AnyOtherInfo

AchievementQualifiers: 
Achievement Name, AchievementCheckSQL, EventsThisAppliesTo 
(Normalize this, if multiple events apply)

In you System, weather its web or win32, you simply insert into the EventItems table whenever the user does some event that you want to track. You could make one class to handle this. For purely DB type events, such as "Item Posted" or "Comment Posted" you could do this with a trigger instead.

Then, in the triggers on EventItems, for each AchievementQualifer that has that EventThisAppliesTo, run the SQL check, and update an UserAchievement table if it's true and hasn't been awarded yet.

Excuse my spelling, as I'm typing this while sitting in a brew pub.

Bo Flexson
i liked this idea at first. But some achievements are based on UI interactions (e.g. column sorting, column resized, column re-ordering) are things in a graphical app that i wouldn't want to slow down the UI with a database hit every time. It would be even worse on the web, with Javascript making changes to a column. If done with a database event every time, there would be a lot of events to write, making it very 'chatty'. Bah, it's a conundrum.
Ian Boyd
At some point i have to accept database access for UI actions. How do i know that you've resized columns 500 times until i store the running counter somewhere...
Ian Boyd
...which reminds me...store as counted events, not detail items.
Ian Boyd
You could also have a counter record, instead of storing the details on every action (such as a column sort). I think with this design you could do both. You could add a counter record for those types, and have details for items you are already storing.
Bo Flexson