@lzimul/minecraft-mcp 1.0.4 → 1.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -21
- package/README.md +297 -219
- package/build/app/server.js +6 -1
- package/build/app/tool-events.js +72 -0
- package/build/app/websocket.js +116 -0
- package/build/config/server-info.js +4 -4
- package/build/config/storage.js +2 -1
- package/build/config/websocket.js +48 -0
- package/build/config/world-limits.js +2 -0
- package/build/enums/move-direction.enum.js +9 -0
- package/build/index.js +19 -1
- package/build/interfaces/websocket.interface.js +1 -0
- package/build/resources/dimension-resources.js +2 -2
- package/build/tools/entity-tools.js +318 -5
- package/build/tools/world-tools.js +388 -1
- package/build/utils/logger.js +1 -1
- package/build/world/block-spec.js +3 -1
- package/build/world/entity-inventory.js +21 -4
- package/build/world/simulated-dimension.js +135 -9
- package/build/world/stores/file-world-store.js +47 -39
- package/build/world/stores/memory-world-store.js +5 -0
- package/build/world/stores/serialized-entity.js +4 -3
- package/build/world/stores/serialized-snapshot.js +35 -0
- package/lib/app/server.d.ts +5 -1
- package/lib/app/server.d.ts.map +1 -1
- package/lib/app/tool-events.d.ts +5 -0
- package/lib/app/tool-events.d.ts.map +1 -0
- package/lib/app/websocket.d.ts +10 -0
- package/lib/app/websocket.d.ts.map +1 -0
- package/lib/config/dimensions.d.ts.map +1 -1
- package/lib/config/server-info.d.ts.map +1 -1
- package/lib/config/storage.d.ts.map +1 -1
- package/lib/config/websocket.d.ts +8 -0
- package/lib/config/websocket.d.ts.map +1 -0
- package/lib/config/world-limits.d.ts +2 -0
- package/lib/config/world-limits.d.ts.map +1 -1
- package/lib/data/entities.d.ts.map +1 -1
- package/lib/enums/bounding-box.enum.d.ts.map +1 -1
- package/lib/enums/dimension-type.enum.d.ts.map +1 -1
- package/lib/enums/entity-kind.enum.d.ts.map +1 -1
- package/lib/enums/icon-theme.enum.d.ts.map +1 -1
- package/lib/enums/inventory-section.enum.d.ts.map +1 -1
- package/lib/enums/move-direction.enum.d.ts +9 -0
- package/lib/enums/move-direction.enum.d.ts.map +1 -0
- package/lib/index.d.ts +1 -1
- package/lib/index.d.ts.map +1 -1
- package/lib/interfaces/block.interface.d.ts.map +1 -1
- package/lib/interfaces/data-entry.interface.d.ts.map +1 -1
- package/lib/interfaces/dimension.interface.d.ts.map +1 -1
- package/lib/interfaces/entity-inventory.interface.d.ts.map +1 -1
- package/lib/interfaces/entity-type.interface.d.ts.map +1 -1
- package/lib/interfaces/entity.interface.d.ts.map +1 -1
- package/lib/interfaces/item.interface.d.ts.map +1 -1
- package/lib/interfaces/placed-block.interface.d.ts.map +1 -1
- package/lib/interfaces/websocket.interface.d.ts +47 -0
- package/lib/interfaces/websocket.interface.d.ts.map +1 -0
- package/lib/interfaces/world-store.interface.d.ts +1 -0
- package/lib/interfaces/world-store.interface.d.ts.map +1 -1
- package/lib/resources/block-resources.d.ts.map +1 -1
- package/lib/resources/data-resources.d.ts.map +1 -1
- package/lib/resources/dimension-resources.d.ts +3 -0
- package/lib/resources/dimension-resources.d.ts.map +1 -1
- package/lib/resources/entity-resources.d.ts.map +1 -1
- package/lib/resources/index.d.ts.map +1 -1
- package/lib/resources/item-resources.d.ts.map +1 -1
- package/lib/schemas/block-schema.d.ts.map +1 -1
- package/lib/schemas/coordinate-schema.d.ts.map +1 -1
- package/lib/schemas/dimension-schema.d.ts.map +1 -1
- package/lib/schemas/entity-schema.d.ts.map +1 -1
- package/lib/schemas/item-schema.d.ts.map +1 -1
- package/lib/tools/block-tools.d.ts.map +1 -1
- package/lib/tools/entity-tools.d.ts.map +1 -1
- package/lib/tools/index.d.ts.map +1 -1
- package/lib/tools/item-tools.d.ts.map +1 -1
- package/lib/tools/result.d.ts.map +1 -1
- package/lib/tools/world-tools.d.ts.map +1 -1
- package/lib/utils/logger.d.ts.map +1 -1
- package/lib/world/block-spec.d.ts.map +1 -1
- package/lib/world/block-states.d.ts.map +1 -1
- package/lib/world/entity-inventory.d.ts.map +1 -1
- package/lib/world/item-spec.d.ts.map +1 -1
- package/lib/world/simulated-dimension.d.ts +25 -0
- package/lib/world/simulated-dimension.d.ts.map +1 -1
- package/lib/world/stores/file-world-store.d.ts +2 -2
- package/lib/world/stores/file-world-store.d.ts.map +1 -1
- package/lib/world/stores/index.d.ts.map +1 -1
- package/lib/world/stores/memory-world-store.d.ts +1 -0
- package/lib/world/stores/memory-world-store.d.ts.map +1 -1
- package/lib/world/stores/serialized-block.d.ts.map +1 -1
- package/lib/world/stores/serialized-entity.d.ts.map +1 -1
- package/lib/world/stores/serialized-snapshot.d.ts +6 -0
- package/lib/world/stores/serialized-snapshot.d.ts.map +1 -0
- package/lib/world/world.d.ts.map +1 -1
- package/package.json +116 -113
|
@@ -2,9 +2,10 @@ import * as z from 'zod/v4';
|
|
|
2
2
|
import { WORLD_LIMITS } from '../config/world-limits.js';
|
|
3
3
|
import { getEntityTypeByName } from '../data/entities.js';
|
|
4
4
|
import { EInventorySection } from '../enums/inventory-section.enum.js';
|
|
5
|
+
import { EMoveDirection } from '../enums/move-direction.enum.js';
|
|
5
6
|
import { blockPositionShape } from '../schemas/coordinate-schema.js';
|
|
6
7
|
import { dimensionField } from '../schemas/dimension-schema.js';
|
|
7
|
-
import { entityInfoSchema, inventoryChangeSchema, inventoryViewSchema, toEntityInfo, toInventoryView, toItemStackInfo } from '../schemas/entity-schema.js';
|
|
8
|
+
import { entityInfoSchema, entitySummarySchema, inventoryChangeSchema, inventoryViewSchema, itemStackSchema, toEntityInfo, toEntitySummary, toInventoryView, toItemStackInfo } from '../schemas/entity-schema.js';
|
|
8
9
|
import { toErrorMessage } from '../utils/error-message.js';
|
|
9
10
|
import { HOTBAR_SLOT_COUNT, INVENTORY_SLOT_COUNT, slotCount } from '../world/entity-inventory.js';
|
|
10
11
|
import { parseItemSpec } from '../world/item-spec.js';
|
|
@@ -13,13 +14,13 @@ const entityIdSchema = z
|
|
|
13
14
|
.string()
|
|
14
15
|
.trim()
|
|
15
16
|
.min(1)
|
|
16
|
-
.max(
|
|
17
|
+
.max(WORLD_LIMITS.maxEntityIdLength)
|
|
17
18
|
.describe('Entity UUID returned by createEntity or createPlayer');
|
|
18
19
|
const targetSchema = z
|
|
19
20
|
.string()
|
|
20
21
|
.trim()
|
|
21
22
|
.min(1)
|
|
22
|
-
.max(
|
|
23
|
+
.max(WORLD_LIMITS.maxEntityIdLength)
|
|
23
24
|
.describe('Entity UUID or player name (player names are case-insensitive)');
|
|
24
25
|
const playerNameSchema = z
|
|
25
26
|
.string()
|
|
@@ -41,6 +42,45 @@ const itemIdSchema = z
|
|
|
41
42
|
.min(1)
|
|
42
43
|
.max(256)
|
|
43
44
|
.describe('Item id, such as "minecraft:diamond_sword" or "diamond_sword". Use "minecraft:air" or count 0 to clear the slot.');
|
|
45
|
+
const entityPositionShape = {
|
|
46
|
+
x: z.number().int(),
|
|
47
|
+
y: z.number().int(),
|
|
48
|
+
z: z.number().int()
|
|
49
|
+
};
|
|
50
|
+
const entityPositionSchema = z.object({
|
|
51
|
+
id: z.string(),
|
|
52
|
+
type: z.string(),
|
|
53
|
+
name: z.string(),
|
|
54
|
+
...entityPositionShape
|
|
55
|
+
});
|
|
56
|
+
const entityMovementSchema = entityPositionSchema.extend({
|
|
57
|
+
direction: z.enum(EMoveDirection),
|
|
58
|
+
previous: z.object(entityPositionShape)
|
|
59
|
+
});
|
|
60
|
+
const entityPositionChangeSchema = entityPositionSchema.extend({
|
|
61
|
+
previous: z.object(entityPositionShape)
|
|
62
|
+
});
|
|
63
|
+
const inventoryClearSchema = inventoryViewSchema.extend({
|
|
64
|
+
clearedSlots: z.number().int()
|
|
65
|
+
});
|
|
66
|
+
const inventorySwapSchema = inventoryViewSchema.extend({
|
|
67
|
+
fromSection: z.enum(EInventorySection),
|
|
68
|
+
fromSlot: z.number().int(),
|
|
69
|
+
toSection: z.enum(EInventorySection),
|
|
70
|
+
toSlot: z.number().int(),
|
|
71
|
+
previousFrom: itemStackSchema.nullable(),
|
|
72
|
+
previousTo: itemStackSchema.nullable()
|
|
73
|
+
});
|
|
74
|
+
function toEntityPosition(entity) {
|
|
75
|
+
return {
|
|
76
|
+
id: entity.id,
|
|
77
|
+
type: entity.type.key,
|
|
78
|
+
name: entity.name,
|
|
79
|
+
x: entity.x,
|
|
80
|
+
y: entity.y,
|
|
81
|
+
z: entity.z
|
|
82
|
+
};
|
|
83
|
+
}
|
|
44
84
|
function resolveEntityType(input) {
|
|
45
85
|
const normalized = input.trim().toLowerCase();
|
|
46
86
|
return (getEntityTypeByName(normalized) ??
|
|
@@ -50,6 +90,9 @@ function resolveTarget(world, target) {
|
|
|
50
90
|
const normalized = target.trim();
|
|
51
91
|
return world.findEntity(normalized) ?? world.findPlayer(normalized);
|
|
52
92
|
}
|
|
93
|
+
function unknownTargetError(target) {
|
|
94
|
+
return toolError(`Unknown entity or player "${target}". Use an entity UUID from createEntity/createPlayer or a player name.`);
|
|
95
|
+
}
|
|
53
96
|
function text(message) {
|
|
54
97
|
return { type: 'text', text: message };
|
|
55
98
|
}
|
|
@@ -214,6 +257,161 @@ export function registerEntityTools(server, world) {
|
|
|
214
257
|
return toolError(`getPlayer failed: ${toErrorMessage(error)}`);
|
|
215
258
|
}
|
|
216
259
|
});
|
|
260
|
+
server.registerTool('deleteEntity', {
|
|
261
|
+
title: 'Delete Entity',
|
|
262
|
+
description: 'Delete one entity or player by UUID or player name. The entity is removed from its dimension and its inventory is discarded. Player names become available again after deletion.',
|
|
263
|
+
inputSchema: z.object({
|
|
264
|
+
target: targetSchema
|
|
265
|
+
}),
|
|
266
|
+
outputSchema: entitySummarySchema,
|
|
267
|
+
annotations: {
|
|
268
|
+
destructiveHint: true,
|
|
269
|
+
idempotentHint: false,
|
|
270
|
+
openWorldHint: false
|
|
271
|
+
}
|
|
272
|
+
}, async ({ target }) => {
|
|
273
|
+
try {
|
|
274
|
+
const entity = resolveTarget(world, target);
|
|
275
|
+
if (!entity) {
|
|
276
|
+
return unknownTargetError(target);
|
|
277
|
+
}
|
|
278
|
+
const dimension = world.getDimension(entity.dimension);
|
|
279
|
+
const deleted = dimension.deleteEntity(entity.id) ?? entity;
|
|
280
|
+
try {
|
|
281
|
+
await dimension.flush();
|
|
282
|
+
}
|
|
283
|
+
catch (error) {
|
|
284
|
+
return toolError(`Entity "${deleted.name}" was deleted but could not be persisted to the world store: ${toErrorMessage(error)}`);
|
|
285
|
+
}
|
|
286
|
+
return {
|
|
287
|
+
content: [
|
|
288
|
+
text(`Deleted ${deleted.kind} "${deleted.name}" (${deleted.id}, ${deleted.type.key}) from ${dimension.info.displayName}`)
|
|
289
|
+
],
|
|
290
|
+
structuredContent: toEntitySummary(deleted)
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
catch (error) {
|
|
294
|
+
return toolError(`deleteEntity failed: ${toErrorMessage(error)}`);
|
|
295
|
+
}
|
|
296
|
+
});
|
|
297
|
+
server.registerTool('moveEntity', {
|
|
298
|
+
title: 'Move Entity',
|
|
299
|
+
description: 'Move one entity or player exactly one block in a fixed direction: forward (+Z, south), back (-Z, north), left (-X, west), right (+X, east), up (+Y) or down (-Y). The destination must stay inside the entity dimension.',
|
|
300
|
+
inputSchema: z.object({
|
|
301
|
+
id: entityIdSchema,
|
|
302
|
+
direction: z
|
|
303
|
+
.enum(EMoveDirection)
|
|
304
|
+
.describe('One-block direction: forward (+Z), back (-Z), left (-X), right (+X), up (+Y), down (-Y)')
|
|
305
|
+
}),
|
|
306
|
+
outputSchema: entityMovementSchema,
|
|
307
|
+
annotations: {
|
|
308
|
+
destructiveHint: false,
|
|
309
|
+
idempotentHint: false,
|
|
310
|
+
openWorldHint: false
|
|
311
|
+
}
|
|
312
|
+
}, async ({ id, direction }) => {
|
|
313
|
+
try {
|
|
314
|
+
const entity = world.findEntity(id);
|
|
315
|
+
if (!entity) {
|
|
316
|
+
return toolError(`Unknown entity "${id}". Use an entity UUID returned by createEntity or createPlayer.`);
|
|
317
|
+
}
|
|
318
|
+
const dimension = world.getDimension(entity.dimension);
|
|
319
|
+
const { previous, entity: moved } = dimension.moveEntity(id, direction);
|
|
320
|
+
try {
|
|
321
|
+
await dimension.flush();
|
|
322
|
+
}
|
|
323
|
+
catch (error) {
|
|
324
|
+
return toolError(`Entity "${moved.name}" was moved but could not be persisted to the world store: ${toErrorMessage(error)}`);
|
|
325
|
+
}
|
|
326
|
+
return {
|
|
327
|
+
content: [
|
|
328
|
+
text(`Moved ${moved.name} (${moved.id}) ${direction} from (${previous.x}, ${previous.y}, ${previous.z}) to (${moved.x}, ${moved.y}, ${moved.z}) in ${dimension.info.displayName}`)
|
|
329
|
+
],
|
|
330
|
+
structuredContent: {
|
|
331
|
+
...toEntityPosition(moved),
|
|
332
|
+
direction,
|
|
333
|
+
previous
|
|
334
|
+
}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
return toolError(`moveEntity failed: ${toErrorMessage(error)}`);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
server.registerTool('getEntityPosition', {
|
|
342
|
+
title: 'Get Entity Position',
|
|
343
|
+
description: 'Get the UUID, entity type, name and exact x/y/z position of one entity or player.',
|
|
344
|
+
inputSchema: z.object({
|
|
345
|
+
id: entityIdSchema
|
|
346
|
+
}),
|
|
347
|
+
outputSchema: entityPositionSchema,
|
|
348
|
+
annotations: {
|
|
349
|
+
readOnlyHint: true,
|
|
350
|
+
idempotentHint: true,
|
|
351
|
+
openWorldHint: false
|
|
352
|
+
}
|
|
353
|
+
}, async ({ id }) => {
|
|
354
|
+
try {
|
|
355
|
+
const entity = world.findEntity(id);
|
|
356
|
+
if (!entity) {
|
|
357
|
+
return toolError(`Unknown entity "${id}". Use an entity UUID returned by createEntity or createPlayer.`);
|
|
358
|
+
}
|
|
359
|
+
const position = toEntityPosition(entity);
|
|
360
|
+
return {
|
|
361
|
+
content: [
|
|
362
|
+
text(`${position.name} (${position.type}, ${position.id}) is at (${position.x}, ${position.y}, ${position.z})`)
|
|
363
|
+
],
|
|
364
|
+
structuredContent: position
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
catch (error) {
|
|
368
|
+
return toolError(`getEntityPosition failed: ${toErrorMessage(error)}`);
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
server.registerTool('setEntityPosition', {
|
|
372
|
+
title: 'Set Entity Position',
|
|
373
|
+
description: 'Set the exact x/y/z position of one entity or player. The position must stay inside the entity dimension.',
|
|
374
|
+
inputSchema: z.object({
|
|
375
|
+
id: entityIdSchema,
|
|
376
|
+
position: z.object(blockPositionShape)
|
|
377
|
+
}),
|
|
378
|
+
outputSchema: entityPositionChangeSchema,
|
|
379
|
+
annotations: {
|
|
380
|
+
destructiveHint: false,
|
|
381
|
+
idempotentHint: true,
|
|
382
|
+
openWorldHint: false
|
|
383
|
+
}
|
|
384
|
+
}, async ({ id, position }) => {
|
|
385
|
+
try {
|
|
386
|
+
const entity = world.findEntity(id);
|
|
387
|
+
if (!entity) {
|
|
388
|
+
return toolError(`Unknown entity "${id}". Use an entity UUID returned by createEntity or createPlayer.`);
|
|
389
|
+
}
|
|
390
|
+
const dimension = world.getDimension(entity.dimension);
|
|
391
|
+
if (!dimension.contains(position.x, position.y, position.z)) {
|
|
392
|
+
return coordinateRangeError(dimension.info, position.x, position.y, position.z);
|
|
393
|
+
}
|
|
394
|
+
const { previous, entity: updated } = dimension.setEntityPosition(id, position.x, position.y, position.z);
|
|
395
|
+
try {
|
|
396
|
+
await dimension.flush();
|
|
397
|
+
}
|
|
398
|
+
catch (error) {
|
|
399
|
+
return toolError(`Entity "${updated.name}" was moved but could not be persisted to the world store: ${toErrorMessage(error)}`);
|
|
400
|
+
}
|
|
401
|
+
return {
|
|
402
|
+
content: [
|
|
403
|
+
text(`Set ${updated.name} (${updated.id}) position from (${previous.x}, ${previous.y}, ${previous.z}) to (${updated.x}, ${updated.y}, ${updated.z}) in ${dimension.info.displayName}`)
|
|
404
|
+
],
|
|
405
|
+
structuredContent: {
|
|
406
|
+
...toEntityPosition(updated),
|
|
407
|
+
previous
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
}
|
|
411
|
+
catch (error) {
|
|
412
|
+
return toolError(`setEntityPosition failed: ${toErrorMessage(error)}`);
|
|
413
|
+
}
|
|
414
|
+
});
|
|
217
415
|
server.registerTool('getInventory', {
|
|
218
416
|
title: 'Get Inventory',
|
|
219
417
|
description: 'Get the full inventory of an entity or player: the 9 hotbar slots and the 27 backpack slots, plus used-slot counts. Empty slots are null. The target is an entity UUID or a player name.',
|
|
@@ -230,7 +428,7 @@ export function registerEntityTools(server, world) {
|
|
|
230
428
|
try {
|
|
231
429
|
const entity = resolveTarget(world, target);
|
|
232
430
|
if (!entity) {
|
|
233
|
-
return
|
|
431
|
+
return unknownTargetError(target);
|
|
234
432
|
}
|
|
235
433
|
const view = toInventoryView(entity);
|
|
236
434
|
return {
|
|
@@ -244,6 +442,121 @@ export function registerEntityTools(server, world) {
|
|
|
244
442
|
return toolError(`getInventory failed: ${toErrorMessage(error)}`);
|
|
245
443
|
}
|
|
246
444
|
});
|
|
445
|
+
server.registerTool('clearInventory', {
|
|
446
|
+
title: 'Clear Inventory',
|
|
447
|
+
description: 'Remove every item from the 9 hotbar slots and 27 backpack slots of one entity or player. The target is an entity UUID or a player name. The cleared slot count is returned.',
|
|
448
|
+
inputSchema: z.object({
|
|
449
|
+
target: targetSchema
|
|
450
|
+
}),
|
|
451
|
+
outputSchema: inventoryClearSchema,
|
|
452
|
+
annotations: {
|
|
453
|
+
destructiveHint: true,
|
|
454
|
+
idempotentHint: true,
|
|
455
|
+
openWorldHint: false
|
|
456
|
+
}
|
|
457
|
+
}, async ({ target }) => {
|
|
458
|
+
try {
|
|
459
|
+
const entity = resolveTarget(world, target);
|
|
460
|
+
if (!entity) {
|
|
461
|
+
return unknownTargetError(target);
|
|
462
|
+
}
|
|
463
|
+
const dimension = world.getDimension(entity.dimension);
|
|
464
|
+
const { clearedSlots, entity: updated } = dimension.clearInventory(entity.id);
|
|
465
|
+
if (clearedSlots > 0) {
|
|
466
|
+
try {
|
|
467
|
+
await dimension.flush();
|
|
468
|
+
}
|
|
469
|
+
catch (error) {
|
|
470
|
+
return toolError(`The inventory of "${updated.name}" was cleared but could not be persisted to the world store: ${toErrorMessage(error)}`);
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
return {
|
|
474
|
+
content: [
|
|
475
|
+
text(clearedSlots > 0
|
|
476
|
+
? `Cleared ${clearedSlots} inventory slot(s) of "${updated.name}"`
|
|
477
|
+
: `The inventory of "${updated.name}" was already empty`)
|
|
478
|
+
],
|
|
479
|
+
structuredContent: {
|
|
480
|
+
...toInventoryView(updated),
|
|
481
|
+
clearedSlots
|
|
482
|
+
}
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
catch (error) {
|
|
486
|
+
return toolError(`clearInventory failed: ${toErrorMessage(error)}`);
|
|
487
|
+
}
|
|
488
|
+
});
|
|
489
|
+
server.registerTool('swapInventorySlots', {
|
|
490
|
+
title: 'Swap Inventory Slots',
|
|
491
|
+
description: 'Swap two inventory slots of one entity or player. section is "hotbar" (slots 0-8) or "inventory" (backpack, slots 0-26). Both slots may be in the same or different sections. The target is an entity UUID or a player name.',
|
|
492
|
+
inputSchema: z.object({
|
|
493
|
+
target: targetSchema,
|
|
494
|
+
fromSection: z
|
|
495
|
+
.enum(EInventorySection)
|
|
496
|
+
.describe('"hotbar" or "inventory" for the first slot'),
|
|
497
|
+
fromSlot: z
|
|
498
|
+
.number()
|
|
499
|
+
.int()
|
|
500
|
+
.min(0)
|
|
501
|
+
.max(INVENTORY_SLOT_COUNT - 1)
|
|
502
|
+
.describe('First slot index (hotbar 0-8, backpack 0-26)'),
|
|
503
|
+
toSection: z
|
|
504
|
+
.enum(EInventorySection)
|
|
505
|
+
.describe('"hotbar" or "inventory" for the second slot'),
|
|
506
|
+
toSlot: z
|
|
507
|
+
.number()
|
|
508
|
+
.int()
|
|
509
|
+
.min(0)
|
|
510
|
+
.max(INVENTORY_SLOT_COUNT - 1)
|
|
511
|
+
.describe('Second slot index (hotbar 0-8, backpack 0-26)')
|
|
512
|
+
}),
|
|
513
|
+
outputSchema: inventorySwapSchema,
|
|
514
|
+
annotations: {
|
|
515
|
+
destructiveHint: false,
|
|
516
|
+
idempotentHint: false,
|
|
517
|
+
openWorldHint: false
|
|
518
|
+
}
|
|
519
|
+
}, async ({ target, fromSection, fromSlot, toSection, toSlot }) => {
|
|
520
|
+
try {
|
|
521
|
+
const entity = resolveTarget(world, target);
|
|
522
|
+
if (!entity) {
|
|
523
|
+
return unknownTargetError(target);
|
|
524
|
+
}
|
|
525
|
+
const fromMax = slotCount(fromSection) - 1;
|
|
526
|
+
if (fromSlot > fromMax) {
|
|
527
|
+
return toolError(`Slot ${fromSlot} is out of range for the ${fromSection} section (0-${fromMax}).`);
|
|
528
|
+
}
|
|
529
|
+
const toMax = slotCount(toSection) - 1;
|
|
530
|
+
if (toSlot > toMax) {
|
|
531
|
+
return toolError(`Slot ${toSlot} is out of range for the ${toSection} section (0-${toMax}).`);
|
|
532
|
+
}
|
|
533
|
+
const dimension = world.getDimension(entity.dimension);
|
|
534
|
+
const { previousFrom, previousTo, entity: updated } = dimension.swapInventorySlots(entity.id, fromSection, fromSlot, toSection, toSlot);
|
|
535
|
+
try {
|
|
536
|
+
await dimension.flush();
|
|
537
|
+
}
|
|
538
|
+
catch (error) {
|
|
539
|
+
return toolError(`The inventory slots of "${updated.name}" were swapped but could not be persisted to the world store: ${toErrorMessage(error)}`);
|
|
540
|
+
}
|
|
541
|
+
return {
|
|
542
|
+
content: [
|
|
543
|
+
text(`Swapped ${fromSection} slot ${fromSlot} with ${toSection} slot ${toSlot} of "${updated.name}"`)
|
|
544
|
+
],
|
|
545
|
+
structuredContent: {
|
|
546
|
+
...toInventoryView(updated),
|
|
547
|
+
fromSection,
|
|
548
|
+
fromSlot,
|
|
549
|
+
toSection,
|
|
550
|
+
toSlot,
|
|
551
|
+
previousFrom: previousFrom ? toItemStackInfo(previousFrom) : null,
|
|
552
|
+
previousTo: previousTo ? toItemStackInfo(previousTo) : null
|
|
553
|
+
}
|
|
554
|
+
};
|
|
555
|
+
}
|
|
556
|
+
catch (error) {
|
|
557
|
+
return toolError(`swapInventorySlots failed: ${toErrorMessage(error)}`);
|
|
558
|
+
}
|
|
559
|
+
});
|
|
247
560
|
server.registerTool('setInventory', {
|
|
248
561
|
title: 'Set Inventory',
|
|
249
562
|
description: 'Set one inventory slot of an entity or player. section is "hotbar" (slots 0-8) or "inventory" (backpack, slots 0-26). The item is validated against the item registry and the count must fit the item stack size. Use "minecraft:air" or count 0 to clear a slot. The target is an entity UUID or a player name.',
|
|
@@ -278,7 +591,7 @@ export function registerEntityTools(server, world) {
|
|
|
278
591
|
try {
|
|
279
592
|
const entity = resolveTarget(world, target);
|
|
280
593
|
if (!entity) {
|
|
281
|
-
return
|
|
594
|
+
return unknownTargetError(target);
|
|
282
595
|
}
|
|
283
596
|
const maxSlot = slotCount(section) - 1;
|
|
284
597
|
if (slot > maxSlot) {
|