Skip to main content

Guidelines & Caveats

Constants over magic numbers

If you're using numbers such as IDs or coordinates in your code, consider using constants. This helps with keeping your code readable and maintainable.

private static final int COINS_ITEM_ID = 995;

private static final Position GRAND_EXCHANGE = Position.from(3164, 3487);

Guard clauses

A guard clause is a simple way of writing code that checks for specific conditions early in a function, and if those conditions aren’t met, it stops the function right away. This helps you avoid having lots of nested if-statements and makes your code easier to read and understand.

Here is an example of a task that performs power-chopping:

@Override
public boolean execute() {
Player self = Players.self();
if (self != null) {
Inventory inv = Inventories.backpack();
if (inv.isFull()) {
inv.interact(iq -> iq.nameContains("logs").results(), "Drop");
return true;
}

if (!self.isAnimating() && !self.isMoving()) {
SceneObject tree = SceneObjects.query().names("Tree").actions("Chop-down").results().nearest();
if (tree != null) {
tree.interact("Chop-down");
} else {
Movement.walkTo(NEAR_TREE_POSITION);
}
return true;
}
}
return false;
}

While this example works fine, it gets very messy and hard to follow with all the nesting. In larger functions, the nesting levels would go deeper, and you'd have more and more edge conditions making it almost unreadable.

The same code can be written as such:

@Override
public boolean execute() {
Player self = Players.self();
if (self == null) {
return false;
}

Inventory inv = Inventories.backpack();
if (inv.isFull()) {
inv.interact(iq -> iq.nameContains("logs").results(), "Drop");
return true;
}

if (self.isAnimating() || self.isMoving()) {
return false;
}

SceneObject tree = SceneObjects.query().names("Tree").actions("Chop-down").results().nearest();
if (tree != null) {
tree.interact("Chop-down");
} else {
Movement.walkTo(NEAR_TREE_POSITION);
}

return true;
}

By using guard clauses, we keep the code clean, readable, and maintainable. This approach ensures that the logic of the method is simple and easy to follow, while edge cases are handled upfront, allowing for early exits and easy modifications.

Guard clauses go hand in hand with defensive programming. Such techniques are used to write safer and more reliable code by handling potential problems early. Preemptively checking for problems like invalid states (null objects or invalid inputs) is always better.