mirror of
https://github.com/bdnugget/rs-sdk.git
synced 2026-11-07 09:07:30 +00:00
some mcp fixes
This commit is contained in:
1 parent
740340e091
commit
b15385fe9e
6 files changed
+86
-6
No files matched your search
@@ -0,0 +1,49 @@
|
||||
# Draynor Manor
|
||||
|
||||
## DANGER: One-Way Front Door
|
||||
|
||||
The front door of Draynor Manor **cannot be opened from inside**. The quest script (`quest_haunted.rs2`) checks `if(coordz(coord) > coordz(loc_coord))` — only players on the north (outside) side can open it.
|
||||
|
||||
**If the pathfinder routes you through the front door, you will be trapped inside.**
|
||||
|
||||
### How to Escape (If Trapped)
|
||||
|
||||
The manor has internal doors that connect rooms. Two key doors form an escape path through the east wing:
|
||||
|
||||
1. **Door at (3119, 3356) id:1530** — connects the SE room to the warehouse area
|
||||
2. **Door at (3123, 3360) id:136** — connects warehouse to the courtyard
|
||||
|
||||
The SDK pathfinder can't open these doors automatically because `sendInteractLoc` relies on server-side pathfinding, which blocks on closed doors. Use raw `sendWalk` to get adjacent, then interact:
|
||||
|
||||
```typescript
|
||||
// Step 1: Raw-walk to a tile adjacent to the door
|
||||
sdk.sendWalk(doorX, doorZ - 1); // south side
|
||||
await sdk.waitForTicks(2);
|
||||
|
||||
// Step 2: Interact to open
|
||||
sdk.sendInteractLoc(doorX, doorZ, doorId, 1);
|
||||
await sdk.waitForTicks(3);
|
||||
|
||||
// Step 3: Walk through
|
||||
sdk.sendWalk(doorX, doorZ + 1); // north side
|
||||
await sdk.waitForTicks(2);
|
||||
```
|
||||
|
||||
### Avoidance
|
||||
|
||||
Avoid routing through Draynor Manor entirely. If you need to pass through the area, use coordinates that stay well clear of the manor grounds (x < 3090 or x > 3130).
|
||||
|
||||
## Draynor Manor Underground
|
||||
|
||||
- **Stairs down** at (3115, 3357) → crypt at (3077, 9771)
|
||||
- Crypt is a separate area from the puzzle basement — no walking connection between them
|
||||
- **Magic door** exit at (2874, 9750) leads to the Wilderness — avoid unless you know what you're doing
|
||||
|
||||
## Key Coordinates
|
||||
|
||||
| Location | Coordinates | Notes |
|
||||
|----------|-------------|-------|
|
||||
| Front door (one-way) | (3108, 3353) | DO NOT ENTER |
|
||||
| East wing doors | (3119, 3356), (3123, 3360) | Escape route |
|
||||
| Crypt stairs | (3115, 3357) | Goes to (3077, 9771) |
|
||||
| Courtyard | (3125, 3370) | North of east wing |
|
||||
+12
-3
@@ -12,6 +12,7 @@ export interface BotConnection {
|
||||
bot: BotActions;
|
||||
username: string;
|
||||
connected: boolean;
|
||||
unsubscribeConnectionState?: () => void;
|
||||
}
|
||||
|
||||
class BotManager {
|
||||
@@ -99,7 +100,7 @@ class BotManager {
|
||||
};
|
||||
|
||||
// Track connection state changes
|
||||
sdk.onConnectionStateChange((state) => {
|
||||
connection.unsubscribeConnectionState = sdk.onConnectionStateChange((state) => {
|
||||
const wasConnected = connection.connected;
|
||||
connection.connected = state === 'connected';
|
||||
if (wasConnected && !connection.connected) {
|
||||
@@ -114,11 +115,16 @@ class BotManager {
|
||||
}
|
||||
|
||||
private async connectWithTimeout(sdk: BotSDK, timeoutMs: number): Promise<void> {
|
||||
let timeoutId: ReturnType<typeof setTimeout>;
|
||||
const timeoutPromise = new Promise<never>((_, reject) => {
|
||||
setTimeout(() => reject(new Error(`Connection timed out after ${timeoutMs / 1000}s`)), timeoutMs);
|
||||
timeoutId = setTimeout(() => reject(new Error(`Connection timed out after ${timeoutMs / 1000}s`)), timeoutMs);
|
||||
});
|
||||
|
||||
await Promise.race([sdk.connect(), timeoutPromise]);
|
||||
try {
|
||||
await Promise.race([sdk.connect(), timeoutPromise]);
|
||||
} finally {
|
||||
clearTimeout(timeoutId!);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -131,6 +137,9 @@ class BotManager {
|
||||
}
|
||||
|
||||
console.error(`[MCP] Disconnecting bot "${name}"...`);
|
||||
if (connection.unsubscribeConnectionState) {
|
||||
connection.unsubscribeConnectionState();
|
||||
}
|
||||
connection.sdk.disconnect();
|
||||
connection.connected = false;
|
||||
this.connections.delete(name);
|
||||
|
||||
+8
-2
@@ -196,10 +196,16 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
||||
|
||||
// Execute code with 10 minute timeout
|
||||
const EXECUTION_TIMEOUT = 10 * 60 * 1000;
|
||||
let timeoutId: ReturnType<typeof setTimeout>;
|
||||
const timeoutPromise = new Promise<never>((_, reject) => {
|
||||
setTimeout(() => reject(new Error(`Code execution timed out after 10 minutes`)), EXECUTION_TIMEOUT);
|
||||
timeoutId = setTimeout(() => reject(new Error(`Code execution timed out after 10 minutes`)), EXECUTION_TIMEOUT);
|
||||
});
|
||||
const result = await Promise.race([fn(connection.bot, connection.sdk), timeoutPromise]);
|
||||
let result: any;
|
||||
try {
|
||||
result = await Promise.race([fn(connection.bot, connection.sdk), timeoutPromise]);
|
||||
} finally {
|
||||
clearTimeout(timeoutId!);
|
||||
}
|
||||
|
||||
// Build formatted output
|
||||
const parts: string[] = [];
|
||||
|
||||
+14
-1
@@ -573,7 +573,16 @@ export class BotActions {
|
||||
const invCountBefore = this.sdk.getInventory().length;
|
||||
const startTick = this.sdk.getState()?.tick || 0;
|
||||
|
||||
// Send pickup directly - game client handles walk-to-interact via MOVE_OPCLICK
|
||||
// Walk to the item's exact tile first
|
||||
const walkResult = await this.walkTo(item.x, item.z, 0);
|
||||
if (!walkResult.success) {
|
||||
return { success: false, message: walkResult.message, reason: 'cant_reach' };
|
||||
}
|
||||
|
||||
// Wait one tick before picking up
|
||||
await this.sdk.waitForTicks(1);
|
||||
|
||||
// Now send the pickup command
|
||||
const result = await this.sdk.sendPickup(item.x, item.z, item.id);
|
||||
if (!result.success) {
|
||||
return { success: false, message: result.message };
|
||||
@@ -610,6 +619,10 @@ export class BotActions {
|
||||
}
|
||||
|
||||
const pickedUp = this.sdk.getInventory().find(i => i.id === item.id);
|
||||
|
||||
// Wait one tick after picking up
|
||||
await this.sdk.waitForTicks(1);
|
||||
|
||||
return { success: true, item: pickedUp, message: `Picked up ${item.name}` };
|
||||
} catch {
|
||||
return { success: false, message: 'Timed out waiting for pickup', reason: 'timeout' };
|
||||
|
||||
@@ -58,11 +58,13 @@ for (const dir of outDirs) {
|
||||
for (const outDir of ['out/standard', 'out/bot']) {
|
||||
fs.copyFileSync('src/3rdparty/bzip2-wasm/bzip2.wasm', `${outDir}/bzip2.wasm`);
|
||||
fs.copyFileSync('src/3rdparty/tinymidipcm/tinymidipcm.wasm', `${outDir}/tinymidipcm.wasm`);
|
||||
fs.copyFileSync('src/3rdparty/tinymidipcm/SCC1_Florestan.sf2', `${outDir}/SCC1_Florestan.sf2`);
|
||||
}
|
||||
|
||||
// Also copy to root out for backwards compatibility
|
||||
fs.copyFileSync('src/3rdparty/bzip2-wasm/bzip2.wasm', 'out/bzip2.wasm');
|
||||
fs.copyFileSync('src/3rdparty/tinymidipcm/tinymidipcm.wasm', 'out/tinymidipcm.wasm');
|
||||
fs.copyFileSync('src/3rdparty/tinymidipcm/SCC1_Florestan.sf2', 'out/SCC1_Florestan.sf2');
|
||||
|
||||
const args = process.argv.slice(2);
|
||||
const prod = args[0] !== 'dev';
|
||||
@@ -124,6 +126,7 @@ const viewerScript = await bunBuild(
|
||||
fs.writeFileSync('out/viewer/viewer.js', replaceDepsUrl(viewerScript.source));
|
||||
fs.copyFileSync('src/3rdparty/bzip2-wasm/bzip2.wasm', 'out/viewer/bzip2.wasm');
|
||||
fs.copyFileSync('src/3rdparty/tinymidipcm/tinymidipcm.wasm', 'out/viewer/tinymidipcm.wasm');
|
||||
fs.copyFileSync('src/3rdparty/tinymidipcm/SCC1_Florestan.sf2', 'out/viewer/SCC1_Florestan.sf2');
|
||||
fs.writeFileSync('out/viewer/deps.js', deps.source);
|
||||
|
||||
// Copy bot client to root out for backwards compatibility
|
||||
|
||||
Binary file not shown.
Reference in new issue
Block a user