Titelbild zum Artikel

Gaming the game: Using Selenium to automate playing

Avatar von Martin Brotzeller

An online acquaintance described it like this:

„You build your tool to reduce grinding. After a while, building the tool becomes a game in itself. One where you make the rules“

Multiplayer online games nowadays heavily rely on small repetitive tasks to regulate the pace in which you proceed in your competition with other players. Duel a player once and win to earn a point. You have enough energy to duel 10 times. Then you have to wait to regain your energy. If the designer did a good job, it’s fun at first. After a while it gets boring, but you have to do it to compete.

My first encounter with a tool for this was Autohotkey. The game was a flash game. The drawbacks were:

  • I needed to learn a completely new programming language
  • The computer had to run Windows
  • The computer was completely blocked while the script ran
  • Detecting information in a flashgame is tedious, in short you have to compare pixel colors
  • Finding places to click or type text into was reliant on measuring relative coordinates

Later, i heard from a coworker that she used Selenium IDE to control an HTML browser game. This sounded like a way better solution, so i immediately started on a Selenese script for a game i was playing at the time. After installing the Selenium IDE in my Firefox, the first task was to duel a player 10 times, since that was the daily limit. A little obstacle was the way the game was rendered – boxes inside boxes like russian dolls, very little classes, dynamically generated id attributes. Thats where Selenese’s locators really rock. You have a wide variety to choose from. Xpath did the job for me (not the most performant solution, but that is not an issue in an interactive session):

click                  //div[contains(@id,'button_battle_')]
waitForVisible         //div[contains(@id,'region_map')]/div/div[3]//a
assertElementPresent   //div[contains(@id, 'reward')]/div[contains(text(),'Winner')]
click                  //div[contains(text(),'Rematch')]
waitForVisible         //div[contains(text(),'Rematch')]
assertElementPresent   //div[contains(@id, 'reward')]/div[contains(text(),'Winner')]
click                  //div[contains(text(),'Rematch')]
waitForVisible         //div[contains(text(),'Rematch')]
... another 7 times

This is was the first working prototype – click on a button with an id of „button_battle_<playerid>“, utilizing waitForVisible to let the AJAX request complete, assert I won the duel, click a button labelled „Rematch“ on the result page, wait again, check for victory. If I lost, the script would just stop, else 10 rounds would be fought.

Since this was nice, but a bit verbose, I looked for some control structures in Selenese and found out that another Firefox Extension was needed, SelBlocks, which provides  If/else, for/foreach and goto, among other constructs. With this, the above can be improved:

click                  //div[contains(@id,'button_battle_')]
waitForVisible         //div[contains(@id,'region_map')]/div/div[3]//a
store                  0                                                              Victories
label                  Repeating
storeElementPresent    //div[contains(@id, 'reward')]/div[contains(text(),'Winner')]  Win
storeEval 	         (function(vic,chg){
                        if (chg) return vic + 1; else return vic - 1
                       })(${Vic},${Win})                                              Victories
gotoIf                 ${Victories} < -1                                              Endpoint
click                  //div[contains(text(),'Rematch')]
waitForVisible 	    //div[contains(text(),'Rematch')] 
                        | //div[@id='navspace']/div/a
storeElementPresent    //a[contains(.,'Battle list')]                                 Ended
gotoIf                 Ended                                                          Endpoint
goto                   Repeating
label                  Endpoint

So here I track how many times i won and lost, and only if the odds are against me, I bail. I need to check whether the game tells me I reached the daily for that particular opponent. An improvement, but it still requires my attention choosing my next victim.

The next step was to extend Selenium IDE with a custom Javascript function that could choose the best duel odds from a list of players. After choosing one, the script would then proceed to battle a player. To have some kind of idea how it went, i started to print out the names of my opponents along with the tally:

storeText   //a[contains(@class,'dark_link')]                  heroname
getEval 	LOG.warn("Hero ${heroname} result: ${Victories}")

The next thing was to monitor my stamina, the form of energy used for the duels:

label Duel
storeText       //span[@id="player_info_stamina"]     Stamina
gotoIf          ${Stamina} < 10                       Waitlabel
... duel on

label           Waitlabel 	
pause           1800000
goto            Duel

This was the point where the browser at home could play the game for me for hours while I was working in the office. As an added benefit, at home I could browse in a different Firefox tab without disturbing Selenium at all! It made playing much more enjoyable, and my guild loved me for my constant weekly performance.

But when something is working, an engineer thinks about what to optimize. Think multiple heroes. Playing one account requires one Selenium IDE. Sadly the IDE only is available for Firefox, and at the time I did not know about how to run multiple Firefox profiles at once.
The obvious choice, Selenium RC or Selenium 2, was a kind of a dead end – Installation is wonky and PHP support is rudimentary and not well documented. Since I could not find anyone who could help me with using Selenium 2, i followed a hint from a coworker and tried RobotFramework. After my problematic experiences with Selenium 2, I was really impressed by the ease of the Installation. Just by entering

sudo apt-get install python python-pip python-wxgtk2.8 firefox
sudo pip install selenium robotframework robotframework-ride robotframework-selenium2library

Everything is working from inside a fully-fledged IDE, which is more powerful and almost as easy to use as Selenium IDE. RobotFramework puts an abstraction onto Selenium 2 that is intuitive to Selenese users but far more powerful.

*** Settings ***
Library           Selenium2Library

*** Variables ***
${GAME_URL}       ************************
${BROWSER}        firefox
${LOGIN_URL}      http://${GAME_URL}/login.php
${MY_URL}         http://${GAME_URL}/?ME=${MY_ID}
${MY_ID}          **********************

*** Keywords ***
Open Login Page
    Open Browser    ${LOGIN_URL}    ${BROWSER}    ff_profile_dir=/home/user/.mozilla/firefox/******
    Switch Browser    1
    Element Should be Visible    pwd
    set selenium speed    0.1 seconds

DoLogin
    [Arguments]       ${USER}=******    ${PASS}=******
    Input Text        hero    ${USER}
    Input Password    pwd    ${PASS}
    Click Element     button-login
    Wait until page contains Element    id=news_popup
    Click Element     css=#button-news-popup > span

This first defines a set of variables to centralize the configuration. Afterwards, two subroutines (which RobotFramework calls keywords) are defined. One opens a browser and selects it and sets a default delay for test runs. The second one fills out a login form and clicks the submit button.
A first „test suite“ for this game then looked like this:

*** Settings ***
Resource          Ressources.txt
Resource          Combat.txt

*** Test Cases ***
CombatTestCase
    Open Login Page
    DoLogin
    Hit Enemies

All can be run directly from the IDE which starts up the specified Firefox profile (the default profile that comes with RobotFramework is working, but if you want to keep cookies or have additional extensions installed, you need to prepare it). The code is easily modularized and reusable and offers lots of potential for further improvement. The only drawback so far is the slightly weaker support for AJAX, but that also applies to Selenium 2; since neither runs directly in the browser, every attempt at waitForVisible is of course less reliable than a piece of Javascript that can access the DOM directly, like Selenium IDE does it.

Why use this and not Greasemonkey? Because i can. And it’s fun. And an easy way to get familiar with Selenium.

Avatar von Martin Brotzeller

Kommentare

3 Antworten zu „Gaming the game: Using Selenium to automate playing“

  1. Lesenswert: Gaming the game: Using Selenium to automate playing http://t.co/tn9oxtiQ3d

  2. „the browser at home could play the game for me for hours while I was working in the office“ http://t.co/SMOQyc3DWo

  3. Great article. The software seems complicated though. I use an application called Chimpeon (https://chimpeon.com) to automate my games. Easy to configure and it allows me to grind mobs and level in games like WOW, Rift and LOTR without even being at my computer.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert


Für das Handling unseres Newsletters nutzen wir den Dienst HubSpot. Mehr Informationen, insbesondere auch zu Deinem Widerrufsrecht, kannst Du jederzeit unserer Datenschutzerklärung entnehmen.