Programming Unlockable Achievements

So you wrote this game, but would now like to step up? Unlockable achievements is an aspect that enhances your game and it’s fun and interesting to program.

Minecraft Achievement
A simple Minecraft Achievement

The Concept

Let’s elaborate on the actual purpose and the concept of unlockable achievements. Basically you could consider an Achievement to be a milestone. It is a goal your end user achieves, literally. It is up to you to determine these milestones.

Let’s take Minecraft‘s ‘Taking Inventory’ achievement as an example. The achievement is unlocked at the moment the inventory is opened for the first time. This example is a single Achievement, meaning it has no predecessors or successors. Possibly you’d want to create an achievement that could only be unlocked when this one was unlocked first. You may even want to have a set of achievements unlocked before achieving a parent achievement.

The previous example was obviously very simplistic. There was one task, one goal that lead to the unlocking of the achievement. Different achievements might consist of multiple milestones to reach before unlock. Or maybe you’d want specific actions to take place in order to achieve the achievement.

Achievements Everywhere

Gaming companies, publishers and console builders all make use of achievements. Think about the trophies you can earn on PlayStation and XBox consoles. Think about achievements that you can collect on the Steam platform. And don’t forget the achievements on mobile devices in Google Play Games (Android) and Game Center (iOS). There are so many possibilities, so many things you can do with your in-game achievements. You can go beyond an implementation in your game itself.

Implementation

Let’s put things in practice by covering a possible implementation approach in Java.

You want to get things started by defining an interface:

public interface Achievable {
    void achieve();
}

Now we’re ready to define an Achievement class. You can make it Observable as we did in the following example. That way registered observers can get notified at the moment the Achievement is unlocked.

public class Achievement extends Observable implements Achievable {

    private String name, description;
    private List<AchievementProperty> propertyList;
    private boolean unlocked;

    /**
     * Class constructor specifying name, description and properties to be activated.
     *
     * @param name        the untranslated name of the achievement
     * @param description the untranslated description of the achievement
     * @param properties  the properties related to the achievement
     */
    public Achievement(String name, String description, List<AchievementProperty> properties) {
        this.name = name;
        this.description = description;
        this.propertyList = properties;
        this.unlocked = false;
    }

    /**
     * Unlocks this achievement and notifies its' observers.
     */
    @Override
    public void achieve() {
        if (!unlocked) {
            boolean allActive = true;
            for (AchievementProperty property : propertyList) {
                if (!property.isActive()) {
                    allActive = false;
                    break;
                }
            }
            if (allActive) {
                this.unlocked = true;
                setChanged();
                notifyObservers();
            }
    }
//Getters, setters and toString omitted...
}

As you can see in the above code, the achievement contains a list of AchievementProperty. These are properties that need to be active when the achievement is unlocked.

Here’s how the AchievementProperty class may look like:

public class AchievementProperty {

    private String name;
    private int value;
    private String activation;
    private int activationValue;
    private int initialValue;
    private String tag;

    /**
     * Class constructor specifying name, activation, activation value and initial value.
     *
     * @param name            the untranslated name of the property
     * @param activation      the activation method of the property
     * @param activationValue the activation value of the property
     * @param initialValue    the initial value of the property
     */
    public AchievementProperty(String name, String activation, int activationValue, int initialValue) {
        this.name = name;
        this.activation = activation;
        this.activationValue = activationValue;
        this.initialValue = initialValue;
    }

    /**
     * Class constructor specifying name, activation, activation value, initial value and tag.
     *
     * @param name            the untranslated name of the property
     * @param activation      the activation method of the property
     * @param activationValue the activation value of the property
     * @param initialValue    the initial value of the property
     * @param tag             the tag of the property
     */
    public AchievementProperty(String name, String activation, int activationValue, int initialValue, String tag) {
        this.name = name;
        this.activation = activation;
        this.activationValue = activationValue;
        this.initialValue = initialValue;
        this.tag = tag;
    }

    /**
     * Returns true when this property is active, false if otherwise.
     *
     * @return true when this property is active, false if otherwise
     */
    public boolean isActive() {
        boolean flag = false;

        switch (activation) {
            case Achiever.ACTIVE_IF_GREATER_THAN:
                flag = value > activationValue;
                break;
            case Achiever.ACTIVE_IF_LESS_THAN:
                flag = value < activationValue;
                break;
            case Achiever.ACTIVE_IF_EQUALS_TO:
                flag = value == activationValue;
        }

        return flag;
    }

    /**
     * Resets this property's current value.
     */
    public void reset() {
        this.value = initialValue;
    }

Now it’s up to you to get all that linked up by creating the ‘Achiever’ class. I’ll leave that as an exercise to the reader. Here’s a bit more context to get you going:

