428 lines
14 KiB
Java
428 lines
14 KiB
Java
package com.openosrs.client.api;
|
|
|
|
import com.openosrs.client.core.ClientCore;
|
|
import com.openosrs.client.engine.GameEngine;
|
|
import com.openosrs.client.api.types.Position;
|
|
import com.openosrs.client.api.types.NPC;
|
|
import com.openosrs.client.api.types.GameObject;
|
|
import com.openosrs.client.api.types.Item;
|
|
import com.openosrs.client.api.types.GroundItem;
|
|
import org.slf4j.Logger;
|
|
import org.slf4j.LoggerFactory;
|
|
|
|
import java.util.concurrent.CompletableFuture;
|
|
|
|
/**
|
|
* InteractionAPI - Handles player interactions with the game world.
|
|
*
|
|
* This API module provides methods for:
|
|
* - Movement and pathfinding
|
|
* - NPC interactions
|
|
* - Object interactions
|
|
* - Item usage and manipulation
|
|
* - Chat and communication
|
|
*/
|
|
public class InteractionAPI {
|
|
private static final Logger logger = LoggerFactory.getLogger(InteractionAPI.class);
|
|
|
|
private final ClientCore clientCore;
|
|
private final GameEngine gameEngine;
|
|
|
|
public InteractionAPI(ClientCore clientCore, GameEngine gameEngine) {
|
|
this.clientCore = clientCore;
|
|
this.gameEngine = gameEngine;
|
|
}
|
|
|
|
/**
|
|
* Walk to a specific position.
|
|
*/
|
|
public CompletableFuture<Boolean> walkTo(Position position) {
|
|
if (position == null) {
|
|
return CompletableFuture.completedFuture(false);
|
|
}
|
|
|
|
logger.debug("Walking to position: {}", position);
|
|
|
|
return CompletableFuture.supplyAsync(() -> {
|
|
try {
|
|
// TODO: Integrate with actual game engine walking logic
|
|
// For now, this is a stub that simulates walking
|
|
|
|
Position currentPos = clientCore.getPlayerState().getPosition();
|
|
if (currentPos == null) {
|
|
logger.warn("Cannot walk - player position unknown");
|
|
return false;
|
|
}
|
|
|
|
double distance = currentPos.distanceTo(position);
|
|
if (distance == 0) {
|
|
logger.debug("Already at target position");
|
|
return true;
|
|
}
|
|
|
|
// Simulate walking time based on distance
|
|
int walkTime = (int) (distance * 100); // 100ms per tile roughly
|
|
Thread.sleep(Math.min(walkTime, 5000)); // Cap at 5 seconds
|
|
|
|
// TODO: Actually send walk packet to server and update player position
|
|
logger.debug("Walk completed to {}", position);
|
|
return true;
|
|
|
|
} catch (InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
logger.warn("Walk interrupted");
|
|
return false;
|
|
} catch (Exception e) {
|
|
logger.error("Error during walk", e);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Run to a specific position.
|
|
*/
|
|
public CompletableFuture<Boolean> runTo(Position position) {
|
|
if (position == null) {
|
|
return CompletableFuture.completedFuture(false);
|
|
}
|
|
|
|
logger.debug("Running to position: {}", position);
|
|
|
|
return CompletableFuture.supplyAsync(() -> {
|
|
try {
|
|
// TODO: Enable run mode if not already enabled
|
|
// Then use walking logic but faster
|
|
|
|
Position currentPos = clientCore.getPlayerState().getPosition();
|
|
if (currentPos == null) {
|
|
logger.warn("Cannot run - player position unknown");
|
|
return false;
|
|
}
|
|
|
|
double distance = currentPos.distanceTo(position);
|
|
if (distance == 0) {
|
|
logger.debug("Already at target position");
|
|
return true;
|
|
}
|
|
|
|
// Simulate running time (faster than walking)
|
|
int runTime = (int) (distance * 60); // 60ms per tile roughly
|
|
Thread.sleep(Math.min(runTime, 3000)); // Cap at 3 seconds
|
|
|
|
// TODO: Actually send run packet to server and update player position
|
|
logger.debug("Run completed to {}", position);
|
|
return true;
|
|
|
|
} catch (InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
logger.warn("Run interrupted");
|
|
return false;
|
|
} catch (Exception e) {
|
|
logger.error("Error during run", e);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Interact with an NPC.
|
|
*/
|
|
public CompletableFuture<Boolean> interactWithNPC(NPC npc, String action) {
|
|
if (npc == null || action == null) {
|
|
return CompletableFuture.completedFuture(false);
|
|
}
|
|
|
|
logger.debug("Interacting with NPC {} using action: {}", npc.getName(), action);
|
|
|
|
return CompletableFuture.supplyAsync(() -> {
|
|
try {
|
|
// TODO: Check if NPC is in range
|
|
// TODO: Send interaction packet to server
|
|
// TODO: Handle interaction response
|
|
|
|
Position playerPos = clientCore.getPlayerState().getPosition();
|
|
if (playerPos == null) {
|
|
logger.warn("Cannot interact - player position unknown");
|
|
return false;
|
|
}
|
|
|
|
double distance = npc.distanceToPlayer(playerPos);
|
|
if (distance > 5) {
|
|
logger.warn("NPC too far away for interaction: {} tiles", distance);
|
|
return false;
|
|
}
|
|
|
|
// Simulate interaction time
|
|
Thread.sleep(600); // 1 game tick
|
|
|
|
logger.debug("Interaction completed with NPC {}", npc.getName());
|
|
return true;
|
|
|
|
} catch (InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
logger.warn("NPC interaction interrupted");
|
|
return false;
|
|
} catch (Exception e) {
|
|
logger.error("Error during NPC interaction", e);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Interact with a game object.
|
|
*/
|
|
public CompletableFuture<Boolean> interactWithObject(GameObject object, String action) {
|
|
if (object == null || action == null) {
|
|
return CompletableFuture.completedFuture(false);
|
|
}
|
|
|
|
logger.debug("Interacting with object {} using action: {}", object.getName(), action);
|
|
|
|
return CompletableFuture.supplyAsync(() -> {
|
|
try {
|
|
// TODO: Check if object is in range
|
|
// TODO: Send interaction packet to server
|
|
// TODO: Handle interaction response
|
|
|
|
Position playerPos = clientCore.getPlayerState().getPosition();
|
|
if (playerPos == null) {
|
|
logger.warn("Cannot interact - player position unknown");
|
|
return false;
|
|
}
|
|
|
|
if (!object.hasAction(action)) {
|
|
logger.warn("Object {} does not have action: {}", object.getName(), action);
|
|
return false;
|
|
}
|
|
|
|
double distance = object.distanceToPlayer(playerPos);
|
|
if (distance > 5) {
|
|
logger.warn("Object too far away for interaction: {} tiles", distance);
|
|
return false;
|
|
}
|
|
|
|
// Simulate interaction time
|
|
Thread.sleep(600); // 1 game tick
|
|
|
|
logger.debug("Interaction completed with object {}", object.getName());
|
|
return true;
|
|
|
|
} catch (InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
logger.warn("Object interaction interrupted");
|
|
return false;
|
|
} catch (Exception e) {
|
|
logger.error("Error during object interaction", e);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Pick up a ground item.
|
|
*/
|
|
public CompletableFuture<Boolean> pickupItem(GroundItem item) {
|
|
if (item == null) {
|
|
return CompletableFuture.completedFuture(false);
|
|
}
|
|
|
|
logger.debug("Picking up ground item: {} x{}", item.getName(), item.getQuantity());
|
|
|
|
return CompletableFuture.supplyAsync(() -> {
|
|
try {
|
|
// TODO: Check if item is in range
|
|
// TODO: Check if inventory has space
|
|
// TODO: Send pickup packet to server
|
|
|
|
Position playerPos = clientCore.getPlayerState().getPosition();
|
|
if (playerPos == null) {
|
|
logger.warn("Cannot pickup - player position unknown");
|
|
return false;
|
|
}
|
|
|
|
double distance = item.distanceToPlayer(playerPos);
|
|
if (distance > 2) {
|
|
logger.warn("Item too far away for pickup: {} tiles", distance);
|
|
return false;
|
|
}
|
|
|
|
// Check inventory space
|
|
if (clientCore.getInventoryState().isInventoryFull() && !item.getName().equals("Coins")) {
|
|
logger.warn("Inventory full - cannot pickup item");
|
|
return false;
|
|
}
|
|
|
|
// Simulate pickup time
|
|
Thread.sleep(600); // 1 game tick
|
|
|
|
logger.debug("Pickup completed for item {}", item.getName());
|
|
return true;
|
|
|
|
} catch (InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
logger.warn("Item pickup interrupted");
|
|
return false;
|
|
} catch (Exception e) {
|
|
logger.error("Error during item pickup", e);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Use an inventory item.
|
|
*/
|
|
public CompletableFuture<Boolean> useItem(int slot) {
|
|
logger.debug("Using item in slot: {}", slot);
|
|
|
|
return CompletableFuture.supplyAsync(() -> {
|
|
try {
|
|
// TODO: Validate slot
|
|
// TODO: Send use item packet
|
|
|
|
Item item = clientCore.getInventoryState().getInventorySlot(slot);
|
|
if (item == null || item.isEmpty()) {
|
|
logger.warn("No item in slot {} to use", slot);
|
|
return false;
|
|
}
|
|
|
|
// Simulate use time
|
|
Thread.sleep(600); // 1 game tick
|
|
|
|
logger.debug("Used item: {}", item.getName());
|
|
return true;
|
|
|
|
} catch (InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
logger.warn("Item use interrupted");
|
|
return false;
|
|
} catch (Exception e) {
|
|
logger.error("Error using item", e);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Use an item on another item.
|
|
*/
|
|
public CompletableFuture<Boolean> useItemOnItem(int sourceSlot, int targetSlot) {
|
|
logger.debug("Using item in slot {} on item in slot {}", sourceSlot, targetSlot);
|
|
|
|
return CompletableFuture.supplyAsync(() -> {
|
|
try {
|
|
// TODO: Validate both slots
|
|
// TODO: Send use item on item packet
|
|
|
|
Item sourceItem = clientCore.getInventoryState().getInventorySlot(sourceSlot);
|
|
Item targetItem = clientCore.getInventoryState().getInventorySlot(targetSlot);
|
|
|
|
if (sourceItem == null || sourceItem.isEmpty()) {
|
|
logger.warn("No item in source slot {} to use", sourceSlot);
|
|
return false;
|
|
}
|
|
|
|
if (targetItem == null || targetItem.isEmpty()) {
|
|
logger.warn("No item in target slot {} to use on", targetSlot);
|
|
return false;
|
|
}
|
|
|
|
// Simulate combination time
|
|
Thread.sleep(600); // 1 game tick
|
|
|
|
logger.debug("Used {} on {}", sourceItem.getName(), targetItem.getName());
|
|
return true;
|
|
|
|
} catch (InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
logger.warn("Item combination interrupted");
|
|
return false;
|
|
} catch (Exception e) {
|
|
logger.error("Error combining items", e);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Drop an inventory item.
|
|
*/
|
|
public CompletableFuture<Boolean> dropItem(int slot) {
|
|
logger.debug("Dropping item in slot: {}", slot);
|
|
|
|
return CompletableFuture.supplyAsync(() -> {
|
|
try {
|
|
// TODO: Validate slot
|
|
// TODO: Send drop item packet
|
|
|
|
Item item = clientCore.getInventoryState().getInventorySlot(slot);
|
|
if (item == null || item.isEmpty()) {
|
|
logger.warn("No item in slot {} to drop", slot);
|
|
return false;
|
|
}
|
|
|
|
// Simulate drop time
|
|
Thread.sleep(600); // 1 game tick
|
|
|
|
logger.debug("Dropped item: {}", item.getName());
|
|
return true;
|
|
|
|
} catch (InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
logger.warn("Item drop interrupted");
|
|
return false;
|
|
} catch (Exception e) {
|
|
logger.error("Error dropping item", e);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Send a chat message.
|
|
*/
|
|
public void sendChatMessage(String message) {
|
|
if (message == null || message.trim().isEmpty()) {
|
|
logger.warn("Cannot send empty chat message");
|
|
return;
|
|
}
|
|
|
|
logger.debug("Sending chat message: {}", message);
|
|
|
|
// TODO: Send chat packet to server
|
|
// TODO: Handle chat message validation and formatting
|
|
|
|
// For now, just log it
|
|
logger.info("Chat: {}", message);
|
|
}
|
|
|
|
/**
|
|
* Enable or disable run mode.
|
|
*/
|
|
public CompletableFuture<Boolean> setRunMode(boolean enabled) {
|
|
logger.debug("Setting run mode: {}", enabled);
|
|
|
|
return CompletableFuture.supplyAsync(() -> {
|
|
try {
|
|
// TODO: Send run mode packet to server
|
|
// TODO: Update player state
|
|
|
|
Thread.sleep(100); // Small delay for packet
|
|
|
|
logger.debug("Run mode set to: {}", enabled);
|
|
return true;
|
|
|
|
} catch (InterruptedException e) {
|
|
Thread.currentThread().interrupt();
|
|
logger.warn("Run mode change interrupted");
|
|
return false;
|
|
} catch (Exception e) {
|
|
logger.error("Error changing run mode", e);
|
|
return false;
|
|
}
|
|
});
|
|
}
|
|
}
|