EnderWiggin / hafen-client

New Haven client
Other
26 stars 35 forks source link

[Feature] automatisation script for collect Clay #86

Open Fr-Dae opened 8 months ago

Fr-Dae commented 8 months ago

Hello, could you produce a script, which determines an area, in which to harvest clay (or acre clay) that automatically equips the shovel with the best shovel available.

package myPackage;

import haven.*; // Import of necessary classes

public class HarvestingBot {
    private Rectangle selectedArea; // Selected area
    private Shovel bestShovel; // Best shovel
    private boolean inventoryFull; // Full or not inventory flag

    public HarvestingBot() {
        // Constructor
    }

    public void onClickIcon(Coord point1, Coord point2) {
        // Determine a rectangular area from two diagonal points
        selectedArea = defineRectangularArea(point1, point2);

        // Check if the selected area contains clay or acreclay
        if (!checkClayInArea(selectedArea)) {
            // Display an error message if there is no clay or acreclay in the selected area
            System.out.println("Error: No clay or acreclay found in the selected area.");
            return;
        }

        // Equip the "shovel" tool with the best statistics from the inventory or belt
        bestShovel = selectBestShovel();
        if (bestShovel == null) {
            // Display an error message if there is no shovel available
            System.out.println("Error: No shovel available in the inventory or belt.");
            return;
        }

        // Start the harvesting process
        startHarvesting();
    }

    private RectangularArea defineRectangularArea(Coord point1, Coord point2) {
        // Logic to define the rectangular area from the two points
        // Use of the Haven API to define the selection area
        // Returns an object representing the defined rectangular area
        return null; // Placeholder, to be replaced with appropriate logic
    }

    private boolean checkClayInArea(RectangularArea area) {
        // Logic to check the presence of clay or acreclay in the specified area
        // Use of the Haven API to analyze resources in the area
        // Returns true if clay or acreclay is present, otherwise false
        return false; // Placeholder, to be replaced with appropriate logic
    }

    private Shovel selectBestShovel() {
        // Logic to choose the shovel with the best statistics
        // Use of the Haven API to manage equipment
        // Returns the best shovel
        return null; // Placeholder, to be replaced with appropriate logic
    }

    private void startHarvesting() {
        // Move to the first tile to start harvesting using the "dig" action
        moveToFirstTileAndDig(selectedArea);

        // Continue harvesting on the next tiles until the inventory is full
        while (!inventoryFull && hasRemainingTiles()) {
            moveToNextClosestTile(selectedArea);
            highlightRemainingTiles(selectedArea);
            harvestCurrentTile();
        }

        // If the inventory is full, stop the script and return to the starting point
        if (inventoryFull) {
            stopScriptAndReturn();
        }
    }

    // Other methods for movement, highlighting tiles, and harvesting
    // moveToFirstTileAndDig(), moveToNextClosestTile(), highlightRemainingTiles(), harvestCurrentTile(), etc.

    private boolean hasRemainingTiles() {
        // Logic to check if there are remaining tiles to harvest in the selected area
        // Returns true or false based on the presence of remaining tiles
        return false; // Placeholder, to be replaced with appropriate logic
    }

    private void harvestCurrentTile() {
        // Logic to harvest resources from the current tile
        // Use of the Haven API to harvest resources
    }

    private void stopScriptAndReturn() {
        // Logic to stop the script and return to the initial location
        // Use of the Haven API to manage the return to the initial location
    }
}

here are the functions that are missing, you are free to code them as you wish, I lack the resources to write what is missing I've done a bit of python and json before, but never java, sorry if it's not great.

defineRectangularArea(Coord point1, Coord point2):
This function should be implemented to determine the rectangular area from two diagonal points. It is essential to define the area where the bot will gather resources.

checkClayInArea(RectangularArea area):
This function is necessary to check the presence of resources (clay or acreclay) in the specified area. It should use Haven API functionalities to analyze resources in the area.

selectBestShovel():
This function should be implemented to choose the best shovel available in the character's inventory or belt. It should utilize shovel statistics and select the one most suitable for harvesting.

moveToFirstTileAndDig(RectangularArea selectedArea):
This function is responsible for moving the character to the first tile of the selected area and initiating harvesting using the "dig" action.

moveToNextClosestTile(RectangularArea selectedArea):
This function should enable the character to move to the next closest tile within the selected area to continue harvesting.

highlightRemainingTiles(RectangularArea selectedArea):
This function is tasked with highlighting the remaining tiles to harvest within the selection to assist the character in identifying the next tiles for harvesting.

harvestCurrentTile():
This function should contain the logic to effectively harvest resources from the current tile. It should utilize Haven API functionalities to perform the harvesting.

hasRemainingTiles():
This function is necessary to check if there are remaining tiles to harvest within the selected area. It should return true or false based on the presence of remaining tiles.

stopScriptAndReturn():
This function should be implemented to halt the harvesting script and return the character to its initial location.
Fr-Dae commented 8 months ago

i have remplace space by tabulation, to respect coding normes 4 spaces for 1 tab

EnderWiggin commented 8 months ago

why not use survey instead?

Fr-Dae commented 8 months ago

why not use survey instead?

sorry i don't understand you question

Fr-Dae commented 8 months ago

for exemple, this is the python script made by pirus and modified by @Cediner fork of @puruscor work

// A clay differ bot, digs ball-clay from the selected area and puts it in the clay stockpiles in the selected area
// Made by Purus Cor to demonstrate usage of PBot API
// For more information about API, join Purus Pasta discord
// To suggest features into API, suggest them in discord

