yeow-api 0.4.2 → 0.5.0
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/advancement.ts +3 -22
- package/src/assets.ts +9 -8
- package/src/block.ts +4 -3
- package/src/bossbar.ts +90 -38
- package/src/core.ts +11 -27
- package/src/entity.ts +44 -0
- package/src/fs.ts +5 -5
- package/src/global.d.ts +23 -1
- package/src/http.ts +74 -14
- package/src/inventory.ts +8 -6
- package/src/material.ts +8 -0
- package/src/player.ts +56 -10
- package/src/potion.ts +9 -15
- package/src/scoreboard.ts +249 -84
- package/src/sound.ts +4 -8
- package/src/target.ts +20 -0
- package/src/util.ts +7 -7
- package/src/world.ts +6 -0
package/package.json
CHANGED
package/src/advancement.ts
CHANGED
|
@@ -1,27 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// 进度操作已上移到 `player.ts` 的 Player 实例方法(`player.grantAdvancement(...)` 等)
|
|
2
|
+
// ——不再提供顶层 uuid 函数。
|
|
3
3
|
|
|
4
|
+
/** 进度完成情况。 */
|
|
4
5
|
export interface AdvancementProgress {
|
|
5
6
|
awardedCriteria: string[];
|
|
6
7
|
remainingCriteria: string[];
|
|
7
8
|
}
|
|
8
|
-
|
|
9
|
-
export function grant(uuid: string, key: string, options?: TaskOptions): Promise<boolean> {
|
|
10
|
-
return post<boolean>('advancement.grant', { uuid, key }, options);
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function revoke(uuid: string, key: string, options?: TaskOptions): Promise<boolean> {
|
|
14
|
-
return post<boolean>('advancement.revoke', { uuid, key }, options);
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export function getProgress(uuid: string, key: string, options?: TaskOptions): Promise<AdvancementProgress | null> {
|
|
18
|
-
return post<AdvancementProgress | null>('advancement.getProgress', { uuid, key }, options);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
export function awardCriteria(uuid: string, key: string, criteria: string, options?: TaskOptions): Promise<boolean> {
|
|
22
|
-
return post<boolean>('advancement.awardCriteria', { uuid, key, criteria }, options);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export function revokeCriteria(uuid: string, key: string, criteria: string, options?: TaskOptions): Promise<boolean> {
|
|
26
|
-
return post<boolean>('advancement.revokeCriteria', { uuid, key, criteria }, options);
|
|
27
|
-
}
|
package/src/assets.ts
CHANGED
|
@@ -55,18 +55,19 @@ const readSyncImpl = (path: string, options?: FsEncoding | ReadFileOptions): Uin
|
|
|
55
55
|
export const read = readImpl as AssetsReadFn;
|
|
56
56
|
export const readSync = readSyncImpl as AssetsReadSyncFn;
|
|
57
57
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
58
|
+
/**
|
|
59
|
+
* 解压单文件资产到磁盘。**`dest` 必填**,基于插件数据目录(`plugins/<插件名>/`)计算,
|
|
60
|
+
* 最终目标必须位于插件目录内。返回解压后的相对服务器根目录路径。
|
|
61
|
+
*/
|
|
62
|
+
export async function extract(path: string, dest: string): Promise<string> {
|
|
63
|
+
const r = await _sendAssetsAsync({ t: 'extract', p: { path, dest } }) as { path: string };
|
|
62
64
|
return r.path;
|
|
63
65
|
}
|
|
64
|
-
export function extractSync(path: string, dest
|
|
65
|
-
|
|
66
|
-
if (dest) p.dest = dest;
|
|
67
|
-
return (_sendAssets({ t: 'extract', p }) as { path: string }).path;
|
|
66
|
+
export function extractSync(path: string, dest: string): string {
|
|
67
|
+
return (_sendAssets({ t: 'extract', p: { path, dest } }) as { path: string }).path;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/** 解压目录树到磁盘。`dest` 可选(默认 `assets/<path>`),基于插件数据目录计算并限定其内。 */
|
|
70
71
|
export async function extractDir(path: string, dest?: string): Promise<string> {
|
|
71
72
|
const p: Record<string, unknown> = { path };
|
|
72
73
|
if (dest) p.dest = dest;
|
package/src/block.ts
CHANGED
|
@@ -9,15 +9,16 @@ import {
|
|
|
9
9
|
keysBlock as pdcKeys, getAllBlock as pdcGetAll,
|
|
10
10
|
} from './pdc.js';
|
|
11
11
|
|
|
12
|
-
/** 方块状态(Minecraft
|
|
12
|
+
/** 方块状态(Minecraft 原版键值对枚举;值为字符串 / 数字 / 布尔——按原版语义保留类型)。 */
|
|
13
13
|
export interface BlockState {
|
|
14
|
-
[key: string]: string;
|
|
14
|
+
[key: string]: string | number | boolean;
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
/**
|
|
18
18
|
* Block —— 方块数据描述符 + 可选的世界位置(location)。
|
|
19
19
|
* 对应 Minecraft 原版的方块概念:类型 + 方块状态(键值对枚举,如
|
|
20
|
-
* `facing`、`waterlogged`、`level`
|
|
20
|
+
* `facing`、`waterlogged`、`level` 等;值按原版语义保留类型——布尔 `waterlogged: false`、
|
|
21
|
+
* 数字 `level: 8`、枚举串 `facing: "north"`)。
|
|
21
22
|
*
|
|
22
23
|
* **静态数据语义**:`type` / `state` / `location` 均为**获取时刻的快照**,
|
|
23
24
|
* 之后世界变化不会自动更新;需要最新状态请重新调用 `world.getBlock`。
|
package/src/bossbar.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import { post } from './task.js';
|
|
1
|
+
import { call, post } from './task.js';
|
|
2
2
|
import type { TaskOptions } from './task.js';
|
|
3
3
|
import { BossBarHandle } from './instance-id.js';
|
|
4
|
+
import { resolveUuid } from './target.js';
|
|
5
|
+
import type { PlayerTarget } from './target.js';
|
|
4
6
|
|
|
5
7
|
export interface BossBarOptions {
|
|
6
8
|
color?: string;
|
|
@@ -9,52 +11,102 @@ export interface BossBarOptions {
|
|
|
9
11
|
visible?: boolean;
|
|
10
12
|
}
|
|
11
13
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
}
|
|
14
|
+
/**
|
|
15
|
+
* BossBar —— 面向玩家的血条对象(OOP)。
|
|
16
|
+
*
|
|
17
|
+
* ```js
|
|
18
|
+
* const bar = await BossBar.create('<red>Loading...</red>', { color: 'RED', progress: 0.0 });
|
|
19
|
+
* await bar.addPlayer(player); // 接受 Player 对象或 uuid
|
|
20
|
+
* await bar.setProgress(0.5);
|
|
21
|
+
* await bar.destroy();
|
|
22
|
+
* ```
|
|
23
|
+
*
|
|
24
|
+
* 事件比对:`bar.toString()` 返回底层句柄 id(与 `inventoryClick` 等比对)。
|
|
25
|
+
* BossBar 颜色/样式/Flag 值域见 [值域附录 · 直接维护的枚举清单]。
|
|
26
|
+
*/
|
|
27
|
+
export class BossBar {
|
|
28
|
+
private constructor(readonly id: string) {}
|
|
17
29
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
30
|
+
/** 创建血条(title 支持 MiniMessage)。 */
|
|
31
|
+
static async create(title: string, options?: BossBarOptions, taskOptions?: TaskOptions): Promise<BossBar> {
|
|
32
|
+
const id = new BossBarHandle().toString();
|
|
33
|
+
await post('bossbar.create', { id, title, ...options }, taskOptions);
|
|
34
|
+
return new BossBar(id);
|
|
35
|
+
}
|
|
21
36
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
37
|
+
/** 底层句柄 id(用于事件比对)。 */
|
|
38
|
+
get handle(): string { return this.id; }
|
|
39
|
+
toString(): string { return this.id; }
|
|
25
40
|
|
|
26
|
-
|
|
27
|
-
return post('bossbar.setProgress', { id: id.toString(), progress }, options);
|
|
28
|
-
}
|
|
41
|
+
// ── 标题 / 进度 / 颜色 / 样式 / 可见性 ──
|
|
29
42
|
|
|
30
|
-
|
|
31
|
-
return post('bossbar.
|
|
32
|
-
}
|
|
43
|
+
set title(v: string) { call('bossbar.setTitle', { id: this.id, title: v }); }
|
|
44
|
+
setTitle(title: string, options?: TaskOptions): Promise<void> { return post('bossbar.setTitle', { id: this.id, title }, options); }
|
|
45
|
+
setTitleSync(title: string, options?: TaskOptions): void { call('bossbar.setTitle', { id: this.id, title }, options); }
|
|
33
46
|
|
|
34
|
-
|
|
35
|
-
return post('bossbar.
|
|
36
|
-
}
|
|
47
|
+
set progress(v: number) { call('bossbar.setProgress', { id: this.id, progress: v }); }
|
|
48
|
+
setProgress(progress: number, options?: TaskOptions): Promise<void> { return post('bossbar.setProgress', { id: this.id, progress }, options); }
|
|
49
|
+
setProgressSync(progress: number, options?: TaskOptions): void { call('bossbar.setProgress', { id: this.id, progress }, options); }
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
return post('bossbar.
|
|
40
|
-
}
|
|
51
|
+
set color(v: string) { call('bossbar.setColor', { id: this.id, color: v }); }
|
|
52
|
+
setColor(color: string, options?: TaskOptions): Promise<void> { return post('bossbar.setColor', { id: this.id, color }, options); }
|
|
53
|
+
setColorSync(color: string, options?: TaskOptions): void { call('bossbar.setColor', { id: this.id, color }, options); }
|
|
41
54
|
|
|
42
|
-
|
|
43
|
-
return post('bossbar.
|
|
44
|
-
}
|
|
55
|
+
set style(v: string) { call('bossbar.setStyle', { id: this.id, style: v }); }
|
|
56
|
+
setStyle(style: string, options?: TaskOptions): Promise<void> { return post('bossbar.setStyle', { id: this.id, style }, options); }
|
|
57
|
+
setStyleSync(style: string, options?: TaskOptions): void { call('bossbar.setStyle', { id: this.id, style }, options); }
|
|
45
58
|
|
|
46
|
-
|
|
47
|
-
return post('bossbar.
|
|
48
|
-
}
|
|
59
|
+
set visible(v: boolean) { call('bossbar.setVisible', { id: this.id, visible: v }); }
|
|
60
|
+
setVisible(visible: boolean, options?: TaskOptions): Promise<void> { return post('bossbar.setVisible', { id: this.id, visible }, options); }
|
|
61
|
+
setVisibleSync(visible: boolean, options?: TaskOptions): void { call('bossbar.setVisible', { id: this.id, visible }, options); }
|
|
49
62
|
|
|
50
|
-
|
|
51
|
-
return post('bossbar.removeAll', { id: id.toString() }, options);
|
|
52
|
-
}
|
|
63
|
+
// ── 玩家绑定 ──
|
|
53
64
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
}
|
|
65
|
+
/** 绑定玩家(接受 `Player` 对象或 uuid)。 */
|
|
66
|
+
addPlayer(player: PlayerTarget, options?: TaskOptions): Promise<void> {
|
|
67
|
+
return post('bossbar.addPlayer', { id: this.id, uuid: resolveUuid(player) }, options);
|
|
68
|
+
}
|
|
69
|
+
addPlayerSync(player: PlayerTarget, options?: TaskOptions): void {
|
|
70
|
+
call('bossbar.addPlayer', { id: this.id, uuid: resolveUuid(player) }, options);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** 移除玩家(接受 `Player` 对象或 uuid)。 */
|
|
74
|
+
removePlayer(player: PlayerTarget, options?: TaskOptions): Promise<void> {
|
|
75
|
+
return post('bossbar.removePlayer', { id: this.id, uuid: resolveUuid(player) }, options);
|
|
76
|
+
}
|
|
77
|
+
removePlayerSync(player: PlayerTarget, options?: TaskOptions): void {
|
|
78
|
+
call('bossbar.removePlayer', { id: this.id, uuid: resolveUuid(player) }, options);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** 移除全部绑定的玩家。 */
|
|
82
|
+
removeAllPlayers(options?: TaskOptions): Promise<void> {
|
|
83
|
+
return post('bossbar.removeAll', { id: this.id }, options);
|
|
84
|
+
}
|
|
85
|
+
removeAllPlayersSync(options?: TaskOptions): void {
|
|
86
|
+
call('bossbar.removeAll', { id: this.id }, options);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// ── Flags ──
|
|
90
|
+
|
|
91
|
+
addFlag(flag: string, options?: TaskOptions): Promise<void> {
|
|
92
|
+
return post('bossbar.addFlag', { id: this.id, flag }, options);
|
|
93
|
+
}
|
|
94
|
+
addFlagSync(flag: string, options?: TaskOptions): void {
|
|
95
|
+
call('bossbar.addFlag', { id: this.id, flag }, options);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
removeFlag(flag: string, options?: TaskOptions): Promise<void> {
|
|
99
|
+
return post('bossbar.removeFlag', { id: this.id, flag }, options);
|
|
100
|
+
}
|
|
101
|
+
removeFlagSync(flag: string, options?: TaskOptions): void {
|
|
102
|
+
call('bossbar.removeFlag', { id: this.id, flag }, options);
|
|
103
|
+
}
|
|
57
104
|
|
|
58
|
-
|
|
59
|
-
|
|
105
|
+
/** 销毁血条(此后句柄失效)。 */
|
|
106
|
+
destroy(options?: TaskOptions): Promise<void> {
|
|
107
|
+
return post('bossbar.destroy', { id: this.id }, options);
|
|
108
|
+
}
|
|
109
|
+
destroySync(options?: TaskOptions): void {
|
|
110
|
+
call('bossbar.destroy', { id: this.id }, options);
|
|
111
|
+
}
|
|
60
112
|
}
|
package/src/core.ts
CHANGED
|
@@ -57,43 +57,27 @@ export { assets, read as assetsRead, readSync as assetsReadSync,
|
|
|
57
57
|
export { path } from './path.js';
|
|
58
58
|
export { createReadStream, createWriteStream } from './fs.js';
|
|
59
59
|
export type { ReadStream, WriteStream, ReadStreamOptions, WriteStreamOptions } from './fs.js';
|
|
60
|
-
export { listen, respond, close, request
|
|
61
|
-
export type { RespondOptions } from './http.js';
|
|
60
|
+
export { listen, respond, close, request } from './http.js';
|
|
61
|
+
export type { RespondOptions, RequestOptions, HttpResponse } from './http.js';
|
|
62
62
|
export { logError } from './log-error.js';
|
|
63
63
|
export { InstanceId, BossBarHandle, InventoryHandle } from './instance-id.js';
|
|
64
64
|
export { ItemStack } from './item.js';
|
|
65
65
|
export type { ItemMeta, PotionEffectData, AttributeModifierData } from './item.js';
|
|
66
66
|
export type { PotionEffect } from './potion.js';
|
|
67
|
-
export {
|
|
68
|
-
export { playSound, stopSound, stopAllSounds } from './sound.js';
|
|
67
|
+
export { playSound } from './sound.js';
|
|
69
68
|
export type { ParticleOptions } from './particle.js';
|
|
70
69
|
export { spawnParticle } from './particle.js';
|
|
70
|
+
export type { PlayerTarget, LivingTarget, EntityTarget } from './target.js';
|
|
71
|
+
export type { AdvancementProgress } from './advancement.js';
|
|
72
|
+
export { BossBar } from './bossbar.js';
|
|
73
|
+
export type { BossBarOptions } from './bossbar.js';
|
|
74
|
+
export { Scoreboard, Objective, Team } from './scoreboard.js';
|
|
75
|
+
export type { ObjectiveInfo, TeamInfo } from './scoreboard.js';
|
|
71
76
|
export { get as pdcGet, set as pdcSet, has as pdcHas, remove as pdcRemove, keys as pdcKeys, getAll as pdcGetAll,
|
|
72
77
|
getRaw as pdcGetRaw, setRaw as pdcSetRaw, getAllRaw as pdcGetAllRaw,
|
|
73
78
|
getBlock as pdcGetBlock, setBlock as pdcSetBlock, hasBlock as pdcHasBlock, removeBlock as pdcRemoveBlock,
|
|
74
79
|
keysBlock as pdcKeysBlock, getAllBlock as pdcGetAllBlock, getBlockRaw as pdcGetBlockRaw, setBlockRaw as pdcSetBlockRaw, getAllBlockRaw as pdcGetAllBlockRaw } from './pdc.js';
|
|
75
|
-
export { createBossBar, destroy as destroyBossBar,
|
|
76
|
-
setTitle as setBossBarTitle, setProgress as setBossBarProgress,
|
|
77
|
-
setColor as setBossBarColor, setStyle as setBossBarStyle,
|
|
78
|
-
setVisible as setBossBarVisible, addPlayer as addBossBarPlayer,
|
|
79
|
-
removePlayer as removeBossBarPlayer, removeAll as removeAllBossBarPlayers,
|
|
80
|
-
addFlag as addBossBarFlag, removeFlag as removeBossBarFlag } from './bossbar.js';
|
|
81
|
-
export type { BossBarOptions } from './bossbar.js';
|
|
82
|
-
export type { AdvancementProgress } from './advancement.js';
|
|
83
|
-
export { grant as grantAdvancement, revoke as revokeAdvancement,
|
|
84
|
-
getProgress as getAdvancementProgress, awardCriteria, revokeCriteria } from './advancement.js';
|
|
85
80
|
export { add as addRecipe, remove as removeRecipe, getForItem as getRecipesForItem } from './recipe.js';
|
|
86
|
-
export type {
|
|
87
|
-
ObjectiveInfo, TeamInfo,
|
|
88
|
-
} from './scoreboard.js';
|
|
89
|
-
export { createBoard as createScoreboard, deleteBoard as deleteScoreboard,
|
|
90
|
-
createObjective, deleteObjective, getObjectives,
|
|
91
|
-
setObjectiveDisplay, getScore, setScore, resetScore,
|
|
92
|
-
createTeam, deleteTeam, getTeam, getTeams,
|
|
93
|
-
setTeamDisplayName, setTeamPrefix, setTeamSuffix, setTeamColor,
|
|
94
|
-
setTeamFriendlyFire, setTeamSeeInvisible, setTeamOption,
|
|
95
|
-
teamAddEntry, teamRemoveEntry, teamGetEntries,
|
|
96
|
-
setPlayerBoard } from './scoreboard.js';
|
|
97
81
|
export { Material, getMaterials, getBlocks, getItems } from './material.js';
|
|
98
82
|
export type { MaterialInfo } from './material.js';
|
|
99
83
|
export { registerService, registerNativeService, request as serviceRequest, subscribe as serviceSubscribe, publish as servicePublish } from './service.js';
|
|
@@ -107,8 +91,8 @@ export type { Permission, PermissionOptions, PermissionDefault } from './permiss
|
|
|
107
91
|
export { createWorker, Worker, onMessage, postMessage } from './worker.js';
|
|
108
92
|
export type { WorkerOptions } from './worker.js';
|
|
109
93
|
export {
|
|
110
|
-
stringToBytes,
|
|
111
|
-
bytesToString,
|
|
94
|
+
stringToBytes, stringToBytesSync,
|
|
95
|
+
bytesToString, bytesToStringSync,
|
|
112
96
|
Gzip,
|
|
113
97
|
} from './util.js';
|
|
114
98
|
export type { GzipCompressor, GzipDecompressor, GzipCompressOptions, GzipDecompressOptions } from './util.js';
|
package/src/entity.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { call, post } from './task.js';
|
|
2
2
|
import type { TaskOptions } from './task.js';
|
|
3
3
|
import { Location, LocationData } from './location.js';
|
|
4
|
+
import type { PotionEffect } from './potion.js';
|
|
4
5
|
|
|
5
6
|
export interface BoundingBox {
|
|
6
7
|
minX: number;
|
|
@@ -113,6 +114,15 @@ export class Entity {
|
|
|
113
114
|
}
|
|
114
115
|
|
|
115
116
|
export class LivingEntity extends Entity {
|
|
117
|
+
/** 按 uuid 查找活体实体(返回 LivingEntity;目标非活体/不存在返回 null)。 */
|
|
118
|
+
static get(uuid: string, options?: TaskOptions): Promise<LivingEntity | null> {
|
|
119
|
+
return post<{ uuid: string }>('entity.get', { uuid }, options).then((d) => (d ? new LivingEntity(d.uuid) : null));
|
|
120
|
+
}
|
|
121
|
+
static getSync(uuid: string, options?: TaskOptions): LivingEntity | null {
|
|
122
|
+
const d = call<{ uuid: string }>('entity.get', { uuid }, options);
|
|
123
|
+
return d ? new LivingEntity(d.uuid) : null;
|
|
124
|
+
}
|
|
125
|
+
|
|
116
126
|
get health(): number { return call<number>('entity.getHealth', { uuid: this.uuid }); }
|
|
117
127
|
set health(v: number) { call('entity.setHealth', { uuid: this.uuid, value: v }); }
|
|
118
128
|
getHealth(options?: TaskOptions): Promise<number> { return post<number>('entity.getHealth', { uuid: this.uuid }, options); }
|
|
@@ -142,4 +152,38 @@ export class LivingEntity extends Entity {
|
|
|
142
152
|
setTargetSync(target: { targetUuid: string } | { world: string; x: number; y: number; z: number; speed?: number }, options?: TaskOptions): boolean {
|
|
143
153
|
return call<boolean>('entity.setTarget', { uuid: this.uuid, ...target }, options);
|
|
144
154
|
}
|
|
155
|
+
|
|
156
|
+
// ── 药水效果(实体级;Player 经继承自动获得) ──
|
|
157
|
+
|
|
158
|
+
/** 添加药水效果。 */
|
|
159
|
+
addPotionEffect(effect: PotionEffect, options?: TaskOptions): Promise<void> {
|
|
160
|
+
return post('entity.addPotionEffect', { uuid: this.uuid, ...effect }, options);
|
|
161
|
+
}
|
|
162
|
+
addPotionEffectSync(effect: PotionEffect, options?: TaskOptions): void {
|
|
163
|
+
call('entity.addPotionEffect', { uuid: this.uuid, ...effect }, options);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** 移除指定类型的药水效果。 */
|
|
167
|
+
removePotionEffect(type: string, options?: TaskOptions): Promise<void> {
|
|
168
|
+
return post('entity.removePotionEffect', { uuid: this.uuid, type }, options);
|
|
169
|
+
}
|
|
170
|
+
removePotionEffectSync(type: string, options?: TaskOptions): void {
|
|
171
|
+
call('entity.removePotionEffect', { uuid: this.uuid, type }, options);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** 清除全部药水效果。 */
|
|
175
|
+
clearPotionEffects(options?: TaskOptions): Promise<void> {
|
|
176
|
+
return post('entity.clearPotionEffects', { uuid: this.uuid }, options);
|
|
177
|
+
}
|
|
178
|
+
clearPotionEffectsSync(options?: TaskOptions): void {
|
|
179
|
+
call('entity.clearPotionEffects', { uuid: this.uuid }, options);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/** 当前生效的药水效果列表(与输入同结构)。 */
|
|
183
|
+
getActivePotionEffects(options?: TaskOptions): Promise<PotionEffect[]> {
|
|
184
|
+
return post<PotionEffect[]>('entity.getActivePotionEffects', { uuid: this.uuid }, options);
|
|
185
|
+
}
|
|
186
|
+
getActivePotionEffectsSync(options?: TaskOptions): PotionEffect[] {
|
|
187
|
+
return call<PotionEffect[]>('entity.getActivePotionEffects', { uuid: this.uuid }, options);
|
|
188
|
+
}
|
|
145
189
|
}
|
package/src/fs.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
type FsLevel = 'plugin' | 'server' | 'outer';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { stringToBytesSync, bytesToStringSync } from './util.js';
|
|
4
4
|
|
|
5
5
|
/** 文件编码:utf8 = 文本;base64 = 将字符串视为 Base64 编码的二进制数据。 */
|
|
6
6
|
export type FsEncoding = 'utf8' | 'base64';
|
|
@@ -53,7 +53,7 @@ function _makeUtf8StreamDecoder() {
|
|
|
53
53
|
if ((b & 0xE0) === 0xC0) return 2;
|
|
54
54
|
if ((b & 0xF0) === 0xE0) return 3;
|
|
55
55
|
if ((b & 0xF8) === 0xF0) return 4;
|
|
56
|
-
return 1; // 非法起始字节:交给
|
|
56
|
+
return 1; // 非法起始字节:交给 bytesToStringSync 以替换字符处理
|
|
57
57
|
};
|
|
58
58
|
|
|
59
59
|
return {
|
|
@@ -84,12 +84,12 @@ function _makeUtf8StreamDecoder() {
|
|
|
84
84
|
|
|
85
85
|
pending = cut === buf.length ? new Uint8Array(0) : buf.slice(cut);
|
|
86
86
|
const complete = cut === buf.length ? buf : buf.subarray(0, cut);
|
|
87
|
-
return complete.length ?
|
|
87
|
+
return complete.length ? bytesToStringSync(complete) : null;
|
|
88
88
|
},
|
|
89
89
|
/** EOF:把剩余的不完整序列交给 Java 解码(通常产出 U+FFFD)。 */
|
|
90
90
|
flush(): string | null {
|
|
91
91
|
if (!pending.length) return null;
|
|
92
|
-
const s =
|
|
92
|
+
const s = bytesToStringSync(pending);
|
|
93
93
|
pending = new Uint8Array(0);
|
|
94
94
|
return s;
|
|
95
95
|
},
|
|
@@ -394,7 +394,7 @@ function _makeWriteStream(
|
|
|
394
394
|
const check = () => { if (closed) throw new Error('write stream closed'); };
|
|
395
395
|
const toBytes = (chunk: Uint8Array | string): Uint8Array => {
|
|
396
396
|
if (typeof chunk !== 'string') return chunk; // Uint8Array 始终按原始字节写入
|
|
397
|
-
return encoding === 'base64' ? Uint8Array.fromBase64(chunk) :
|
|
397
|
+
return encoding === 'base64' ? Uint8Array.fromBase64(chunk) : stringToBytesSync(chunk);
|
|
398
398
|
};
|
|
399
399
|
return {
|
|
400
400
|
encoding,
|
package/src/global.d.ts
CHANGED
|
@@ -29,12 +29,34 @@ declare global {
|
|
|
29
29
|
headers: { get(name: string): string | undefined };
|
|
30
30
|
text(): Promise<string>;
|
|
31
31
|
json(): Promise<any>;
|
|
32
|
+
base64(): Promise<string>;
|
|
33
|
+
bytes(): Promise<Uint8Array>;
|
|
34
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
32
35
|
}
|
|
33
36
|
function fetch(
|
|
34
37
|
url: string,
|
|
35
|
-
init?: { method?: string; headers?: Record<string, string>; body?: string | null }
|
|
38
|
+
init?: { method?: string; headers?: Record<string, string>; body?: string | Uint8Array | null; encoding?: 'utf8' | 'base64'; timeout?: number }
|
|
36
39
|
): Promise<YeowResponse>;
|
|
37
40
|
|
|
41
|
+
// ── TextEncoder / TextDecoder(utf-8,polyfill 注入;同步 API)──
|
|
42
|
+
interface TextEncoder {
|
|
43
|
+
readonly encoding: string;
|
|
44
|
+
encode(input?: string): Uint8Array;
|
|
45
|
+
}
|
|
46
|
+
const TextEncoder: {
|
|
47
|
+
new (encoding?: string): TextEncoder;
|
|
48
|
+
prototype: TextEncoder;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
interface TextDecoder {
|
|
52
|
+
readonly encoding: string;
|
|
53
|
+
decode(input?: Uint8Array): string;
|
|
54
|
+
}
|
|
55
|
+
const TextDecoder: {
|
|
56
|
+
new (encoding?: string): TextDecoder;
|
|
57
|
+
prototype: TextDecoder;
|
|
58
|
+
};
|
|
59
|
+
|
|
38
60
|
function setTimeout(handler: (...args: any[]) => void, timeout?: number, ...args: any[]): string;
|
|
39
61
|
function clearTimeout(id: string): void;
|
|
40
62
|
function setInterval(handler: (...args: any[]) => void, timeout?: number, ...args: any[]): string;
|
package/src/http.ts
CHANGED
|
@@ -22,6 +22,42 @@ export interface RespondOptions {
|
|
|
22
22
|
headers?: Record<string, string>;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
/** HTTP 请求选项(request)。 */
|
|
26
|
+
export interface RequestOptions {
|
|
27
|
+
/** HTTP 方法(默认 `"GET"`)。 */
|
|
28
|
+
method?: string;
|
|
29
|
+
/** 请求头。 */
|
|
30
|
+
headers?: Record<string, string>;
|
|
31
|
+
/**
|
|
32
|
+
* 请求体(与 `fs.writeFile` 同语义):`Uint8Array` 直接作为二进制;
|
|
33
|
+
* 字符串按 `encoding` 解释——缺省 UTF-8 文本,`'base64'` 时视为 base64 编码的二进制。
|
|
34
|
+
*/
|
|
35
|
+
body?: string | Uint8Array;
|
|
36
|
+
/**
|
|
37
|
+
* 请求体(body 为字符串时)解释:`'utf8'`(默认)文本 / `'base64'` base64 二进制
|
|
38
|
+
* (与 `fs.writeFile` 同语义)。
|
|
39
|
+
*/
|
|
40
|
+
encoding?: 'utf8' | 'base64';
|
|
41
|
+
/**
|
|
42
|
+
* 响应体形态:缺省 `Uint8Array`(原始字节,可在收到后自行解码,
|
|
43
|
+
* 如 `bytesToStringSync(body)` 或 `new TextDecoder().decode(body)`);
|
|
44
|
+
* `'utf8'` → UTF-8 字符串;`'base64'` → base64 字符串(原样返回,不解码)。
|
|
45
|
+
*/
|
|
46
|
+
responseEncoding?: 'utf8' | 'base64';
|
|
47
|
+
/** 超时(毫秒);缺省运行时默认(连接 5s / 读取 10s)。 */
|
|
48
|
+
timeout?: number;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** HTTP 响应(request)。 */
|
|
52
|
+
export interface HttpResponse {
|
|
53
|
+
/** HTTP 状态码。 */
|
|
54
|
+
status: number;
|
|
55
|
+
/** 响应头(键小写)。 */
|
|
56
|
+
headers: Record<string, string>;
|
|
57
|
+
/** 响应体:缺省 `Uint8Array`;`encoding: 'utf8' | 'base64'` 时为字符串。 */
|
|
58
|
+
body: string | Uint8Array;
|
|
59
|
+
}
|
|
60
|
+
|
|
25
61
|
function _sendHttp(payload: Record<string, unknown>): HttpResult {
|
|
26
62
|
const r = $send('http', payload);
|
|
27
63
|
if (!r) return {};
|
|
@@ -75,25 +111,49 @@ _registerCallback(() => {
|
|
|
75
111
|
|
|
76
112
|
/**
|
|
77
113
|
* 异步 HTTP 请求(不阻塞 JS 线程)——底层走 `http:requestAsync` 通道。
|
|
78
|
-
*
|
|
114
|
+
*
|
|
115
|
+
* 请求体与 `fs.writeFile` 同语义(`body: string | Uint8Array`,字符串按
|
|
116
|
+
* `encoding` 解释);响应体默认 `Uint8Array`(原始字节),可用
|
|
117
|
+
* `responseEncoding` 直接得到字符串(`'utf8'` / `'base64'`),也可在收到后
|
|
118
|
+
* 用 `bytesToStringSync` 自行解码。`timeout` 指定超时毫秒数(连接与读取,缺省
|
|
119
|
+
* 运行时默认)。
|
|
79
120
|
*/
|
|
80
|
-
export function request(url: string, opts:
|
|
121
|
+
export function request(url: string, opts: RequestOptions = {}): Promise<HttpResponse> {
|
|
81
122
|
return new Promise((resolve, reject) => {
|
|
82
123
|
const cbId = _registerCallback((result: unknown) => {
|
|
83
|
-
|
|
84
|
-
|
|
124
|
+
const r = result as HttpResult;
|
|
125
|
+
if (r?.err || (r as any)?.error) {
|
|
126
|
+
reject(new Error(r?.err || (r as any).error));
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
const body = r.body ?? '';
|
|
130
|
+
resolve({
|
|
131
|
+
status: r.status ?? 0,
|
|
132
|
+
headers: r.headers ?? {},
|
|
133
|
+
// 底层始终以 base64 承载原始字节;'utf8' 时 Java 侧已解码为文本,其余形态本地转换
|
|
134
|
+
body: opts.responseEncoding === 'utf8' ? body
|
|
135
|
+
: opts.responseEncoding === 'base64' ? body
|
|
136
|
+
: Uint8Array.fromBase64(body),
|
|
137
|
+
});
|
|
85
138
|
});
|
|
86
139
|
try {
|
|
87
|
-
|
|
140
|
+
const p: Record<string, unknown> = {
|
|
141
|
+
url,
|
|
142
|
+
method: opts.method || 'GET',
|
|
143
|
+
headers: opts.headers || {},
|
|
144
|
+
};
|
|
145
|
+
// 请求体与 fs.writeFile 同语义:Uint8Array 直接二进制(base64 承载);
|
|
146
|
+
// 字符串按 encoding——缺省 UTF-8 文本,'base64' 视为 base64 二进制
|
|
147
|
+
if (opts.body instanceof Uint8Array) {
|
|
148
|
+
p.body = opts.body.toBase64();
|
|
149
|
+
p.encoding = 'base64';
|
|
150
|
+
} else {
|
|
151
|
+
p.body = opts.body ?? null;
|
|
152
|
+
if (opts.encoding === 'base64') p.encoding = 'base64';
|
|
153
|
+
}
|
|
154
|
+
p.responseType = opts.responseEncoding === 'utf8' ? 'text' : 'base64';
|
|
155
|
+
if (opts.timeout !== undefined) p.timeout = opts.timeout;
|
|
156
|
+
_sendHttp({ t: 'requestAsync', p: { ...p, cb: String(cbId) } });
|
|
88
157
|
} catch (e) { reject(e); }
|
|
89
158
|
});
|
|
90
159
|
}
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* 同步 HTTP 请求(**阻塞 JS 线程**直到响应返回)——底层走 `http:request` 通道。
|
|
94
|
-
* 阻塞期间 JS 线程无法处理事件/命令/回调(可能触发 event.timeout 告警);
|
|
95
|
-
* 仅适合低频、非事件上下文。事件处理器或高频场景请用 `request`(异步)或全局 `fetch`。
|
|
96
|
-
*/
|
|
97
|
-
export function requestSync(url: string, opts: Record<string, unknown> = {}): HttpResult {
|
|
98
|
-
return _sendHttp({ t: 'request', p: { url, ...opts } });
|
|
99
|
-
}
|
package/src/inventory.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { call, post } from './task.js';
|
|
|
2
2
|
import type { TaskOptions } from './task.js';
|
|
3
3
|
import type { ItemStack } from './item.js';
|
|
4
4
|
import { InstanceId } from './instance-id.js';
|
|
5
|
+
import { resolveUuid } from './target.js';
|
|
6
|
+
import type { PlayerTarget } from './target.js';
|
|
5
7
|
|
|
6
8
|
/**
|
|
7
9
|
* Inventory —— 统一容器抽象,三种持有者:
|
|
@@ -141,9 +143,9 @@ export class Inventory {
|
|
|
141
143
|
|
|
142
144
|
// ── 自定义 Inventory 专属 ─────────────────────────────────────────
|
|
143
145
|
|
|
144
|
-
/** 为玩家打开(自定义 Inventory)。 */
|
|
145
|
-
open(
|
|
146
|
-
return post<boolean>('inventory.open', { ...this.address(), uuid }, options);
|
|
146
|
+
/** 为玩家打开(自定义 Inventory;接受 `Player` 对象或 uuid)。 */
|
|
147
|
+
open(player: PlayerTarget, options?: TaskOptions): Promise<boolean> {
|
|
148
|
+
return post<boolean>('inventory.open', { ...this.address(), uuid: resolveUuid(player) }, options);
|
|
147
149
|
}
|
|
148
150
|
|
|
149
151
|
/** 关闭所有查看者(自定义 Inventory)。 */
|
|
@@ -151,9 +153,9 @@ export class Inventory {
|
|
|
151
153
|
return post<boolean>('inventory.close', this.address(), options);
|
|
152
154
|
}
|
|
153
155
|
|
|
154
|
-
/** 仅关闭指定玩家(自定义 Inventory)。 */
|
|
155
|
-
closePlayer(
|
|
156
|
-
return post<boolean>('inventory.closePlayer', { ...this.address(), uuid }, options);
|
|
156
|
+
/** 仅关闭指定玩家(自定义 Inventory;接受 `Player` 对象或 uuid)。 */
|
|
157
|
+
closePlayer(player: PlayerTarget, options?: TaskOptions): Promise<boolean> {
|
|
158
|
+
return post<boolean>('inventory.closePlayer', { ...this.address(), uuid: resolveUuid(player) }, options);
|
|
157
159
|
}
|
|
158
160
|
|
|
159
161
|
/** 当前查看者 uuid 列表(自定义 Inventory)。 */
|
package/src/material.ts
CHANGED
|
@@ -55,4 +55,12 @@ export const Material = {
|
|
|
55
55
|
isAirSync(type: string, options?: TaskOptions): boolean {
|
|
56
56
|
return call<boolean>('material.isAir', { type }, options);
|
|
57
57
|
},
|
|
58
|
+
|
|
59
|
+
/** 最大耐久(非耐用品返回 0;未知类型抛错)。 */
|
|
60
|
+
getMaxDurability(type: string, options?: TaskOptions): Promise<number> {
|
|
61
|
+
return post<number>('material.getMaxDurability', { type }, options);
|
|
62
|
+
},
|
|
63
|
+
getMaxDurabilitySync(type: string, options?: TaskOptions): number {
|
|
64
|
+
return call<number>('material.getMaxDurability', { type }, options);
|
|
65
|
+
},
|
|
58
66
|
};
|
package/src/player.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { call, post } from './task.js';
|
|
2
2
|
import type { TaskOptions } from './task.js';
|
|
3
|
+
import { LivingEntity } from './entity.js';
|
|
3
4
|
import { Location, LocationData } from './location.js';
|
|
4
5
|
import type { ItemStack } from './item.js';
|
|
5
6
|
import { Block } from './block.js';
|
|
6
7
|
import type { Message } from './message.js';
|
|
7
8
|
import type { Permission } from './permission.js';
|
|
9
|
+
import type { AdvancementProgress } from './advancement.js';
|
|
8
10
|
import { Inventory } from './inventory.js';
|
|
9
11
|
import {
|
|
10
12
|
get as pdcGet, set as pdcSet, has as pdcHas, remove as pdcRemove,
|
|
@@ -16,7 +18,7 @@ interface PlayerData {
|
|
|
16
18
|
name: string;
|
|
17
19
|
}
|
|
18
20
|
|
|
19
|
-
export class Player {
|
|
21
|
+
export class Player extends LivingEntity {
|
|
20
22
|
static get(identifier: string, options?: TaskOptions): Promise<Player | null> {
|
|
21
23
|
return post<PlayerData>('player.get', { identifier }, options).then((d) => (d ? new Player(d.uuid, d.name) : null));
|
|
22
24
|
}
|
|
@@ -31,7 +33,10 @@ export class Player {
|
|
|
31
33
|
return call<PlayerData[]>('player.getAll', {}, options).map((r) => new Player(r.uuid, r.name));
|
|
32
34
|
}
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
// uuid 由 Entity 基类持有(readonly);本类扩展玩家特有字段。
|
|
37
|
+
constructor(uuid: string, private _name?: string) {
|
|
38
|
+
super(uuid);
|
|
39
|
+
}
|
|
35
40
|
|
|
36
41
|
/** 玩家名。未提供时首次访问惰性同步获取并缓存(仅一次往返)。 */
|
|
37
42
|
get name(): string {
|
|
@@ -153,6 +158,20 @@ export class Player {
|
|
|
153
158
|
playSoundSync(sound: string, volume?: number, pitch?: number, options?: TaskOptions): void {
|
|
154
159
|
call('player.playSound', { uuid: this.uuid, sound, volume, pitch }, options);
|
|
155
160
|
}
|
|
161
|
+
/** 停止播放指定音效。 */
|
|
162
|
+
stopSound(sound: string, options?: TaskOptions): Promise<void> {
|
|
163
|
+
return post('player.stopSound', { uuid: this.uuid, sound }, options);
|
|
164
|
+
}
|
|
165
|
+
stopSoundSync(sound: string, options?: TaskOptions): void {
|
|
166
|
+
call('player.stopSound', { uuid: this.uuid, sound }, options);
|
|
167
|
+
}
|
|
168
|
+
/** 停止该玩家所有音效。 */
|
|
169
|
+
stopAllSounds(options?: TaskOptions): Promise<void> {
|
|
170
|
+
return post('player.stopAllSounds', { uuid: this.uuid }, options);
|
|
171
|
+
}
|
|
172
|
+
stopAllSoundsSync(options?: TaskOptions): void {
|
|
173
|
+
call('player.stopAllSounds', { uuid: this.uuid }, options);
|
|
174
|
+
}
|
|
156
175
|
giveExp(amount: number, options?: TaskOptions): Promise<void> { return post('player.giveExp', { uuid: this.uuid, amount }, options); }
|
|
157
176
|
giveExpSync(amount: number, options?: TaskOptions): void { call('player.giveExp', { uuid: this.uuid, amount }, options); }
|
|
158
177
|
/** 检查权限(经 Yeow 权限检查:`permissionCheck` 事件优先,无处理时回退 Bukkit)。node 可为权限节点对象。 */
|
|
@@ -169,6 +188,41 @@ export class Player {
|
|
|
169
188
|
performCommandSync(cmd: string, options?: TaskOptions): boolean {
|
|
170
189
|
return call<boolean>('player.performCommand', { uuid: this.uuid, command: cmd.replace(/^\//, '') }, options);
|
|
171
190
|
}
|
|
191
|
+
/** 授予进度全部条件。 */
|
|
192
|
+
grantAdvancement(key: string, options?: TaskOptions): Promise<boolean> {
|
|
193
|
+
return post<boolean>('advancement.grant', { uuid: this.uuid, key }, options);
|
|
194
|
+
}
|
|
195
|
+
grantAdvancementSync(key: string, options?: TaskOptions): boolean {
|
|
196
|
+
return call<boolean>('advancement.grant', { uuid: this.uuid, key }, options);
|
|
197
|
+
}
|
|
198
|
+
/** 撤销进度全部条件。 */
|
|
199
|
+
revokeAdvancement(key: string, options?: TaskOptions): Promise<boolean> {
|
|
200
|
+
return post<boolean>('advancement.revoke', { uuid: this.uuid, key }, options);
|
|
201
|
+
}
|
|
202
|
+
revokeAdvancementSync(key: string, options?: TaskOptions): boolean {
|
|
203
|
+
return call<boolean>('advancement.revoke', { uuid: this.uuid, key }, options);
|
|
204
|
+
}
|
|
205
|
+
/** 查询进度完成情况。 */
|
|
206
|
+
getAdvancementProgress(key: string, options?: TaskOptions): Promise<AdvancementProgress | null> {
|
|
207
|
+
return post<AdvancementProgress | null>('advancement.getProgress', { uuid: this.uuid, key }, options);
|
|
208
|
+
}
|
|
209
|
+
getAdvancementProgressSync(key: string, options?: TaskOptions): AdvancementProgress | null {
|
|
210
|
+
return call<AdvancementProgress | null>('advancement.getProgress', { uuid: this.uuid, key }, options);
|
|
211
|
+
}
|
|
212
|
+
/** 授予进度单个条件。 */
|
|
213
|
+
awardCriteria(key: string, criteria: string, options?: TaskOptions): Promise<boolean> {
|
|
214
|
+
return post<boolean>('advancement.awardCriteria', { uuid: this.uuid, key, criteria }, options);
|
|
215
|
+
}
|
|
216
|
+
awardCriteriaSync(key: string, criteria: string, options?: TaskOptions): boolean {
|
|
217
|
+
return call<boolean>('advancement.awardCriteria', { uuid: this.uuid, key, criteria }, options);
|
|
218
|
+
}
|
|
219
|
+
/** 撤销进度单个条件。 */
|
|
220
|
+
revokeCriteria(key: string, criteria: string, options?: TaskOptions): Promise<boolean> {
|
|
221
|
+
return post<boolean>('advancement.revokeCriteria', { uuid: this.uuid, key, criteria }, options);
|
|
222
|
+
}
|
|
223
|
+
revokeCriteriaSync(key: string, criteria: string, options?: TaskOptions): boolean {
|
|
224
|
+
return call<boolean>('advancement.revokeCriteria', { uuid: this.uuid, key, criteria }, options);
|
|
225
|
+
}
|
|
172
226
|
teleport(loc: Location, options?: TaskOptions): Promise<void> { return post('player.teleport', { uuid: this.uuid, ...loc.toObject() }, options); }
|
|
173
227
|
teleportSync(loc: Location, options?: TaskOptions): void { call('player.teleport', { uuid: this.uuid, ...loc.toObject() }, options); }
|
|
174
228
|
/** 向玩家发送假方块变化(仅客户端视觉,不改变真实世界)。block 为 Block 对象或字符串(同 world.setBlock,字符串无状态)。 */
|
|
@@ -236,14 +290,6 @@ export class Player {
|
|
|
236
290
|
return call<boolean>('player.setPlayerListName', { uuid: this.uuid, name }, options);
|
|
237
291
|
}
|
|
238
292
|
|
|
239
|
-
/** 设置客户端世界边界(传 null 重置为服务端边界;centerX/centerZ 可选,指定边界中心)。 */
|
|
240
|
-
setBorder(size: number | null, centerX?: number, centerZ?: number, options?: TaskOptions): Promise<boolean> {
|
|
241
|
-
return post<boolean>('player.setBorder', { uuid: this.uuid, size, centerX, centerZ }, options);
|
|
242
|
-
}
|
|
243
|
-
setBorderSync(size: number | null, centerX?: number, centerZ?: number, options?: TaskOptions): boolean {
|
|
244
|
-
return call<boolean>('player.setBorder', { uuid: this.uuid, size, centerX, centerZ }, options);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
293
|
// ── PDC(玩家持久数据) ──
|
|
248
294
|
|
|
249
295
|
/** 读取并 JSON 反序列化(无值返回 null;旧数据非 JSON 时原样返回字符串)。 */
|
package/src/potion.ts
CHANGED
|
@@ -1,24 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// 药水效果类型定义。操作已上移到 `entity.ts` 的 LivingEntity 实例方法
|
|
2
|
+
// (`entity.addPotionEffect(...)` 等)——不再提供顶层 uuid 函数。
|
|
3
3
|
|
|
4
|
+
/** 药水效果(`entity.addPotionEffect` 任务载荷;与 `getActivePotionEffects` 输出同结构)。 */
|
|
4
5
|
export interface PotionEffect {
|
|
6
|
+
/** 药水效果类型(值域 R1 注册键,如 `minecraft:speed`;兼容旧枚举名,大小写不敏感)。 */
|
|
5
7
|
type: string;
|
|
8
|
+
/** 持续时间(tick)。 */
|
|
6
9
|
duration: number;
|
|
10
|
+
/** 等级(0 = 一级)。 */
|
|
7
11
|
amplifier: number;
|
|
12
|
+
/** 是否环境指示剂(默认 true)。 */
|
|
8
13
|
ambient?: boolean;
|
|
14
|
+
/** 是否显示粒子(默认 true)。 */
|
|
9
15
|
particles?: boolean;
|
|
16
|
+
/** 是否显示图标(默认 true)。 */
|
|
10
17
|
icon?: boolean;
|
|
11
18
|
}
|
|
12
|
-
|
|
13
|
-
export function addPotionEffect(uuid: string, effect: PotionEffect, options?: TaskOptions): Promise<void> {
|
|
14
|
-
return post('entity.addPotionEffect', { uuid, ...effect }, options);
|
|
15
|
-
}
|
|
16
|
-
export function removePotionEffect(uuid: string, type: string, options?: TaskOptions): Promise<void> {
|
|
17
|
-
return post('entity.removePotionEffect', { uuid, type }, options);
|
|
18
|
-
}
|
|
19
|
-
export function clearPotionEffects(uuid: string, options?: TaskOptions): Promise<void> {
|
|
20
|
-
return post('entity.clearPotionEffects', { uuid }, options);
|
|
21
|
-
}
|
|
22
|
-
export function getActivePotionEffects(uuid: string, options?: TaskOptions): Promise<PotionEffect[]> {
|
|
23
|
-
return post<PotionEffect[]>('entity.getActivePotionEffects', { uuid }, options);
|
|
24
|
-
}
|
package/src/scoreboard.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
import { post } from './task.js';
|
|
1
|
+
import { call, post } from './task.js';
|
|
2
2
|
import type { TaskOptions } from './task.js';
|
|
3
|
+
import { resolveUuid } from './target.js';
|
|
4
|
+
import type { PlayerTarget } from './target.js';
|
|
3
5
|
|
|
4
6
|
export interface ObjectiveInfo {
|
|
5
7
|
name: string;
|
|
@@ -23,117 +25,280 @@ export interface TeamInfo {
|
|
|
23
25
|
};
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
+
/** 线缆 board 参数:自定义计分板注入 `{ board: <id> }`,主计分板为空。 */
|
|
29
|
+
function wireBoard(boardId: string | null): Record<string, unknown> {
|
|
30
|
+
return boardId != null ? { board: boardId } : {};
|
|
28
31
|
}
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
return post<string>('scoreboard.createBoard', { id }, options);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export function deleteBoard(id: string, options?: TaskOptions): Promise<void> {
|
|
37
|
-
return post('scoreboard.deleteBoard', { id }, options);
|
|
33
|
+
/** 计分板 entry 解析:Player 对象取其玩家名(Bukkit 计分板按玩家名登记),字符串原样。 */
|
|
34
|
+
function resolveEntry(t: PlayerTarget): string {
|
|
35
|
+
return typeof t === 'string' ? t : t.name;
|
|
38
36
|
}
|
|
39
37
|
|
|
40
|
-
// ── Objectives ──
|
|
41
|
-
|
|
42
38
|
/**
|
|
43
|
-
*
|
|
44
|
-
*
|
|
45
|
-
*
|
|
39
|
+
* Scoreboard —— 计分板对象(OOP)。主计分板用 `Scoreboard.main()`,自定义用
|
|
40
|
+
* `Scoreboard.create(id)`;Objective / Team / Score 操作都在对应对象上调用,
|
|
41
|
+
* 不再反复传 `board`/裸名。
|
|
42
|
+
*
|
|
43
|
+
* ```js
|
|
44
|
+
* const board = await Scoreboard.create('myBoard');
|
|
45
|
+
* const obj = await board.createObjective('kills', 'dummy', '<red>Kills</red>');
|
|
46
|
+
* await obj.setDisplay('SIDEBAR');
|
|
47
|
+
* await obj.setScore(player, 42); // 接受 Player 对象或 entry 字符串
|
|
48
|
+
* const team = await board.createTeam('red');
|
|
49
|
+
* await team.add(player);
|
|
50
|
+
* await board.attach(player); // 为该玩家设置个人计分板
|
|
51
|
+
* await board.destroy();
|
|
52
|
+
* ```
|
|
53
|
+
*
|
|
54
|
+
* > **Folia 限制**:Folia 不支持注册新 objective/team(`createObjective` / `createTeam`
|
|
55
|
+
* > 会 reject);读取与修改已存在对象(`setScore` / `setTeamPrefix` 等)可用。
|
|
46
56
|
*/
|
|
47
|
-
export
|
|
48
|
-
|
|
49
|
-
}
|
|
57
|
+
export class Scoreboard {
|
|
58
|
+
private constructor(readonly id: string | null) {}
|
|
50
59
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
60
|
+
/** 主计分板(服务器默认)。 */
|
|
61
|
+
static main(): Scoreboard {
|
|
62
|
+
return new Scoreboard(null);
|
|
63
|
+
}
|
|
54
64
|
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
65
|
+
/** 创建自定义计分板(返回自身句柄)。 */
|
|
66
|
+
static async create(id: string, options?: TaskOptions): Promise<Scoreboard> {
|
|
67
|
+
await post('scoreboard.createBoard', { id }, options);
|
|
68
|
+
return new Scoreboard(id);
|
|
69
|
+
}
|
|
58
70
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
71
|
+
static createSync(id: string, options?: TaskOptions): Scoreboard {
|
|
72
|
+
call('scoreboard.createBoard', { id }, options);
|
|
73
|
+
return new Scoreboard(id);
|
|
74
|
+
}
|
|
62
75
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
76
|
+
/** 销毁自定义计分板(主计分板不可销毁,抛错)。 */
|
|
77
|
+
destroy(options?: TaskOptions): Promise<void> {
|
|
78
|
+
if (this.id == null) return Promise.reject(new Error('cannot destroy main scoreboard'));
|
|
79
|
+
return post('scoreboard.deleteBoard', { id: this.id }, options);
|
|
80
|
+
}
|
|
81
|
+
destroySync(options?: TaskOptions): void {
|
|
82
|
+
if (this.id == null) throw new Error('cannot destroy main scoreboard');
|
|
83
|
+
call('scoreboard.deleteBoard', { id: this.id }, options);
|
|
84
|
+
}
|
|
66
85
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
}
|
|
86
|
+
/** 为该玩家设置其个人计分板为本计分板(接受 `Player` 对象或 uuid;重置用 `Scoreboard.main().attach(player)`)。 */
|
|
87
|
+
attach(player: PlayerTarget, options?: TaskOptions): Promise<void> {
|
|
88
|
+
return post('scoreboard.setPlayerBoard', { uuid: resolveUuid(player), ...wireBoard(this.id) }, options);
|
|
89
|
+
}
|
|
90
|
+
attachSync(player: PlayerTarget, options?: TaskOptions): void {
|
|
91
|
+
call('scoreboard.setPlayerBoard', { uuid: resolveUuid(player), ...wireBoard(this.id) }, options);
|
|
92
|
+
}
|
|
70
93
|
|
|
71
|
-
|
|
72
|
-
return post('scoreboard.resetScore', { objective, entry, ...boardParam(board) }, options);
|
|
73
|
-
}
|
|
94
|
+
// ── Objective ──
|
|
74
95
|
|
|
75
|
-
|
|
96
|
+
createObjective(name: string, criteria: string, displayName: string, options?: TaskOptions): Promise<Objective> {
|
|
97
|
+
return post<{ name: string; criteria: string }>('scoreboard.createObjective', { name, criteria, displayName, ...wireBoard(this.id) }, options)
|
|
98
|
+
.then((o) => new Objective(this.id, o.name, o.criteria, null));
|
|
99
|
+
}
|
|
100
|
+
createObjectiveSync(name: string, criteria: string, displayName: string, options?: TaskOptions): Objective {
|
|
101
|
+
const o = call<{ name: string; criteria: string }>('scoreboard.createObjective', { name, criteria, displayName, ...wireBoard(this.id) }, options);
|
|
102
|
+
return new Objective(this.id, o.name, o.criteria, null);
|
|
103
|
+
}
|
|
76
104
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
105
|
+
getObjectives(options?: TaskOptions): Promise<Objective[]> {
|
|
106
|
+
return post<ObjectiveInfo[]>('scoreboard.getObjectives', { ...wireBoard(this.id) }, options)
|
|
107
|
+
.then((list) => list.map((o) => new Objective(this.id, o.name, o.criteria, o.displaySlot)));
|
|
108
|
+
}
|
|
109
|
+
getObjectivesSync(options?: TaskOptions): Objective[] {
|
|
110
|
+
return call<ObjectiveInfo[]>('scoreboard.getObjectives', { ...wireBoard(this.id) }, options)
|
|
111
|
+
.map((o) => new Objective(this.id, o.name, o.criteria, o.displaySlot));
|
|
112
|
+
}
|
|
84
113
|
|
|
85
|
-
|
|
86
|
-
return post('scoreboard.deleteTeam', { name, ...boardParam(board) }, options);
|
|
87
|
-
}
|
|
114
|
+
// ── Team ──
|
|
88
115
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
116
|
+
createTeam(name: string, options?: TaskOptions): Promise<Team> {
|
|
117
|
+
return post('scoreboard.createTeam', { name, ...wireBoard(this.id) }, options)
|
|
118
|
+
.then(() => this.getTeam(name))
|
|
119
|
+
.then((t) => {
|
|
120
|
+
if (!t) throw new Error('team created but not found: ' + name);
|
|
121
|
+
return t;
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
createTeamSync(name: string, options?: TaskOptions): Team {
|
|
125
|
+
call('scoreboard.createTeam', { name, ...wireBoard(this.id) }, options);
|
|
126
|
+
const t = this.getTeamSync(name);
|
|
127
|
+
if (!t) throw new Error('team created but not found: ' + name);
|
|
128
|
+
return t;
|
|
129
|
+
}
|
|
92
130
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
131
|
+
getTeam(name: string, options?: TaskOptions): Promise<Team | null> {
|
|
132
|
+
return post<TeamInfo | null>('scoreboard.getTeam', { name, ...wireBoard(this.id) }, options)
|
|
133
|
+
.then((info) => (info ? new Team(this.id, info) : null));
|
|
134
|
+
}
|
|
135
|
+
getTeamSync(name: string, options?: TaskOptions): Team | null {
|
|
136
|
+
const info = call<TeamInfo | null>('scoreboard.getTeam', { name, ...wireBoard(this.id) }, options);
|
|
137
|
+
return info ? new Team(this.id, info) : null;
|
|
138
|
+
}
|
|
96
139
|
|
|
97
|
-
|
|
98
|
-
|
|
140
|
+
getTeams(options?: TaskOptions): Promise<Team[]> {
|
|
141
|
+
return post<TeamInfo[]>('scoreboard.getTeams', { ...wireBoard(this.id) }, options)
|
|
142
|
+
.then((list) => list.map((info) => new Team(this.id, info)));
|
|
143
|
+
}
|
|
144
|
+
getTeamsSync(options?: TaskOptions): Team[] {
|
|
145
|
+
return call<TeamInfo[]>('scoreboard.getTeams', { ...wireBoard(this.id) }, options)
|
|
146
|
+
.map((info) => new Team(this.id, info));
|
|
147
|
+
}
|
|
99
148
|
}
|
|
100
149
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
150
|
+
/** 计分项(objective)句柄。 */
|
|
151
|
+
export class Objective {
|
|
152
|
+
constructor(
|
|
153
|
+
private readonly boardId: string | null,
|
|
154
|
+
public readonly name: string,
|
|
155
|
+
public readonly criteria?: string,
|
|
156
|
+
public readonly displaySlot: string | null = null,
|
|
157
|
+
) {}
|
|
104
158
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
159
|
+
/** 设置显示位置(slot 为 BELOW_NAME/PLAYER_LIST/SIDEBAR;null 取消显示)。 */
|
|
160
|
+
setDisplay(slot: string | null, options?: TaskOptions): Promise<boolean> {
|
|
161
|
+
return post<boolean>('scoreboard.setObjectiveDisplay', { name: this.name, slot, ...wireBoard(this.boardId) }, options);
|
|
162
|
+
}
|
|
163
|
+
setDisplaySync(slot: string | null, options?: TaskOptions): boolean {
|
|
164
|
+
return call<boolean>('scoreboard.setObjectiveDisplay', { name: this.name, slot, ...wireBoard(this.boardId) }, options);
|
|
165
|
+
}
|
|
108
166
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
167
|
+
/** 设置分数(target 为 `Player` 对象或 entry 字符串)。 */
|
|
168
|
+
setScore(target: PlayerTarget, value: number, options?: TaskOptions): Promise<void> {
|
|
169
|
+
return post('scoreboard.setScore', { objective: this.name, entry: resolveEntry(target), value, ...wireBoard(this.boardId) }, options);
|
|
170
|
+
}
|
|
171
|
+
setScoreSync(target: PlayerTarget, value: number, options?: TaskOptions): void {
|
|
172
|
+
call('scoreboard.setScore', { objective: this.name, entry: resolveEntry(target), value, ...wireBoard(this.boardId) }, options);
|
|
173
|
+
}
|
|
112
174
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
175
|
+
/** 查询分数(无记录返回 null)。 */
|
|
176
|
+
getScore(target: PlayerTarget, options?: TaskOptions): Promise<number | null> {
|
|
177
|
+
return post<number | null>('scoreboard.getScore', { objective: this.name, entry: resolveEntry(target), ...wireBoard(this.boardId) }, options);
|
|
178
|
+
}
|
|
179
|
+
getScoreSync(target: PlayerTarget, options?: TaskOptions): number | null {
|
|
180
|
+
return call<number | null>('scoreboard.getScore', { objective: this.name, entry: resolveEntry(target), ...wireBoard(this.boardId) }, options);
|
|
181
|
+
}
|
|
116
182
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
}
|
|
183
|
+
/** 重置(清除)分数。 */
|
|
184
|
+
resetScore(target: PlayerTarget, options?: TaskOptions): Promise<void> {
|
|
185
|
+
return post('scoreboard.resetScore', { objective: this.name, entry: resolveEntry(target), ...wireBoard(this.boardId) }, options);
|
|
186
|
+
}
|
|
187
|
+
resetScoreSync(target: PlayerTarget, options?: TaskOptions): void {
|
|
188
|
+
call('scoreboard.resetScore', { objective: this.name, entry: resolveEntry(target), ...wireBoard(this.boardId) }, options);
|
|
189
|
+
}
|
|
120
190
|
|
|
121
|
-
|
|
122
|
-
|
|
191
|
+
/** 删除此计分项。 */
|
|
192
|
+
delete(options?: TaskOptions): Promise<void> {
|
|
193
|
+
return post('scoreboard.deleteObjective', { name: this.name, ...wireBoard(this.boardId) }, options);
|
|
194
|
+
}
|
|
195
|
+
deleteSync(options?: TaskOptions): void {
|
|
196
|
+
call('scoreboard.deleteObjective', { name: this.name, ...wireBoard(this.boardId) }, options);
|
|
197
|
+
}
|
|
123
198
|
}
|
|
124
199
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
200
|
+
/** 队伍(team)句柄;携带读取时刻的快照字段。 */
|
|
201
|
+
export class Team {
|
|
202
|
+
readonly name: string;
|
|
203
|
+
readonly displayName: string;
|
|
204
|
+
readonly prefix: string;
|
|
205
|
+
readonly suffix: string;
|
|
206
|
+
readonly color: string;
|
|
207
|
+
readonly allowFriendlyFire: boolean;
|
|
208
|
+
readonly canSeeFriendlyInvisibles: boolean;
|
|
209
|
+
readonly entries: string[];
|
|
210
|
+
readonly options: TeamInfo['options'];
|
|
128
211
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
212
|
+
constructor(private readonly boardId: string | null, info: TeamInfo) {
|
|
213
|
+
this.name = info.name;
|
|
214
|
+
this.displayName = info.displayName;
|
|
215
|
+
this.prefix = info.prefix;
|
|
216
|
+
this.suffix = info.suffix;
|
|
217
|
+
this.color = info.color;
|
|
218
|
+
this.allowFriendlyFire = info.allowFriendlyFire;
|
|
219
|
+
this.canSeeFriendlyInvisibles = info.canSeeFriendlyInvisibles;
|
|
220
|
+
this.entries = info.entries;
|
|
221
|
+
this.options = info.options;
|
|
222
|
+
}
|
|
132
223
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
}
|
|
224
|
+
setDisplayName(v: string, options?: TaskOptions): Promise<void> {
|
|
225
|
+
return post('scoreboard.setTeamDisplayName', { name: this.name, displayName: v, ...wireBoard(this.boardId) }, options);
|
|
226
|
+
}
|
|
227
|
+
setDisplayNameSync(v: string, options?: TaskOptions): void {
|
|
228
|
+
call('scoreboard.setTeamDisplayName', { name: this.name, displayName: v, ...wireBoard(this.boardId) }, options);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
setPrefix(v: string, options?: TaskOptions): Promise<void> {
|
|
232
|
+
return post('scoreboard.setTeamPrefix', { name: this.name, prefix: v, ...wireBoard(this.boardId) }, options);
|
|
233
|
+
}
|
|
234
|
+
setPrefixSync(v: string, options?: TaskOptions): void {
|
|
235
|
+
call('scoreboard.setTeamPrefix', { name: this.name, prefix: v, ...wireBoard(this.boardId) }, options);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
setSuffix(v: string, options?: TaskOptions): Promise<void> {
|
|
239
|
+
return post('scoreboard.setTeamSuffix', { name: this.name, suffix: v, ...wireBoard(this.boardId) }, options);
|
|
240
|
+
}
|
|
241
|
+
setSuffixSync(v: string, options?: TaskOptions): void {
|
|
242
|
+
call('scoreboard.setTeamSuffix', { name: this.name, suffix: v, ...wireBoard(this.boardId) }, options);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
setColor(v: string, options?: TaskOptions): Promise<void> {
|
|
246
|
+
return post('scoreboard.setTeamColor', { name: this.name, color: v, ...wireBoard(this.boardId) }, options);
|
|
247
|
+
}
|
|
248
|
+
setColorSync(v: string, options?: TaskOptions): void {
|
|
249
|
+
call('scoreboard.setTeamColor', { name: this.name, color: v, ...wireBoard(this.boardId) }, options);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
setFriendlyFire(allow: boolean, options?: TaskOptions): Promise<void> {
|
|
253
|
+
return post('scoreboard.setTeamFriendlyFire', { name: this.name, allow, ...wireBoard(this.boardId) }, options);
|
|
254
|
+
}
|
|
255
|
+
setFriendlyFireSync(allow: boolean, options?: TaskOptions): void {
|
|
256
|
+
call('scoreboard.setTeamFriendlyFire', { name: this.name, allow, ...wireBoard(this.boardId) }, options);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
setSeeInvisible(canSee: boolean, options?: TaskOptions): Promise<void> {
|
|
260
|
+
return post('scoreboard.setTeamSeeInvisible', { name: this.name, canSee, ...wireBoard(this.boardId) }, options);
|
|
261
|
+
}
|
|
262
|
+
setSeeInvisibleSync(canSee: boolean, options?: TaskOptions): void {
|
|
263
|
+
call('scoreboard.setTeamSeeInvisible', { name: this.name, canSee, ...wireBoard(this.boardId) }, options);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
setOption(option: string, value: string, options?: TaskOptions): Promise<void> {
|
|
267
|
+
return post('scoreboard.setTeamOption', { name: this.name, option, value, ...wireBoard(this.boardId) }, options);
|
|
268
|
+
}
|
|
269
|
+
setOptionSync(option: string, value: string, options?: TaskOptions): void {
|
|
270
|
+
call('scoreboard.setTeamOption', { name: this.name, option, value, ...wireBoard(this.boardId) }, options);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** 添加成员(`Player` 对象取其名,或 entry 字符串)。 */
|
|
274
|
+
add(target: PlayerTarget, options?: TaskOptions): Promise<void> {
|
|
275
|
+
return post('scoreboard.teamAddEntry', { name: this.name, entry: resolveEntry(target), ...wireBoard(this.boardId) }, options);
|
|
276
|
+
}
|
|
277
|
+
addSync(target: PlayerTarget, options?: TaskOptions): void {
|
|
278
|
+
call('scoreboard.teamAddEntry', { name: this.name, entry: resolveEntry(target), ...wireBoard(this.boardId) }, options);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** 移除成员。 */
|
|
282
|
+
remove(target: PlayerTarget, options?: TaskOptions): Promise<void> {
|
|
283
|
+
return post('scoreboard.teamRemoveEntry', { name: this.name, entry: resolveEntry(target), ...wireBoard(this.boardId) }, options);
|
|
284
|
+
}
|
|
285
|
+
removeSync(target: PlayerTarget, options?: TaskOptions): void {
|
|
286
|
+
call('scoreboard.teamRemoveEntry', { name: this.name, entry: resolveEntry(target), ...wireBoard(this.boardId) }, options);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** 成员列表(快照)。 */
|
|
290
|
+
getEntries(options?: TaskOptions): Promise<string[]> {
|
|
291
|
+
return post<string[]>('scoreboard.teamGetEntries', { name: this.name, ...wireBoard(this.boardId) }, options);
|
|
292
|
+
}
|
|
293
|
+
getEntriesSync(options?: TaskOptions): string[] {
|
|
294
|
+
return call<string[]>('scoreboard.teamGetEntries', { name: this.name, ...wireBoard(this.boardId) }, options);
|
|
295
|
+
}
|
|
136
296
|
|
|
137
|
-
|
|
138
|
-
|
|
297
|
+
/** 删除队伍。 */
|
|
298
|
+
delete(options?: TaskOptions): Promise<void> {
|
|
299
|
+
return post('scoreboard.deleteTeam', { name: this.name, ...wireBoard(this.boardId) }, options);
|
|
300
|
+
}
|
|
301
|
+
deleteSync(options?: TaskOptions): void {
|
|
302
|
+
call('scoreboard.deleteTeam', { name: this.name, ...wireBoard(this.boardId) }, options);
|
|
303
|
+
}
|
|
139
304
|
}
|
package/src/sound.ts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
import { post } from './task.js';
|
|
2
2
|
import type { TaskOptions } from './task.js';
|
|
3
3
|
|
|
4
|
+
// 玩家侧 stopSound/stopAllSounds 已上移到 `player.ts` 的 Player 实例方法
|
|
5
|
+
// (`player.stopSound(sound)` / `player.stopAllSounds()`)——不再提供顶层 uuid 函数。
|
|
6
|
+
|
|
7
|
+
/** 世界级音效(在指定世界坐标播放,对范围内玩家生效)。 */
|
|
4
8
|
export function playSound(world: string, sound: string, x: number, y: number, z: number, volume?: number, pitch?: number, options?: TaskOptions): Promise<void> {
|
|
5
9
|
return post('world.playSound', { world, sound, x, y, z, volume, pitch }, options);
|
|
6
10
|
}
|
|
7
|
-
|
|
8
|
-
export function stopSound(uuid: string, sound: string, options?: TaskOptions): Promise<void> {
|
|
9
|
-
return post('player.stopSound', { uuid, sound }, options);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function stopAllSounds(uuid: string, options?: TaskOptions): Promise<void> {
|
|
13
|
-
return post('player.stopAllSounds', { uuid }, options);
|
|
14
|
-
}
|
package/src/target.ts
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Player } from './player.js';
|
|
2
|
+
import type { Entity, LivingEntity } from './entity.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* 以玩家/实体为目标的参数统一类型:**对象或字符串**。
|
|
6
|
+
*
|
|
7
|
+
* 传对象(`Player` / `LivingEntity` / `Entity`)时取其 `uuid`;传字符串时按原样
|
|
8
|
+
* 当作 uuid(或按具体 API 上下文为玩家名——如计分板 entry)。彻底消除
|
|
9
|
+
* 「必须手动传 uuid」的摩擦:有对象直接传对象,只有原始 id 时才传字符串。
|
|
10
|
+
*/
|
|
11
|
+
export type PlayerTarget = Player | string;
|
|
12
|
+
|
|
13
|
+
export type LivingTarget = LivingEntity | string;
|
|
14
|
+
|
|
15
|
+
export type EntityTarget = Entity | string;
|
|
16
|
+
|
|
17
|
+
/** 解析目标 → uuid:对象取其 `uuid`,字符串原样返回。 */
|
|
18
|
+
export function resolveUuid(t: PlayerTarget | LivingTarget | EntityTarget): string {
|
|
19
|
+
return typeof t === 'string' ? t : t.uuid;
|
|
20
|
+
}
|
package/src/util.ts
CHANGED
|
@@ -31,25 +31,25 @@ function toB64(data: Uint8Array | string): string {
|
|
|
31
31
|
: data.toBase64();
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
// ── 字符串 ↔ 字节(UTF-8
|
|
34
|
+
// ── 字符串 ↔ 字节(UTF-8;默认异步,同步加 Sync 后缀)──────────────
|
|
35
35
|
|
|
36
36
|
/** UTF-8 字符串 → 字节(同步)。 */
|
|
37
|
-
export function
|
|
37
|
+
export function stringToBytesSync(text: string): Uint8Array {
|
|
38
38
|
return Uint8Array.fromBase64(send<{ data: string }>('encode.utf8', { data: text }).data);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
/** 字节 → UTF-8 字符串(同步;非法序列替换为 U+FFFD,不抛错)。 */
|
|
42
|
-
export function
|
|
42
|
+
export function bytesToStringSync(bytes: Uint8Array): string {
|
|
43
43
|
return send<{ data: string }>('decode.utf8', { data: bytes.toBase64() }).data;
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
/** UTF-8 字符串 → 字节(异步,ioExecutor
|
|
47
|
-
export function
|
|
46
|
+
/** UTF-8 字符串 → 字节(异步,ioExecutor 执行;默认)。 */
|
|
47
|
+
export function stringToBytes(text: string): Promise<Uint8Array> {
|
|
48
48
|
return sendAsync<{ data: string }>('encode.utf8', { data: text }).then((r) => Uint8Array.fromBase64(r.data));
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
/** 字节 → UTF-8
|
|
52
|
-
export function
|
|
51
|
+
/** 字节 → UTF-8 字符串(异步;非法序列替换为 U+FFFD)。 */
|
|
52
|
+
export function bytesToString(bytes: Uint8Array): Promise<string> {
|
|
53
53
|
return sendAsync<{ data: string }>('decode.utf8', { data: bytes.toBase64() }).then((r) => r.data);
|
|
54
54
|
}
|
|
55
55
|
|
package/src/world.ts
CHANGED
|
@@ -133,6 +133,12 @@ export class World {
|
|
|
133
133
|
isChunkLoadedSync(x: number, z: number, options?: TaskOptions): boolean {
|
|
134
134
|
return call<boolean>('world.isChunkLoaded', { world: this.name, x, z }, options);
|
|
135
135
|
}
|
|
136
|
+
isChunkGenerated(x: number, z: number, options?: TaskOptions): Promise<boolean> {
|
|
137
|
+
return post<boolean>('world.isChunkGenerated', { world: this.name, x, z }, options);
|
|
138
|
+
}
|
|
139
|
+
isChunkGeneratedSync(x: number, z: number, options?: TaskOptions): boolean {
|
|
140
|
+
return call<boolean>('world.isChunkGenerated', { world: this.name, x, z }, options);
|
|
141
|
+
}
|
|
136
142
|
loadChunk(x: number, z: number, options?: TaskOptions): Promise<boolean> {
|
|
137
143
|
return post<boolean>('world.loadChunk', { world: this.name, x, z }, options);
|
|
138
144
|
}
|