  1. Make use of a HashMap to keep AchievementProperty instances;
  2. Make use of a HashMap to keep Achievement instances;
  3. Provide a ‘defineProperty’ method that creates and returns a new AchievementProperty based on specified parameters. If the property is not yet listed in the HashMap, put it in there;
  4. Provide a ‘defineAchievement’ method that creates and returns a new Achievement based on specified parameters (do not forget its’ related Achievementproperty/AchievementProperties!). If the achievement is not yet listed in the HashMap, put in in there;
  5. Add a method that will achieve all eligible achievements (don’t forget checks on the related AchievementProperty/AchievementProperties;
  6. Add methods to add/set a value to properties, or even to reset property values.

At this point you can create your new achievements and their respective related property/properties.

On the moment a property needs to get an update, you call the ‘addValue’ method from step 6 and you call the ‘checkAchievements’ method from step 5. This way your achievements can get unlocked at the proper time.

Monkey Testing Web Apps Using Gremlins.js

Gremlins.js is a monkey testing library written in JavaScript. It is incredibly lightweight and perfect for your quick test runs. Find the repository on GitHub.

What it does

To be honest, I couldn’t describe the purpose of the library any better than they do themselves:

Use it to check the robustness of web applications by unleashing a horde of undisciplined gremlins.

That’s a nice piece of imagery they use there, but you’ll notice how accurate it is once you get your hands on the actual code.

Feel free to compare a ‘gremlin’ with a monkey in the monkey testing context. The gremlin represents a user going absolutely nuts on your web application. I always imagine a monkey sitting behind a computer, bashing on all possible keys of the keyboard in front. Include all sort of clicking, scrolling and other mouse actions in your picture.

Gremlins performing visible click and scroll actions on a website.
Gremlins performing visible click and scroll actions on a website.

Imagine what such a user might have as impact on any website. Will such a user be able to crash the system our pull off a bunch of unexpected things? With gremlins.js you can now be sure of what is possible.

Unleash the Horde

Getting started is quick and straight-forward. In no time you can have multiple gremlin species deployed on your web page. The developers have been so kind to provide us with some examples.

To get you started in Google Chrome, open up your website under test and hit F12. This will open the Developer Tools. In the Developer Tools, open up the tab ‘Sources’ and navigate to ‘Snippets’. Right click and select ‘New’. A blank snippet will be created. In this snippet, copy the contents of gremlins.min.js, this is a mandatory step.

Prepare 2 more blank snippets. In order to have some basic functions on top of gremlins, paste the content of this PasteBin paste in a snippet. For the last snippet you can use the content of another PasteBin paste. This last snippet will prepare all you need to start spamming your application.

Initialization of a gremlins horde.
Initialization of a gremlins horde.

Species, are a thing in gremlins.js. Each gremlin species has some responsibility, such as clicking or scrolling. For every action you aim to test you should create a species and add it to the horde you are going to release later on.

Over to the real action then! From the Developer Tools run the first snippet (the gremlins.min.js script). Now do the same thing for the two other scripts, make sure you get the order right (gremlins, functions, launch). From the moment you run the last script, the gremlins horde will be released onto your web app to cause absolute mayhem (let’s hope they don’t).

Now customization is up to you. I have also created a different script that does exactly the same that we just did, except that it hides all gremlins’ actions. Find it here.

I thought I’d share this little library, since it is a unique little piece of software that is very easy to setup and remarkable in the way you set it up.

About the Bromine Project

Since my experience with Selenium is growing I become to understand it better every day. At first I was amazed about its possibilities. You can do a lot with Selenium WebDriver, but soon enough I came to realize it’s missing a few aspects. That’s how Bromine evolved from idea to project.

Filling in the Gaps

The Bromine project’s aim is to fill in the gaps in the default Selenium WebDriver Livery for Java. In stead of using Selenium, use Bromine that will on its turn use Selenium for you, while still leaving you enough means of customizing the WebDriver functionality.

Screenshots

A good example of a feature I was really missing in Selenium was a descent way of taking screenshots. The method getScreenshotAs(OutputType.FILE); just simply didn’t quit fulfill my needs (and those were from an automatic testing’s perspective). What I specifically wanted to be able to take a screenshot of the current browser instance any time I’d desire, but more importantly, every time a unit test fails.

An example screenshot taken by a Bromine command.
An example screenshot taken by a Bromine command.

In Bromine, a simple JUnit rule can take care of just that. Add it to your test class as follows:

@Rule
public ScreenShotOnFailure failure = new ScreenShotOnFailure("./screenshots/");

Statistics

When I use Selenium in a test framework, at some point, I might become interested in several statistics. Of course I do not intend to re-invent the wheel. I respect the current web analytics standard of today, Google Analytics, and I believe it to cover most needs one can have regarding statistics and analysis of a website.

What Google Analytics doesn’t provide you is statistics of events on your web page right in your test framework.

Why would that even be useful? Well, if you’re creating an automated test framework you are trying to ensure a qualitative final product for your users to interact with. Wouldn’t you want to know how many clicks one has to perform before reaching a particular page? Aren’t you interested in how many times form fields have to be filled in before a desired action occurs? Those are examples of what Bromine would like to cover.

As of version 0.2-alpha, a basic implementation of this is in place, ready for you to extend at will. I made sure I provided at least a very minimum, being tracking of left mouse button clicks, double clicks and the amount of times keys are entered.

Since I can image one might find the need to create their own tracking means, I ensured the system works with plugins (StatsPlugin) that can be registered and enabled any time.

Bringing SUT Structure

Selenium merely provides the ability to browse through websites, while what many might want to do would be structuring their System Under Test (SUT) inside their framework. It is a good practice to do so, since you might want to reuse pages and features that are used across the site multiple times.

Bromine provides a base to register pages (Page) and their respective sections (section) to a globally accessible collection (Pages). The easiest way to implement your application structure would be to assign a specific package in your project to contain classes extending the Page class. If you make use of the default no-parameter constructor, you won’t even have to create new instances of your pages. Just make sure to call registerAllPagesFromPackage(String pack) from the Pages class to register all your predefined pages to the collection.

Work in Progress

Bromine is currently in a very early stage. Additional extensions to Selenium are more than likely to appear, as well as probable breaking changes in the future. Needless to say that Bromine has to evolve as does Selenium.

Personally, I attempt to use the framework in multiple different projects. That way I can evaluate how useful it is and how well it works. Most useful features at the moment (for me personnally) are the screenshots and the structuring of pages from the SUT.

I’m happy to share the source on GitHub. I made it to be open source since I will always be open to feedback and improvement suggestions.

Why Blocking Root Users Is a Bridge Too Far

Rooting your Android phone, shady business for some, pure satisfaction for control freaks and customization lovers. Among these root access privileged users there are obviously a bunch of cheaters and hackers we should be aware of, but there are also a lot of legit users.

 Disputed Pokémon Go Update

Niantic‘s immensely popular game, Pokémon Go recently got an update that blocks devices that are granted root access. From now on, users with elevated rights are not allowed to play the game anymore.

pokemon goDefinite and potential cheaters are avoided from disrupting the intended gameplay, which obviously is a good thing. The downside though, is that all the legitimate players that happen to have rooted their device are now duped.

The result of those duped players not having access to their beloved game must be rather significant. The sales coming from in-app purchases will be directly impacted as less users can buy in-game goodies. The somewhat more indirect impact would concise of negative 1-star ratings on the Play Store. Fora get filled with negative user feedback, people will start discourage others playing the game.

On another note, it is a bit of a strange decision on Niantic’s part, considering they have already built in descent cheating protection. That would be an expertise learned from their previous game, Ingress, which shows a lot of similarities to Pokémon Go (as it is also a positioning based game). People trying to spoof their GPS location are likely to be banned, if they even managed to properly spoof the device’s location. That is a good way to remove the unwanted players from using the app.

Limiting the User Beyond 1 App

If one application blocks the rooted user, they are basically discouraged to continue using their root-required apps and features. A company should not decide for it’s users whether or not they can use rooted Android devices.

Imagine what elevated access can do. It allows one to completely customize their Android livery. Tiresome adds can be removed using ad-blockers, CPU usage and performance can be tweaked. Want to open your favorite music app as you plug headphones in? Guess what you need, root access. There are plenty more reasons why one would want to root his/her device.

Hacky Work-Arounds

What would you expect, root guru’s to stop finding tricky solutions to bypass this kind of issue? There are already quite a few apps that can hide your Su binary. Those however, don’t always do the trick.

Some people like to use something like the Xposed Framework to ‘cloack’ root from specific apps. Others like to go over using the game-changing Magisk.

 

The Importance About Globalization

When you are working on any kind of project, you should globalize it. Except if you have a very specific target audience of course. The importance of globalization in general is enormous.

globe

More than Localization

When we are talking about globalization we are talking about much more than simply localization (which would mainly consist of translating your program). You could say that globalizing your application would mean to make it accessible to users all around the world.

Does your program come with any kind of currency handling? Guess what, you should add support for foreign currencies. Another marvelous example: date formatting! Worldwide there are quite a few different date representations. Make sure you display dates in a matter that your end user is used to.

Try to view the big picture. Apply country-specific standards (representation of VAT numbers, bank account numbers and specifications, address (and zip code) notations, …) as often as possible. But be aware of one downside: data conversion might be needed in some cases. Make sure you are prepared for that (foresee some good old converters).

Increased Target Audience

Imagine what impact a proper globalization implementation might mean for your target audience. Guess what, it will vastly increase and thus result in more sales. Now go improve your conversion rates!

Is it Worth the Effort?

I can already picture programmers and project leads thinking why they would even bother to put in the extra effort to globalize their project(s). Globalizing does indeed take up some time. In fact, you could say most of the time would have to do with the initial setup. Once you get it going, you only need to update your existing resources every once in a while.

The extra effort put in should not be a factor. The value of your application(s) improves so greatly that this minor efforts are really no argument for not having a globalized project. Don’t argue and do it already!