// Import required Java packages
const ui = Java.type('haven.purus.pbot.PBotAPI').ui();
const PBotUtils = Java.type("haven.purus.pbot.PBotUtils");
const PBotCharacterAPI = Java.type("haven.purus.pbot.PBotCharacterAPI");
const PBotGobAPI = Java.type("haven.purus.pbot.PBotGobAPI");
const PBotWindowAPI = Java.type("haven.purus.pbot.PBotWindowAPI");

// Create a window for the bot and add a start button
const window = PBotUtils.PBotWindow(ui, "Clay Digger", 50, 110, ScriptID);
const startBtn = window.addButton("startBtnCb", "Start", 100, 5, 5);

// Change the start button's color
startBtn.changeColor(255, 200, 255);

// Initialize stop flag
let stop = false;

// Callback function for start button click event
const startBtnCb = () => {
    let clayDug = 0;
    startBtn.destroy();
    PBotUtils.sysMsg(ui, "First, select area to dig ball clay from!");
    PBotUtils.selectArea(ui);
    const aCoordDig = PBotUtils.getSelectedAreaA();
    const bCoordDig = PBotUtils.getSelectedAreaB();
    let clayTiles = [];
    const maxX = Math.max(aCoordDig.x, bCoordDig.x);
    const minX = Math.min(aCoordDig.x, bCoordDig.x);
    const maxY = Math.max(aCoordDig.y, bCoordDig.y);
    const minY = Math.min(aCoordDig.y, bCoordDig.y);
    console.log(maxX + " ja " + minX + " JA " + maxY + " ja " + minY);
    for (let i = minY; i < maxY; i += 11) {
        for (let j = minX; j < maxX; j += 11) {
            // Add shallow water tiles into the claytile list
            if (PBotUtils.tileResnameAt(ui, j, i) === "gfx/tiles/water" || PBotUtils.tileResnameAt(ui, j, i) === "gfx/tiles/owater") {
                clayTiles.push({ x: j, y: i });
            }
        }
    }
    PBotUtils.sysMsg(ui, "Second, select area with stockpiles!");
    PBotUtils.selectArea(ui);
    let stockpiles = [];
    const gobs = PBotUtils.gobsInArea(ui, PBotUtils.getSelectedAreaA(), PBotUtils.getSelectedAreaB());
    for (let i = 0; i < gobs.size(); i++) {
        if (gobs[i].getResname() === "gfx/terobjs/stockpile-clay") stockpiles.push(gobs[i]);
    }

    while (!shouldStop()) {
        // Dig until inventory full or out of claytiles
        if (clayTiles.length === 0) {
            PBotUtils.sysMsg(ui, "Out of tiles to dig clay from!");
            stop = true;
            break;
        }
        while (clayTiles.length > 0 && PBotUtils.playerInventory(ui).freeSlotsInv() > 1 && !shouldStop()) {
            if (PBotCharacterAPI.getStamina(ui) < 70) PBotUtils.drink(ui, true);
            PBotUtils.pfLeftClick(ui, clayTiles[0].x, clayTiles[0].y);
            PBotCharacterAPI.doAct(ui, "dig");
            PBotUtils.mapClick(ui, clayTiles[0].x, clayTiles[0].y, 1, 0);
            PBotCharacterAPI.cancelAct(ui);
            waitForIdle();
            clayTiles.shift();
        }
        PBotUtils.sleep(100); // Wait a moment for all the clay to appear into the inventory
        let clayInInv = PBotUtils.playerInventory(ui).getInventoryItemsByResnames(".*clay-ball").size();
        console.log(clayInInv);
        // Put clay in stockpiles or out of stockpiles
        while (clayInInv > 0) {
            if (stockpiles.length == 0) {
                stop = true;
                PBotUtils.sysMsg(ui, "Ran out of free clay stockpiles!");
                break;
            }
            console.log(stockpiles[0]);
            PBotUtils.pfRightClick(ui, stockpiles[0], 0);
            PBotWindowAPI.waitForWindow(ui, "Stockpile");
            const slots = PBotWindowAPI.getStockpileTotalCapacity(ui);
            const used = PBotWindowAPI.getStockpileUsedCapacity(ui);
            const count = Math.min(clayInInv, slots - used);
            PBotWindowAPI.putItemFromInventoryToStockpile(ui, count);
            clayDug += count;
            if (count + used === slots) stockpiles.shift();
            clayInInv -= count;
            while (PBotUtils.playerInventory(ui).getInventoryItemsByResnames(".*clay-ball").size() != clayInInv) {
                PBotUtils.sleep(25);
            }
        }
    }
    PBotUtils.sysMsg(ui, "Finished! Total clay dug: " + clayDug);
};

const shouldStop = () => {
    return stop || window.closed();
};

function getPlayer() {
    return PBotGobAPI.player(ui);
}
function waitForIdle() {
    const tick = 75;
    const maxWaitTicks = 4;
    //PBotUtils.waitForHourglass(ui, tick * maxWaitTicks);
    let idleCounter = maxWaitTicks;
    while (idleCounter >= 0 && !shouldStop()) {
        if (PBotUtils.getHourglass(ui) == -1 && !getPlayer().isMoving()) idleCounter--;
        else idleCounter = maxWaitTicks;
        PBotUtils.sleep(tick);
    }
}
Fr-Dae commented 8 months ago

so, ok, i understand you don't like python. but rather than taking the time to redo a script from scratch, why not just add python to your launcher and import the existing scripts?