@lzimul/minecraft-mcp 1.0.3 → 1.0.4
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/README.md +219 -179
- package/SECURITY.md +38 -21
- package/build/config/server-info.js +3 -2
- package/build/config/world-limits.js +4 -1
- package/build/data/entities.js +1581 -0
- package/build/enums/entity-kind.enum.js +5 -0
- package/build/enums/inventory-section.enum.js +5 -0
- package/build/index.js +5 -6
- package/build/interfaces/entity-inventory.interface.js +1 -0
- package/build/interfaces/entity-type.interface.js +1 -0
- package/build/interfaces/entity.interface.js +1 -0
- package/build/resources/dimension-resources.js +23 -6
- package/build/resources/entity-resources.js +17 -0
- package/build/resources/index.js +2 -0
- package/build/schemas/coordinate-schema.js +5 -0
- package/build/schemas/dimension-schema.js +1 -0
- package/build/schemas/entity-schema.js +95 -0
- package/build/tools/block-tools.js +14 -23
- package/build/tools/entity-tools.js +325 -0
- package/build/tools/index.js +4 -0
- package/build/tools/result.js +3 -5
- package/build/tools/world-tools.js +139 -0
- package/build/utils/logger.js +53 -0
- package/build/world/block-spec.js +6 -6
- package/build/world/block-states.js +23 -4
- package/build/world/entity-inventory.js +84 -0
- package/build/world/item-spec.js +25 -0
- package/build/world/simulated-dimension.js +187 -13
- package/build/world/stores/file-world-store.js +67 -20
- package/build/world/stores/memory-world-store.js +13 -5
- package/build/world/stores/serialized-block.js +9 -14
- package/build/world/stores/serialized-entity.js +74 -0
- package/build/world/world.js +33 -1
- package/lib/config/server-info.d.ts.map +1 -1
- package/lib/config/world-limits.d.ts +3 -0
- package/lib/config/world-limits.d.ts.map +1 -1
- package/lib/data/entities.d.ts +5 -0
- package/lib/data/entities.d.ts.map +1 -0
- package/lib/enums/entity-kind.enum.d.ts +5 -0
- package/lib/enums/entity-kind.enum.d.ts.map +1 -0
- package/lib/enums/inventory-section.enum.d.ts +5 -0
- package/lib/enums/inventory-section.enum.d.ts.map +1 -0
- package/lib/interfaces/entity-inventory.interface.d.ts +9 -0
- package/lib/interfaces/entity-inventory.interface.d.ts.map +1 -0
- package/lib/interfaces/entity-type.interface.d.ts +8 -0
- package/lib/interfaces/entity-type.interface.d.ts.map +1 -0
- package/lib/interfaces/entity.interface.d.ts +17 -0
- package/lib/interfaces/entity.interface.d.ts.map +1 -0
- package/lib/interfaces/world-store.interface.d.ts +7 -2
- package/lib/interfaces/world-store.interface.d.ts.map +1 -1
- package/lib/resources/dimension-resources.d.ts.map +1 -1
- package/lib/resources/entity-resources.d.ts +3 -0
- package/lib/resources/entity-resources.d.ts.map +1 -0
- package/lib/resources/index.d.ts.map +1 -1
- package/lib/schemas/coordinate-schema.d.ts +5 -0
- package/lib/schemas/coordinate-schema.d.ts.map +1 -1
- package/lib/schemas/dimension-schema.d.ts +1 -0
- package/lib/schemas/dimension-schema.d.ts.map +1 -1
- package/lib/schemas/entity-schema.d.ts +134 -0
- package/lib/schemas/entity-schema.d.ts.map +1 -0
- package/lib/tools/block-tools.d.ts.map +1 -1
- package/lib/tools/entity-tools.d.ts +4 -0
- package/lib/tools/entity-tools.d.ts.map +1 -0
- package/lib/tools/index.d.ts.map +1 -1
- package/lib/tools/result.d.ts +2 -6
- package/lib/tools/result.d.ts.map +1 -1
- package/lib/tools/world-tools.d.ts +4 -0
- package/lib/tools/world-tools.d.ts.map +1 -0
- package/lib/utils/logger.d.ts +3 -0
- package/lib/utils/logger.d.ts.map +1 -0
- package/lib/world/block-states.d.ts +2 -0
- package/lib/world/block-states.d.ts.map +1 -1
- package/lib/world/entity-inventory.d.ts +16 -0
- package/lib/world/entity-inventory.d.ts.map +1 -0
- package/lib/world/item-spec.d.ts +10 -0
- package/lib/world/item-spec.d.ts.map +1 -0
- package/lib/world/simulated-dimension.d.ts +29 -0
- package/lib/world/simulated-dimension.d.ts.map +1 -1
- package/lib/world/stores/file-world-store.d.ts +3 -3
- package/lib/world/stores/file-world-store.d.ts.map +1 -1
- package/lib/world/stores/memory-world-store.d.ts +3 -4
- 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 +24 -0
- package/lib/world/stores/serialized-entity.d.ts.map +1 -0
- package/lib/world/world.d.ts +3 -0
- package/lib/world/world.d.ts.map +1 -1
- package/package.json +113 -109
package/build/index.js
CHANGED
|
@@ -3,13 +3,12 @@ import { serveStdio } from '@modelcontextprotocol/server/stdio';
|
|
|
3
3
|
import { createServer } from './app/server.js';
|
|
4
4
|
import { WORLD_STORAGE } from './config/storage.js';
|
|
5
5
|
import { toErrorMessage } from './utils/error-message.js';
|
|
6
|
+
import { logger } from './utils/logger.js';
|
|
6
7
|
import { createWorldStore } from './world/stores/index.js';
|
|
7
8
|
import { World } from './world/world.js';
|
|
8
9
|
async function main() {
|
|
9
10
|
const world = await World.load(createWorldStore(), WORLD_STORAGE.writeDelayMs);
|
|
10
|
-
const handle = serveStdio(() => createServer(world)
|
|
11
|
-
legacy: 'reject'
|
|
12
|
-
});
|
|
11
|
+
const handle = serveStdio(() => createServer(world));
|
|
13
12
|
let shuttingDown = false;
|
|
14
13
|
const shutdown = async (exitCode) => {
|
|
15
14
|
if (shuttingDown) {
|
|
@@ -21,14 +20,14 @@ async function main() {
|
|
|
21
20
|
await world.flush();
|
|
22
21
|
}
|
|
23
22
|
catch (error) {
|
|
24
|
-
|
|
23
|
+
logger.error(`Failed to flush world state on shutdown: ${toErrorMessage(error)}`);
|
|
25
24
|
code = 1;
|
|
26
25
|
}
|
|
27
26
|
try {
|
|
28
27
|
await handle.close();
|
|
29
28
|
}
|
|
30
29
|
catch (error) {
|
|
31
|
-
|
|
30
|
+
logger.error(`Failed to close the MCP transport: ${toErrorMessage(error)}`);
|
|
32
31
|
code = 1;
|
|
33
32
|
}
|
|
34
33
|
process.exit(code);
|
|
@@ -44,6 +43,6 @@ try {
|
|
|
44
43
|
await main();
|
|
45
44
|
}
|
|
46
45
|
catch (error) {
|
|
47
|
-
|
|
46
|
+
logger.error(`Fatal: ${toErrorMessage(error)}`);
|
|
48
47
|
process.exitCode = 1;
|
|
49
48
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import { toBlockInfo } from '../schemas/block-schema.js';
|
|
2
|
+
import { toEntityInfo } from '../schemas/entity-schema.js';
|
|
2
3
|
import { errorResource } from './error-content.js';
|
|
3
4
|
import { World } from '../world/world.js';
|
|
5
|
+
function dimensionSummary(world, dimension) {
|
|
6
|
+
const simulated = world.getDimension(dimension.type);
|
|
7
|
+
return {
|
|
8
|
+
key: dimension.key,
|
|
9
|
+
type: dimension.type,
|
|
10
|
+
displayName: dimension.displayName,
|
|
11
|
+
minY: dimension.minY,
|
|
12
|
+
maxY: dimension.maxY,
|
|
13
|
+
hasSkylight: dimension.hasSkylight,
|
|
14
|
+
modifiedBlockCount: simulated.modifiedBlockCount,
|
|
15
|
+
entityCount: simulated.entityCount,
|
|
16
|
+
playerCount: simulated.playerCount,
|
|
17
|
+
uri: `lzimul://minecraft/dimensions/${dimension.type}`
|
|
18
|
+
};
|
|
19
|
+
}
|
|
4
20
|
function dimensionState(world, dimension) {
|
|
5
21
|
const simulated = world.getDimension(dimension.type);
|
|
6
22
|
return {
|
|
@@ -11,21 +27,22 @@ function dimensionState(world, dimension) {
|
|
|
11
27
|
maxY: dimension.maxY,
|
|
12
28
|
hasSkylight: dimension.hasSkylight,
|
|
13
29
|
modifiedBlockCount: simulated.modifiedBlockCount,
|
|
14
|
-
|
|
15
|
-
|
|
30
|
+
entityCount: simulated.entityCount,
|
|
31
|
+
playerCount: simulated.playerCount,
|
|
32
|
+
placedBlocks: simulated.sortedPlacedBlocks.map(placed => ({
|
|
16
33
|
x: placed.x,
|
|
17
34
|
y: placed.y,
|
|
18
35
|
z: placed.z,
|
|
19
36
|
block: toBlockInfo(placed.block),
|
|
20
37
|
states: placed.states
|
|
21
|
-
}))
|
|
22
|
-
|
|
38
|
+
})),
|
|
39
|
+
entities: simulated.sortedPlacedEntities.map(toEntityInfo)
|
|
23
40
|
};
|
|
24
41
|
}
|
|
25
42
|
export function registerDimensionIndexResource(server, world) {
|
|
26
43
|
server.registerResource('minecraft/dimensions', 'lzimul://minecraft/dimensions', {
|
|
27
44
|
title: 'Minecraft Dimension List',
|
|
28
|
-
description: 'Index of the persisted Minecraft dimensions',
|
|
45
|
+
description: 'Index of the persisted Minecraft dimensions with their block counts (read the per-dimension resource for placed blocks)',
|
|
29
46
|
mimeType: 'application/json'
|
|
30
47
|
}, async (uri) => {
|
|
31
48
|
try {
|
|
@@ -34,7 +51,7 @@ export function registerDimensionIndexResource(server, world) {
|
|
|
34
51
|
{
|
|
35
52
|
uri: uri.href,
|
|
36
53
|
mimeType: 'application/json',
|
|
37
|
-
text: JSON.stringify(World.listDimensions().map(dimension =>
|
|
54
|
+
text: JSON.stringify(World.listDimensions().map(dimension => dimensionSummary(world, dimension)), null, 2)
|
|
38
55
|
}
|
|
39
56
|
]
|
|
40
57
|
};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MINECRAFT_ENTITY_COUNT, MINECRAFT_ENTITY_TYPES } from '../data/entities.js';
|
|
2
|
+
import { MINECRAFT_DATA_VERSION } from '../data/version.js';
|
|
3
|
+
import { registerDataEntryResources, registerDataIndexResource } from './data-resources.js';
|
|
4
|
+
export function registerEntityResources(server) {
|
|
5
|
+
registerDataIndexResource(server, {
|
|
6
|
+
name: 'minecraft/entities',
|
|
7
|
+
uri: 'lzimul://minecraft/entities',
|
|
8
|
+
title: 'Minecraft Entity Type List',
|
|
9
|
+
description: `Index of all ${MINECRAFT_ENTITY_COUNT} Minecraft entity types (Java Edition ${MINECRAFT_DATA_VERSION})`,
|
|
10
|
+
entries: MINECRAFT_ENTITY_TYPES
|
|
11
|
+
});
|
|
12
|
+
registerDataEntryResources(server, {
|
|
13
|
+
pathPrefix: 'entities',
|
|
14
|
+
category: 'entity type',
|
|
15
|
+
entries: MINECRAFT_ENTITY_TYPES
|
|
16
|
+
});
|
|
17
|
+
}
|
package/build/resources/index.js
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { registerBlockResources } from './block-resources.js';
|
|
2
2
|
import { registerDimensionIndexResource, registerDimensionResources } from './dimension-resources.js';
|
|
3
|
+
import { registerEntityResources } from './entity-resources.js';
|
|
3
4
|
import { registerItemResources } from './item-resources.js';
|
|
4
5
|
export function registerResources(server, world) {
|
|
5
6
|
registerBlockResources(server);
|
|
6
7
|
registerItemResources(server);
|
|
8
|
+
registerEntityResources(server);
|
|
7
9
|
registerDimensionIndexResource(server, world);
|
|
8
10
|
registerDimensionResources(server, world);
|
|
9
11
|
}
|
|
@@ -10,3 +10,8 @@ export const verticalCoordinate = z
|
|
|
10
10
|
.int()
|
|
11
11
|
.min(WORLD_LIMITS.minVertical)
|
|
12
12
|
.max(WORLD_LIMITS.maxVertical);
|
|
13
|
+
export const blockPositionShape = {
|
|
14
|
+
x: horizontalCoordinate.describe('X coordinate (-30000000 to 30000000)'),
|
|
15
|
+
y: verticalCoordinate.describe('Y coordinate, within the dimension height range'),
|
|
16
|
+
z: horizontalCoordinate.describe('Z coordinate (-30000000 to 30000000)')
|
|
17
|
+
};
|
|
@@ -4,3 +4,4 @@ export const dimensionSchema = z
|
|
|
4
4
|
.enum(EDimensionType)
|
|
5
5
|
.default(EDimensionType.Overworld);
|
|
6
6
|
export const dimensionTypeSchema = z.enum(EDimensionType);
|
|
7
|
+
export const dimensionField = dimensionSchema.describe('Dimension: "overworld" (default), "the_nether" or "the_end"');
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import * as z from 'zod/v4';
|
|
2
|
+
import { EEntityKind } from '../enums/entity-kind.enum.js';
|
|
3
|
+
import { EInventorySection } from '../enums/inventory-section.enum.js';
|
|
4
|
+
import { HOTBAR_SLOT_COUNT, INVENTORY_SLOT_COUNT, inventoryUsedSlots, sectionUsedSlots, TOTAL_SLOT_COUNT } from '../world/entity-inventory.js';
|
|
5
|
+
export const itemStackSchema = z.object({
|
|
6
|
+
item: z.string(),
|
|
7
|
+
count: z.number().int().min(1)
|
|
8
|
+
});
|
|
9
|
+
export const entityInventorySchema = z.object({
|
|
10
|
+
hotbar: z.array(itemStackSchema.nullable()),
|
|
11
|
+
inventory: z.array(itemStackSchema.nullable())
|
|
12
|
+
});
|
|
13
|
+
export const entitySummarySchema = z.object({
|
|
14
|
+
id: z.string(),
|
|
15
|
+
kind: z.enum(EEntityKind),
|
|
16
|
+
type: z.string(),
|
|
17
|
+
typeDisplayName: z.string(),
|
|
18
|
+
category: z.string(),
|
|
19
|
+
name: z.string(),
|
|
20
|
+
x: z.number(),
|
|
21
|
+
y: z.number(),
|
|
22
|
+
z: z.number(),
|
|
23
|
+
dimension: z.string()
|
|
24
|
+
});
|
|
25
|
+
export const entityInfoSchema = entitySummarySchema.extend({
|
|
26
|
+
createdAt: z.string(),
|
|
27
|
+
usedSlots: z.number().int(),
|
|
28
|
+
totalSlots: z.number().int(),
|
|
29
|
+
inventory: entityInventorySchema
|
|
30
|
+
});
|
|
31
|
+
export const inventoryViewSchema = z.object({
|
|
32
|
+
entity: entitySummarySchema,
|
|
33
|
+
hotbar: z.array(itemStackSchema.nullable()),
|
|
34
|
+
inventory: z.array(itemStackSchema.nullable()),
|
|
35
|
+
hotbarUsed: z.number().int(),
|
|
36
|
+
inventoryUsed: z.number().int(),
|
|
37
|
+
usedSlots: z.number().int(),
|
|
38
|
+
totalSlots: z.number().int()
|
|
39
|
+
});
|
|
40
|
+
export const inventoryChangeSchema = inventoryViewSchema.extend({
|
|
41
|
+
section: z.enum(EInventorySection),
|
|
42
|
+
slot: z.number().int(),
|
|
43
|
+
previous: itemStackSchema.nullable(),
|
|
44
|
+
item: itemStackSchema.nullable()
|
|
45
|
+
});
|
|
46
|
+
export function toItemStackInfo(stack) {
|
|
47
|
+
return { item: stack.item, count: stack.count };
|
|
48
|
+
}
|
|
49
|
+
function toNullableItemStackInfo(stack) {
|
|
50
|
+
return stack ? toItemStackInfo(stack) : null;
|
|
51
|
+
}
|
|
52
|
+
export function toEntityInventoryInfo(entity) {
|
|
53
|
+
return {
|
|
54
|
+
hotbar: entity.inventory.hotbar.map(toNullableItemStackInfo),
|
|
55
|
+
inventory: entity.inventory.inventory.map(toNullableItemStackInfo)
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
export function toEntitySummary(entity) {
|
|
59
|
+
return {
|
|
60
|
+
id: entity.id,
|
|
61
|
+
kind: entity.kind,
|
|
62
|
+
type: entity.type.key,
|
|
63
|
+
typeDisplayName: entity.type.displayName,
|
|
64
|
+
category: entity.type.category,
|
|
65
|
+
name: entity.name,
|
|
66
|
+
x: entity.x,
|
|
67
|
+
y: entity.y,
|
|
68
|
+
z: entity.z,
|
|
69
|
+
dimension: entity.dimension
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
export function toEntityInfo(entity) {
|
|
73
|
+
return {
|
|
74
|
+
...toEntitySummary(entity),
|
|
75
|
+
createdAt: entity.createdAt,
|
|
76
|
+
usedSlots: inventoryUsedSlots(entity.inventory),
|
|
77
|
+
totalSlots: TOTAL_SLOT_COUNT,
|
|
78
|
+
inventory: toEntityInventoryInfo(entity)
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
export function toInventoryView(entity) {
|
|
82
|
+
return {
|
|
83
|
+
entity: toEntitySummary(entity),
|
|
84
|
+
hotbar: entity.inventory.hotbar.map(toNullableItemStackInfo),
|
|
85
|
+
inventory: entity.inventory.inventory.map(toNullableItemStackInfo),
|
|
86
|
+
hotbarUsed: sectionUsedSlots(entity.inventory, EInventorySection.Hotbar),
|
|
87
|
+
inventoryUsed: sectionUsedSlots(entity.inventory, EInventorySection.Inventory),
|
|
88
|
+
usedSlots: inventoryUsedSlots(entity.inventory),
|
|
89
|
+
totalSlots: TOTAL_SLOT_COUNT
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export const INVENTORY_LIMITS = {
|
|
93
|
+
hotbar: HOTBAR_SLOT_COUNT,
|
|
94
|
+
inventory: INVENTORY_SLOT_COUNT
|
|
95
|
+
};
|
|
@@ -1,25 +1,20 @@
|
|
|
1
1
|
import * as z from 'zod/v4';
|
|
2
2
|
import { WORLD_LIMITS } from '../config/world-limits.js';
|
|
3
3
|
import { blockInfoSchema, toBlockInfo } from '../schemas/block-schema.js';
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import { blockPositionShape } from '../schemas/coordinate-schema.js';
|
|
5
|
+
import { dimensionField } from '../schemas/dimension-schema.js';
|
|
6
6
|
import { toErrorMessage } from '../utils/error-message.js';
|
|
7
7
|
import { formatStates } from '../world/block-states.js';
|
|
8
8
|
import { parseBlockSpec } from '../world/block-spec.js';
|
|
9
|
-
import { toolError } from './result.js';
|
|
9
|
+
import { coordinateRangeError, toolError } from './result.js';
|
|
10
10
|
const blockStatesSchema = z.record(z.string(), z.string());
|
|
11
|
-
function rangeError(dimension, x, y, z) {
|
|
12
|
-
return toolError(`Coordinates (${x}, ${y}, ${z}) are out of range in ${dimension.displayName} (Y: ${dimension.minY} to ${dimension.maxY - 1}).`);
|
|
13
|
-
}
|
|
14
11
|
export function registerBlockTools(server, world) {
|
|
15
12
|
server.registerTool('getBlock', {
|
|
16
13
|
title: 'Get Block',
|
|
17
14
|
description: 'Get the block at the given coordinates in the given dimension, including its properties (name, hardness, light level, etc.) and its block states (for example facing=south). Each dimension has its own persisted world state; unmodified coordinates return air (minecraft:air).',
|
|
18
15
|
inputSchema: z.object({
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
z: horizontalCoordinate.describe('Z coordinate (-30000000 to 30000000)'),
|
|
22
|
-
dimension: dimensionSchema.describe('Dimension: "overworld" (default), "the_nether" or "the_end"')
|
|
16
|
+
...blockPositionShape,
|
|
17
|
+
dimension: dimensionField
|
|
23
18
|
}),
|
|
24
19
|
outputSchema: z.object({
|
|
25
20
|
x: z.number(),
|
|
@@ -38,10 +33,9 @@ export function registerBlockTools(server, world) {
|
|
|
38
33
|
try {
|
|
39
34
|
const dimension = world.getDimension(dimensionType);
|
|
40
35
|
if (!dimension.contains(x, y, z)) {
|
|
41
|
-
return
|
|
36
|
+
return coordinateRangeError(dimension.info, x, y, z);
|
|
42
37
|
}
|
|
43
|
-
const block = dimension.
|
|
44
|
-
const states = dimension.getStates(x, y, z);
|
|
38
|
+
const { block, states } = dimension.getBlockState(x, y, z);
|
|
45
39
|
return {
|
|
46
40
|
content: [
|
|
47
41
|
{
|
|
@@ -67,15 +61,13 @@ export function registerBlockTools(server, world) {
|
|
|
67
61
|
title: 'Set Block',
|
|
68
62
|
description: 'Place a block at the given coordinates in the given dimension and return the replaced block. Block states are supported: "minecraft:oak_stairs[facing=south,half=bottom]" or "oak_stairs[facing=south]". Each dimension has its own persisted world state; setting air removes the block. blockType is a block id such as "minecraft:stone" or "stone"; see the resource lzimul://minecraft/blocks for the full list.',
|
|
69
63
|
inputSchema: z.object({
|
|
70
|
-
|
|
71
|
-
y: verticalCoordinate.describe('Y coordinate, within the dimension height range'),
|
|
72
|
-
z: horizontalCoordinate.describe('Z coordinate (-30000000 to 30000000)'),
|
|
64
|
+
...blockPositionShape,
|
|
73
65
|
blockType: z
|
|
74
66
|
.string()
|
|
75
67
|
.min(1)
|
|
76
68
|
.max(256)
|
|
77
69
|
.describe('Block id with optional states, such as "minecraft:stone" or "minecraft:oak_stairs[facing=south]"'),
|
|
78
|
-
dimension:
|
|
70
|
+
dimension: dimensionField
|
|
79
71
|
}),
|
|
80
72
|
outputSchema: z.object({
|
|
81
73
|
x: z.number(),
|
|
@@ -96,7 +88,7 @@ export function registerBlockTools(server, world) {
|
|
|
96
88
|
try {
|
|
97
89
|
const dimension = world.getDimension(dimensionType);
|
|
98
90
|
if (!dimension.contains(x, y, z)) {
|
|
99
|
-
return
|
|
91
|
+
return coordinateRangeError(dimension.info, x, y, z);
|
|
100
92
|
}
|
|
101
93
|
const spec = parseBlockSpec(blockType);
|
|
102
94
|
if (!spec.ok) {
|
|
@@ -110,8 +102,7 @@ export function registerBlockTools(server, world) {
|
|
|
110
102
|
if (!isAir && !dimension.canSetBlock(x, y, z)) {
|
|
111
103
|
return toolError(`The ${dimension.info.displayName} world already holds the maximum of ${WORLD_LIMITS.maxModifiedBlocks} modified blocks. Remove blocks with "minecraft:air" before adding more.`);
|
|
112
104
|
}
|
|
113
|
-
const
|
|
114
|
-
const previousStates = dimension.getStates(x, y, z);
|
|
105
|
+
const previous = dimension.getBlockState(x, y, z);
|
|
115
106
|
dimension.setBlock(x, y, z, spec.block, spec.states);
|
|
116
107
|
try {
|
|
117
108
|
await dimension.flush();
|
|
@@ -123,7 +114,7 @@ export function registerBlockTools(server, world) {
|
|
|
123
114
|
content: [
|
|
124
115
|
{
|
|
125
116
|
type: 'text',
|
|
126
|
-
text: `Block set at (${x}, ${y}, ${z}) in ${dimension.info.displayName}: ${
|
|
117
|
+
text: `Block set at (${x}, ${y}, ${z}) in ${dimension.info.displayName}: ${previous.block.displayName} (${previous.block.key})${formatStates(previous.states)} -> ${spec.block.displayName} (${spec.block.key})${formatStates(spec.states)}`
|
|
127
118
|
}
|
|
128
119
|
],
|
|
129
120
|
structuredContent: {
|
|
@@ -133,8 +124,8 @@ export function registerBlockTools(server, world) {
|
|
|
133
124
|
dimension: dimension.info.key,
|
|
134
125
|
block: toBlockInfo(spec.block),
|
|
135
126
|
states: spec.states,
|
|
136
|
-
previous: toBlockInfo(
|
|
137
|
-
previousStates
|
|
127
|
+
previous: toBlockInfo(previous.block),
|
|
128
|
+
previousStates: previous.states
|
|
138
129
|
}
|
|
139
130
|
};
|
|
140
131
|
}
|