yeow-api 0.2.107 → 0.2.109
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/package.json +1 -1
- package/src/block.ts +64 -14
- package/src/core.ts +3 -2
- package/src/event.ts +13 -2
- package/src/material.ts +31 -1
- package/src/server.ts +0 -2
- package/src/world.ts +25 -10
package/package.json
CHANGED
package/src/block.ts
CHANGED
|
@@ -2,32 +2,82 @@ import { call, post } from './task.js';
|
|
|
2
2
|
import type { TaskOptions } from './task.js';
|
|
3
3
|
import { Location } from './location.js';
|
|
4
4
|
import type { ItemStack } from './item.js';
|
|
5
|
+
import { Material } from './material.js';
|
|
5
6
|
|
|
7
|
+
/** 方块状态(Minecraft 原版键值对枚举,值统一为字符串)。 */
|
|
8
|
+
export interface BlockState {
|
|
9
|
+
[key: string]: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Block —— 方块数据描述符 + 可选的世界位置(location)。
|
|
14
|
+
* 对应 Minecraft 原版的方块概念:类型 + 方块状态(键值对枚举,如
|
|
15
|
+
* `facing`、`waterlogged`、`level` 等,值统一为字符串)。
|
|
16
|
+
*
|
|
17
|
+
* **静态数据语义**:`type` / `state` / `location` 均为**获取时刻的快照**,
|
|
18
|
+
* 之后世界变化不会自动更新;需要最新状态请重新调用 `world.getBlock`。
|
|
19
|
+
*
|
|
20
|
+
* 两种来源:
|
|
21
|
+
* - `Block.of(type, state?)` —— 纯数据描述符,无 location(用于放置/比较)
|
|
22
|
+
* - `world.getBlock(x, y, z)` —— 世界中的方块,带 location(yaw/pitch 忽略,为 0)
|
|
23
|
+
*/
|
|
6
24
|
export class Block {
|
|
7
25
|
constructor(
|
|
8
|
-
public readonly world: string,
|
|
9
|
-
public readonly x: number,
|
|
10
|
-
public readonly y: number,
|
|
11
|
-
public readonly z: number,
|
|
12
26
|
public readonly type: string,
|
|
27
|
+
public readonly state?: BlockState,
|
|
28
|
+
/** 世界位置(由 world.getBlock 返回时存在;yaw/pitch 恒为 0)。 */
|
|
29
|
+
public readonly location?: Location,
|
|
13
30
|
) {}
|
|
14
31
|
|
|
15
|
-
|
|
16
|
-
return new
|
|
32
|
+
static of(type: string, state?: BlockState): Block {
|
|
33
|
+
return new Block(type, state);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** 派生一个带状态的新描述符(原对象不变)。 */
|
|
37
|
+
withState(state: BlockState): Block {
|
|
38
|
+
return new Block(this.type, { ...(this.state ?? {}), ...state }, this.location);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 是否与给定类型/状态相同(忽略空状态差异)。 */
|
|
42
|
+
matches(type: string, state?: BlockState): boolean {
|
|
43
|
+
if (this.type !== type) return false;
|
|
44
|
+
if (!state || Object.keys(state).length === 0) return true;
|
|
45
|
+
const s = this.state ?? {};
|
|
46
|
+
for (const [k, v] of Object.entries(state)) {
|
|
47
|
+
if (s[k] !== v) return false;
|
|
48
|
+
}
|
|
49
|
+
return true;
|
|
17
50
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
51
|
+
|
|
52
|
+
// ── 材料级静态判断(基于类型,委托 Material;不依赖位置/状态)──
|
|
53
|
+
|
|
54
|
+
isSolid(options?: TaskOptions): Promise<boolean> { return Material.isSolid(this.type, options); }
|
|
55
|
+
isSolidSync(options?: TaskOptions): boolean { return Material.isSolidSync(this.type, options); }
|
|
56
|
+
isLiquid(options?: TaskOptions): Promise<boolean> { return Material.isLiquid(this.type, options); }
|
|
57
|
+
isLiquidSync(options?: TaskOptions): boolean { return Material.isLiquidSync(this.type, options); }
|
|
58
|
+
isAir(options?: TaskOptions): Promise<boolean> { return Material.isAir(this.type, options); }
|
|
59
|
+
isAirSync(options?: TaskOptions): boolean { return Material.isAirSync(this.type, options); }
|
|
60
|
+
|
|
61
|
+
// ── 世界操作(需要 location)──
|
|
62
|
+
|
|
63
|
+
private get pos(): { world: string; x: number; y: number; z: number } | null {
|
|
64
|
+
const l = this.location;
|
|
65
|
+
if (!l || l.world === undefined) return null;
|
|
66
|
+
return { world: l.world, x: l.x, y: l.y, z: l.z };
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** 按该方块的位置自然破坏并掉落物品(需要 location)。 */
|
|
24
70
|
breakNaturally(tool?: ItemStack, options?: TaskOptions): Promise<boolean> {
|
|
25
|
-
const
|
|
71
|
+
const pos = this.pos;
|
|
72
|
+
if (!pos) return Promise.reject(new Error('block has no location (create with world.getBlock)'));
|
|
73
|
+
const p: Record<string, unknown> = { ...pos };
|
|
26
74
|
if (tool) p.item = tool;
|
|
27
75
|
return post<boolean>('block.breakNaturally', p, options);
|
|
28
76
|
}
|
|
29
77
|
breakNaturallySync(tool?: ItemStack, options?: TaskOptions): boolean {
|
|
30
|
-
const
|
|
78
|
+
const pos = this.pos;
|
|
79
|
+
if (!pos) throw new Error('block has no location (create with world.getBlock)');
|
|
80
|
+
const p: Record<string, unknown> = { ...pos };
|
|
31
81
|
if (tool) p.item = tool;
|
|
32
82
|
return call<boolean>('block.breakNaturally', p, options);
|
|
33
83
|
}
|
package/src/core.ts
CHANGED
|
@@ -9,6 +9,7 @@ export type { ChunkData } from './chunk.js';
|
|
|
9
9
|
export { Entity, LivingEntity } from './entity.js';
|
|
10
10
|
export type { BoundingBox } from './entity.js';
|
|
11
11
|
export { Block } from './block.js';
|
|
12
|
+
export type { BlockState } from './block.js';
|
|
12
13
|
export { Inventory } from './inventory.js';
|
|
13
14
|
export { registerCommand } from './command.js';
|
|
14
15
|
export type { CommandOptions, CommandPayload, CommandSender, ManualCompleter } from './command.js';
|
|
@@ -31,7 +32,7 @@ export type {
|
|
|
31
32
|
export { onInit, onLoad, onUnload } from './lifecycle.js';
|
|
32
33
|
export {
|
|
33
34
|
broadcast, broadcastSync, dispatchCommand, dispatchCommandSync,
|
|
34
|
-
setMotd, setMotdSync,
|
|
35
|
+
setMotd, setMotdSync,
|
|
35
36
|
getMotd, getMotdSync, getVersion, getVersionSync,
|
|
36
37
|
getTps, getTpsSync, getMaxPlayers, getMaxPlayersSync,
|
|
37
38
|
} from './server.js';
|
|
@@ -84,7 +85,7 @@ export { createBoard as createScoreboard, deleteBoard as deleteScoreboard,
|
|
|
84
85
|
setTeamFriendlyFire, setTeamSeeInvisible, setTeamOption,
|
|
85
86
|
teamAddEntry, teamRemoveEntry, teamGetEntries,
|
|
86
87
|
setPlayerBoard } from './scoreboard.js';
|
|
87
|
-
export { getMaterials, getBlocks, getItems } from './material.js';
|
|
88
|
+
export { Material, getMaterials, getBlocks, getItems } from './material.js';
|
|
88
89
|
export type { MaterialInfo } from './material.js';
|
|
89
90
|
export { registerService, registerNativeService, request as serviceRequest, subscribe as serviceSubscribe, publish as servicePublish } from './service.js';
|
|
90
91
|
export type { ServiceResult, NativeServiceResult } from './service.js';
|
package/src/event.ts
CHANGED
|
@@ -151,10 +151,18 @@ export interface InventoryCloseEvent {
|
|
|
151
151
|
}
|
|
152
152
|
export interface ServerPingEvent {
|
|
153
153
|
address: string;
|
|
154
|
+
/** 当前在线人数。handler 可返回 `{ numPlayers: <number> }` 覆盖该次 ping 响应显示的在线人数——**不建议修改**(伪装在线人数可能违反服务器列表政策)。 */
|
|
154
155
|
numPlayers: number;
|
|
156
|
+
/** 最大玩家数。handler 可返回 `{ maxPlayers: <number> }` 覆盖该次 ping 响应显示的最大玩家数——**不建议修改**(仅影响显示,不改变实际进入限制)。 */
|
|
155
157
|
maxPlayers: number;
|
|
158
|
+
/** MOTD 文本。handler 可返回 `{ motd: "<text>" }` 覆盖该次 ping 响应的 MOTD。 */
|
|
156
159
|
motd: string;
|
|
157
160
|
cancelled?: boolean;
|
|
161
|
+
/**
|
|
162
|
+
* handler 可返回 `{ icon: "<PNG base64>" }` 修改服务器列表图标
|
|
163
|
+
* (自动缩放至 64×64;无效图片忽略,保持原图标)。
|
|
164
|
+
*/
|
|
165
|
+
icon?: string;
|
|
158
166
|
}
|
|
159
167
|
export interface PlayerTeleportEvent {
|
|
160
168
|
player: Player;
|
|
@@ -344,7 +352,7 @@ function adaptEvent<K extends keyof EventMap>(type: K, data: RawEvent): EventMap
|
|
|
344
352
|
|
|
345
353
|
// ── Event Subscription ─────────────────────────────────────────────
|
|
346
354
|
|
|
347
|
-
type EventHandler<K extends keyof EventMap> = (e: EventMap[K]) =>
|
|
355
|
+
type EventHandler<K extends keyof EventMap> = (e: EventMap[K]) => unknown;
|
|
348
356
|
type ManualHandler<K extends keyof EventMap> = (
|
|
349
357
|
e: EventMap[K],
|
|
350
358
|
complete: (result?: Record<string, unknown>) => void,
|
|
@@ -394,7 +402,10 @@ export function eventOn<K extends keyof EventMap>(
|
|
|
394
402
|
}
|
|
395
403
|
|
|
396
404
|
const result = (handler as EventHandler<typeof eventType>)(wrapped);
|
|
397
|
-
const mods
|
|
405
|
+
const mods: Record<string, unknown> = {
|
|
406
|
+
...(result && typeof result === 'object' ? result : {}),
|
|
407
|
+
};
|
|
408
|
+
if (localMods.cancelled) mods.cancelled = true;
|
|
398
409
|
$send('task', { type: 'event.complete', params: { callbackId: cbId, mods }, cb: '' });
|
|
399
410
|
}, { persistent: true });
|
|
400
411
|
|
package/src/material.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { post } from './task.js';
|
|
1
|
+
import { call, post } from './task.js';
|
|
2
2
|
import type { TaskOptions } from './task.js';
|
|
3
3
|
|
|
4
4
|
export interface MaterialInfo {
|
|
@@ -34,3 +34,33 @@ export async function getItems(options?: TaskOptions): Promise<string[]> {
|
|
|
34
34
|
Object.freeze(_items);
|
|
35
35
|
return _items;
|
|
36
36
|
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Material —— 材料级静态判断对象(不依赖坐标/状态)。
|
|
40
|
+
* 基于方块类型(material)判断其固有属性:固体/液体/空气。
|
|
41
|
+
*/
|
|
42
|
+
export const Material = {
|
|
43
|
+
/** 是否为固体方块(基于类型,状态不影响)。 */
|
|
44
|
+
isSolid(type: string, options?: TaskOptions): Promise<boolean> {
|
|
45
|
+
return post<boolean>('material.isSolid', { type }, options);
|
|
46
|
+
},
|
|
47
|
+
isSolidSync(type: string, options?: TaskOptions): boolean {
|
|
48
|
+
return call<boolean>('material.isSolid', { type }, options);
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/** 是否为液体(水 / 熔岩)。 */
|
|
52
|
+
isLiquid(type: string, options?: TaskOptions): Promise<boolean> {
|
|
53
|
+
return post<boolean>('material.isLiquid', { type }, options);
|
|
54
|
+
},
|
|
55
|
+
isLiquidSync(type: string, options?: TaskOptions): boolean {
|
|
56
|
+
return call<boolean>('material.isLiquid', { type }, options);
|
|
57
|
+
},
|
|
58
|
+
|
|
59
|
+
/** 是否为空气(空方块)。 */
|
|
60
|
+
isAir(type: string, options?: TaskOptions): Promise<boolean> {
|
|
61
|
+
return post<boolean>('material.isAir', { type }, options);
|
|
62
|
+
},
|
|
63
|
+
isAirSync(type: string, options?: TaskOptions): boolean {
|
|
64
|
+
return call<boolean>('material.isAir', { type }, options);
|
|
65
|
+
},
|
|
66
|
+
};
|
package/src/server.ts
CHANGED
|
@@ -7,8 +7,6 @@ export function dispatchCommand(cmd: string, options?: TaskOptions): Promise<boo
|
|
|
7
7
|
export function dispatchCommandSync(cmd: string, options?: TaskOptions): boolean { return call<boolean>('command.dispatch', { command: cmd }, options); }
|
|
8
8
|
export function setMotd(motd: string, options?: TaskOptions): Promise<void> { return post('server.setMotd', { motd }, options); }
|
|
9
9
|
export function setMotdSync(motd: string, options?: TaskOptions): void { call('server.setMotd', { motd }, options); }
|
|
10
|
-
export function setIcon(base64: string, options?: TaskOptions): Promise<void> { return post('server.setIcon', { icon: base64 }, options); }
|
|
11
|
-
export function setIconSync(base64: string, options?: TaskOptions): void { call('server.setIcon', { icon: base64 }, options); }
|
|
12
10
|
export function getMotd(options?: TaskOptions): Promise<string> { return post<string>('server.getMotd', {}, options); }
|
|
13
11
|
export function getMotdSync(options?: TaskOptions): string { return call<string>('server.getMotd', {}, options); }
|
|
14
12
|
export function getVersion(options?: TaskOptions): Promise<string> { return post<string>('server.getVersion', {}, options); }
|
package/src/world.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { call, post } from './task.js';
|
|
|
2
2
|
import type { TaskOptions } from './task.js';
|
|
3
3
|
import { Location, LocationData } from './location.js';
|
|
4
4
|
import { Block } from './block.js';
|
|
5
|
+
import type { BlockState } from './block.js';
|
|
5
6
|
import { Chunk, ChunkData } from './chunk.js';
|
|
6
7
|
|
|
7
8
|
interface WorldData {
|
|
@@ -100,18 +101,32 @@ export class World {
|
|
|
100
101
|
return call<string>('world.getBiome', { world: this.name, x, y, z }, options);
|
|
101
102
|
}
|
|
102
103
|
getBlock(x: number, y: number, z: number, options?: TaskOptions): Promise<Block | null> {
|
|
103
|
-
return post<{ x: number; y: number; z: number; type: string }>('world.getBlock', { world: this.name, x, y, z }, options)
|
|
104
|
-
.then((r) => (r ? new Block(
|
|
104
|
+
return post<{ world: string; x: number; y: number; z: number; type: string; state: BlockState }>('world.getBlock', { world: this.name, x, y, z }, options)
|
|
105
|
+
.then((r) => (r ? new Block(r.type, r.state, new Location(r.x, r.y, r.z, 0, 0, r.world)) : null));
|
|
105
106
|
}
|
|
106
107
|
getBlockSync(x: number, y: number, z: number, options?: TaskOptions): Block | null {
|
|
107
|
-
const r = call<{ x: number; y: number; z: number; type: string }>('world.getBlock', { world: this.name, x, y, z }, options);
|
|
108
|
-
return r ? new Block(
|
|
109
|
-
}
|
|
110
|
-
setBlock(x: number, y: number, z: number,
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
108
|
+
const r = call<{ world: string; x: number; y: number; z: number; type: string; state: BlockState }>('world.getBlock', { world: this.name, x, y, z }, options);
|
|
109
|
+
return r ? new Block(r.type, r.state, new Location(r.x, r.y, r.z, 0, 0, r.world)) : null;
|
|
110
|
+
}
|
|
111
|
+
setBlock(x: number, y: number, z: number, block: Block | string, options?: TaskOptions): Promise<void> {
|
|
112
|
+
const p: Record<string, unknown> = { world: this.name, x, y, z };
|
|
113
|
+
if (typeof block === 'string') {
|
|
114
|
+
p.blockType = block;
|
|
115
|
+
} else {
|
|
116
|
+
p.blockType = block.type;
|
|
117
|
+
if (block.state && Object.keys(block.state).length > 0) p.state = block.state;
|
|
118
|
+
}
|
|
119
|
+
return post('world.setBlock', p, options);
|
|
120
|
+
}
|
|
121
|
+
setBlockSync(x: number, y: number, z: number, block: Block | string, options?: TaskOptions): void {
|
|
122
|
+
const p: Record<string, unknown> = { world: this.name, x, y, z };
|
|
123
|
+
if (typeof block === 'string') {
|
|
124
|
+
p.blockType = block;
|
|
125
|
+
} else {
|
|
126
|
+
p.blockType = block.type;
|
|
127
|
+
if (block.state && Object.keys(block.state).length > 0) p.state = block.state;
|
|
128
|
+
}
|
|
129
|
+
call('world.setBlock', p, options);
|
|
115
130
|
}
|
|
116
131
|
getEntities(options?: TaskOptions): Promise<string[]> {
|
|
117
132
|
return post<string[]>('world.getEntities', { world: this.name }, options);
|