Monday 30 January 2017

Extending Haven and Hearth Client

Hey All, in my previous post - https://winter-in-hnh.blogspot.ru/2017/01/haven-and-hearth-client.html we explored Amber - an advanced Haven and Hearth client by romovs; we learned to fork it on GitHub, clone it to a local repository and compile it in Eclipse IDE, so now it's time for a change, or actually to make a change.

What's the plan?

This particular amendment will allow us to simplify adding Kin's into our Kin list - while adding somebody via hearth secret is not hard and is easily manageble for a solo player, or a player with a couple of friends it gets really challanging once you have over 100 hearth secrets which would be the case for a bigger village or even kingdom. So what are we going to do? We are going to create an AutoKin class which sole purpose would be to open a text file, read hearth secrets from it and tell the client to add Kin's with respective secrets.

Setting everything up

But before we get to coding there is one additional step we need to perform and that is telling Eclipse IDE that we are actually dealing with a Java project. Previously (in https://winter-in-hnh.blogspot.ru/2017/01/haven-and-hearth-client.html) we created a generic project to store our source code, and then only used Eclipse IDE to check out source code from Git and told it to execute an Ant build using build.xml supplied by the project. Since now we are getting into more advanced stuff we need to make sure Eclipse IDE has an idea of what we are working with. To do so right-click your project name in Project Explorer tab and select Properties. Then click "Project Facets" and select "Java" to instruct Eclipse IDE that we are going to be using Java in our project.
Now we are all set to code.

Adding AutoKin

In our Project Explorer tab - lets pick a nice place for where we will put our AutoKin class, to me the most obvious place is with other automation tasks:

So right-click "haven.automation" folder and select "New > Class":

Now select the name of your class and check the package where it will be added, as well as pick interfaces it is going to implement:
It's worth noting that Runnable is a standard Java class (https://docs.oracle.com/javase/8/docs/api/java/lang/Runnable.html) that needs to implement a single method - run().

Once finished you should see your newly added AutoKin.java in Project Explorer window under "haven.automation" package in the source tree:
As you can see Eclipse IDE also prepopolated our class based on information we provide, so it "implements Runnable" and has stub run() method.


Coding AutoKin

Now that we successfully added a new class lets populate it with some actual functionality.

package haven.automation;
import java.awt.Color;
import java.io.BufferedReader;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

import haven.GameUI;

public class AutoKin implements Runnable {
  // private attribute pointing to GameUI
  private GameUI gui;
  // AutoKin constructor
  public AutoKin(GameUI gui) {
    this.gui = gui;
  }
  @Override
  public void run() {
    gui.syslog.append("AutoAdding Kin's:", Color.WHITE);
    Path file = Paths.get("secrets.txt");
    Charset charset = Charset.forName("UTF-8");
    try (BufferedReader reader = Files.newBufferedReader(file, charset)) {
      String line = null;
      while ((line = reader.readLine()) != null) {
        gui.syslog.append(line,Color.BLUE);
        gui.wdgmsg(gui.buddies,"bypwd",line);
      }
    } catch (IOException x) {
      gui.syslog.append("Exception: "+x.toString(),Color.RED);
    }
  }
}

Now, this is pretty much self explanatory - very basic stuff. We create a Path pointing to "secrets.txt" file in current directory (directory from where the client was started) and try to read it as if it was "UTF-8" encoded line by line. Every line is interpreted as a hearth secret, so we try to add a kin (buddy) using their secret (bypwd). This is good time to rebuild the client and see if we broke anything with our addition. I hope you remember how to execute the Ant build - so right-click on "build.xml", and then select "Run As > Ant Build" and there it goes - remember to save your changes! In Console tab you should be able to see your project building:
Buildfile: C:\workspace\amber\build.xml
build-env:
hafen-client:
    [javac] Compiling 1 source file to C:\workspace\amber\build\classes
buildinfo:
lib-classes:
jar:
      [jar] Updating jar: C:\workspace\amber\build\hafen.jar
res-jar:
l10n-jar:
jars:
deftgt:
BUILD SUCCESSFUL
Total time: 4 seconds

Great, so our functionality compiled, but how do we trigger it?

Lets run() the Runnable

For now we are not going to get into intricacies of menu's, windows, widgets and buttons, but rather go the easy way and bind our functionality to a hotkey. To do so, we will modify globtype() method in GameUI.java class. GameUI.class is located under package "haven" and particular place within globtype() we are interested in is the following:
        } else if (!ev.isShiftDown() && ev.getKeyCode() == KeyEvent.VK_Q) {
            Thread t = new Thread(new PickForageable(this), "PickForageable");
            t.start();
            return true;
        } else if (ev.isControlDown() && ev.getKeyCode() == KeyEvent.VK_K){
         // AutoKin
         Thread t = new Thread(new AutoKin(this), "AutoKin");
         t.start();
         return true;
        }
        return (super.globtype(key, ev));
As you can see this method takes two arguments - character representing key pressed and a KeyEvent class, we are using the latter since we need slightly more information than what is the key character. Above you can see us adding another clause binding execution of AutoKin in a new thread to Control+K chord.

Auto-adding-Kins

With all changes done and saved, we recompile our build and start the client. Once logged in and in game lets press Control+K for the fun of it:
Yay! Our code picked up and tried opening secrets.txt, which was not there and thus failed with NoSuchFileException. Now let's create "secrets.txt", which will only consist of single line "A9XylWM6" and put it into our "build" directory - and now we are all set to press Control+K again.
Ok, now this is better - we see the hearth secret we are trying to add, but we see that nobody has it - this happens because "l" and "I" look alike, so we just had the wrong hearth secret - lets fix it in the file. This time no red line appears and "Kith and Kin" window pops-up showing our new added Kin(s).

Achievement Unlocked

Here is what we have achieved:
  1. Set our project to be Java based
  2. Developed AutoKin functionality - reading hearth secrets from file and adding kins by their hearth secret
  3. Added a hotkey to invoke our AutoKin functionality
  4. Compiled updated Haven and Hearth client



No comments:

Post a Comment