@occultus/toolkit 0.22.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/LICENSE +9 -0
- package/README.md +31 -0
- package/package.json +38 -0
- package/src/entity/EntitiesUtils.ts +108 -0
- package/src/entity/entityUtils.ts +277 -0
- package/src/index.ts +7 -0
- package/src/item/container.ts +95 -0
- package/src/item/item.ts +94 -0
- package/tsconfig.json +21 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright © 2025 CTN Studios
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Star Tenon Toolkit
|
|
2
|
+
|
|
3
|
+
一个轻量的 API 工具包,包括一些常用的工具函数,可用于实体以及 ItemStack。
|
|
4
|
+
|
|
5
|
+
## 支持版本
|
|
6
|
+
|
|
7
|
+
本 API 支持任意可以运行 Script API v2.0.0+ 的游戏版本,包括:
|
|
8
|
+
|
|
9
|
+
- 1.21.90;
|
|
10
|
+
- 1.21.100;
|
|
11
|
+
- 1.21.110;
|
|
12
|
+
- 以及更多……
|
|
13
|
+
|
|
14
|
+
注意:本包理论上可以在部分更旧的版本上运作,但未经过严格的测试。
|
|
15
|
+
|
|
16
|
+
## 协议
|
|
17
|
+
|
|
18
|
+
本项目使用 MIT License 授权:
|
|
19
|
+
|
|
20
|
+
```text
|
|
21
|
+
The MIT License (MIT)
|
|
22
|
+
|
|
23
|
+
Copyright © 2025 CTN Studios
|
|
24
|
+
|
|
25
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
26
|
+
|
|
27
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
28
|
+
|
|
29
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
30
|
+
```
|
|
31
|
+
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@occultus/toolkit",
|
|
3
|
+
"version": "0.22.0",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://codeberg.org/TeamOccultus/StarTenonAPI"
|
|
7
|
+
},
|
|
8
|
+
"homepage": "https://codeberg.org/TeamOccultus/StarTenonAPI",
|
|
9
|
+
"bugs": {
|
|
10
|
+
"url": "https://codeberg.org/TeamOccultus/StarTenonAPI/issues",
|
|
11
|
+
"email": "FangLiulii@outlook.com"
|
|
12
|
+
},
|
|
13
|
+
"description": "Star Tenon api toolkit",
|
|
14
|
+
"main": "src/index.ts",
|
|
15
|
+
"keywords": [
|
|
16
|
+
"Minecraft",
|
|
17
|
+
"Occultus SDK",
|
|
18
|
+
"Script API"
|
|
19
|
+
],
|
|
20
|
+
"contributors": [
|
|
21
|
+
"FangLimao <FangLiulii@outlook.com>"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"author": "CTN Studios",
|
|
25
|
+
"dependencies": {},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@minecraft/server": ">=2.0.0",
|
|
28
|
+
"@minecraft/server-ui": ">=2.0.0",
|
|
29
|
+
"@occultus/core": ">=0.18.4 || <0.19.0",
|
|
30
|
+
"@occultus/common": "0.20.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"typedoc": "^0.28.9"
|
|
34
|
+
},
|
|
35
|
+
"scripts": {
|
|
36
|
+
"test": "tsc"
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Dimension,
|
|
3
|
+
EntityQueryOptions,
|
|
4
|
+
Entity,
|
|
5
|
+
EntityApplyDamageByProjectileOptions,
|
|
6
|
+
EntityApplyDamageOptions,
|
|
7
|
+
EffectType,
|
|
8
|
+
EntityEffectOptions,
|
|
9
|
+
ItemStack,
|
|
10
|
+
} from "@minecraft/server";
|
|
11
|
+
import { EffectGroups, EffectData } from "@occultus/common";
|
|
12
|
+
import { addEffect, applyEffectData, clearSlot, giveItem } from "./entityUtils";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* 适用于批量实体的相关工具
|
|
16
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
17
|
+
* @example
|
|
18
|
+
* new EntitiesUtils(world.getDimension("overworld"), {
|
|
19
|
+
* type: "minecraft:player",
|
|
20
|
+
* }).damage(10);
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
export class EntitiesUtils {
|
|
24
|
+
/**
|
|
25
|
+
* @param dimension 实体所在的维度
|
|
26
|
+
* @param queryOption 查询实体的选项
|
|
27
|
+
*/
|
|
28
|
+
constructor(
|
|
29
|
+
public dimension: Dimension,
|
|
30
|
+
public queryOption: EntityQueryOptions
|
|
31
|
+
) {}
|
|
32
|
+
/**
|
|
33
|
+
* 查询给定条件下的实体
|
|
34
|
+
* @returns
|
|
35
|
+
*/
|
|
36
|
+
query(): Entity[] {
|
|
37
|
+
return this.dimension.getEntities(this.queryOption);
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* 尝试对实体进行操作
|
|
41
|
+
* @param operate 操作函数,接受一个实体作为参数
|
|
42
|
+
*/
|
|
43
|
+
tryOperateEntity(operate: (entity: Entity) => void) {
|
|
44
|
+
this.query().forEach((entity) => {
|
|
45
|
+
if (entity.isValid) {
|
|
46
|
+
operate(entity);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* 对批量实体进行伤害
|
|
52
|
+
* @param amount 施加的伤害量
|
|
53
|
+
* @param options 关于伤害来源的额外选项,可能会增加额外的效果或造成受伤实体的额外行为
|
|
54
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
55
|
+
*/
|
|
56
|
+
applyDamage(
|
|
57
|
+
amount: number,
|
|
58
|
+
options?: EntityApplyDamageByProjectileOptions | EntityApplyDamageOptions
|
|
59
|
+
) {
|
|
60
|
+
this.query().forEach((entity) => entity.applyDamage(amount, options));
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* 为批量实体添加效果
|
|
64
|
+
*
|
|
65
|
+
* @param effectType 效果的类型
|
|
66
|
+
* @param duration
|
|
67
|
+
* 效果持续时间,以刻为单位 *(20刻=1秒)*
|
|
68
|
+
*
|
|
69
|
+
* 其值必须在范围`[0, 20000000]`内
|
|
70
|
+
* @param effectOption 可选参数,状态效果的具体配置选项
|
|
71
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
72
|
+
*/
|
|
73
|
+
addEffect(
|
|
74
|
+
effectType: EffectType | EffectType[] | string | string[] | EffectGroups,
|
|
75
|
+
duration: number,
|
|
76
|
+
effectOption?: EntityEffectOptions
|
|
77
|
+
) {
|
|
78
|
+
this.query().forEach((entity) =>
|
|
79
|
+
addEffect(entity, effectType, duration, effectOption)
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* 批量给予实体物品
|
|
84
|
+
* @param entity 要给予物品的实体
|
|
85
|
+
* @param item 要给予的物品
|
|
86
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
87
|
+
*/
|
|
88
|
+
giveItem(item: ItemStack) {
|
|
89
|
+
this.query().forEach((entity) => giveItem(entity, item));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* 批量清空实体的容器
|
|
93
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
94
|
+
*/
|
|
95
|
+
clearSlot(): void {
|
|
96
|
+
this.query().forEach((entity) => clearSlot(entity));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* 批量为实体应用 {@link EffectData }
|
|
100
|
+
* @param data 要应用的 {@link EffectData }
|
|
101
|
+
* @returns
|
|
102
|
+
*/
|
|
103
|
+
applyEffectData(data: EffectData | EffectData[]): void {
|
|
104
|
+
return this.query().forEach((entity) =>
|
|
105
|
+
applyEffectData(entity, data)
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Container,
|
|
3
|
+
Effect,
|
|
4
|
+
EffectType,
|
|
5
|
+
Entity,
|
|
6
|
+
EntityEffectOptions,
|
|
7
|
+
EntityEquippableComponent,
|
|
8
|
+
EquipmentSlot,
|
|
9
|
+
ItemStack,
|
|
10
|
+
Player,
|
|
11
|
+
} from "@minecraft/server";
|
|
12
|
+
import { EffectData, effectGroupMap, EffectGroups } from "@occultus/common";
|
|
13
|
+
import { OccultusSDKError } from "@occultus/core";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* 尝试对实体进行操作
|
|
17
|
+
*
|
|
18
|
+
* @param entity 要操作的实体
|
|
19
|
+
* @param operate 操作函数,接受一个实体作为参数
|
|
20
|
+
* @returns 操作是否成功
|
|
21
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
22
|
+
*/
|
|
23
|
+
export function tryOperateEntity(
|
|
24
|
+
entity: Entity,
|
|
25
|
+
operate: (entity: Entity) => void
|
|
26
|
+
): boolean {
|
|
27
|
+
if (entity.isValid) {
|
|
28
|
+
operate(entity);
|
|
29
|
+
return true;
|
|
30
|
+
}
|
|
31
|
+
return false;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 获取给定实体的指定槽位物品
|
|
36
|
+
*
|
|
37
|
+
* **IMPORTANT: 受原版接口限制, 当前只能获取玩家的装备**
|
|
38
|
+
* @param entity 要获取槽位的实体
|
|
39
|
+
* @param slot 要获取的槽位,默认为 {@link EquipmentSlot.Mainhand}
|
|
40
|
+
* @return 槽位中的物品
|
|
41
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
42
|
+
*/
|
|
43
|
+
export function getEquipmentItem(
|
|
44
|
+
entity: Entity,
|
|
45
|
+
slot = EquipmentSlot.Mainhand
|
|
46
|
+
): ItemStack | undefined {
|
|
47
|
+
const equipment = entity?.getComponent(
|
|
48
|
+
"minecraft:equippable"
|
|
49
|
+
) as EntityEquippableComponent;
|
|
50
|
+
return equipment?.getEquipment(slot);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* 设置给定实体的指定槽位物品
|
|
55
|
+
*
|
|
56
|
+
* **IMPORTANT: 受原版接口限制, 当前只能获取玩家的装备**
|
|
57
|
+
* @param entity 要设置槽位的实体
|
|
58
|
+
* @param item 要设置的物品,如果为undefined则清空该槽位
|
|
59
|
+
* @param slot 要设置的槽位,默认为 {@link EquipmentSlot.Mainhand}
|
|
60
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
61
|
+
*/
|
|
62
|
+
export function setEquipmentItem(
|
|
63
|
+
entity: Entity,
|
|
64
|
+
item?: ItemStack,
|
|
65
|
+
slot: EquipmentSlot = EquipmentSlot.Mainhand
|
|
66
|
+
): boolean {
|
|
67
|
+
const equipment = entity?.getComponent(
|
|
68
|
+
"minecraft:equippable"
|
|
69
|
+
) as EntityEquippableComponent;
|
|
70
|
+
if (!equipment) return false;
|
|
71
|
+
return equipment?.setEquipment(slot, item);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 获取实体的容器
|
|
76
|
+
*
|
|
77
|
+
* @param entity 要获取容器的实体
|
|
78
|
+
* @return 实体的容器,如果没有则返回`undefined`
|
|
79
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
80
|
+
*/
|
|
81
|
+
export function getContainer(entity: Entity): Container | undefined {
|
|
82
|
+
return entity.getComponent("minecraft:inventory")?.container;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* 设置实体的槽位物品
|
|
87
|
+
* @param entity 要设置槽位物品的实体
|
|
88
|
+
* @param slot 槽位索引,从0开始依次递增
|
|
89
|
+
* @param item 要设置的物品
|
|
90
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
91
|
+
*/
|
|
92
|
+
export function setSlot(entity: Entity, slot: number, item?: ItemStack): void {
|
|
93
|
+
getContainer(entity)?.setItem(slot, item);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 给予实体物品
|
|
98
|
+
* @param entity 要给予物品的实体
|
|
99
|
+
* @param item 要给予的物品
|
|
100
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
101
|
+
*/
|
|
102
|
+
export function giveItem(entity: Entity, item: ItemStack | ItemStack[]): void {
|
|
103
|
+
const container = getContainer(entity);
|
|
104
|
+
if (Array.isArray(item)) {
|
|
105
|
+
for (const i of item) {
|
|
106
|
+
giveItem(entity, i);
|
|
107
|
+
}
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
if (container && container.emptySlotsCount > 0) {
|
|
111
|
+
container.addItem(item);
|
|
112
|
+
} else {
|
|
113
|
+
entity.dimension.spawnItem(item, entity.location);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* 清空实体的容器
|
|
119
|
+
* @param entity 要清空容器的实体
|
|
120
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
121
|
+
*/
|
|
122
|
+
export function clearSlot(entity: Entity): void {
|
|
123
|
+
getContainer(entity)?.clearAll();
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* 将 {@link EffectData} 应用到实体上
|
|
128
|
+
* @param entity 要应用 {@link EffectData} 的实体
|
|
129
|
+
* @param data 要应用的 {@link EffectData}
|
|
130
|
+
* @returns 应用后的状态效果
|
|
131
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
132
|
+
*/
|
|
133
|
+
export function applyEffectData(
|
|
134
|
+
entity: Entity,
|
|
135
|
+
data: EffectData | EffectData[]
|
|
136
|
+
): (Effect | undefined)[] {
|
|
137
|
+
if (!Array.isArray(data)) {
|
|
138
|
+
data = [data];
|
|
139
|
+
}
|
|
140
|
+
return data.flatMap((effectData) => {
|
|
141
|
+
return entity.addEffect(effectData.effectType, effectData.duration, {
|
|
142
|
+
amplifier: effectData.amplifier,
|
|
143
|
+
showParticles: effectData.showParticles,
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* 向实体移除状态效果
|
|
150
|
+
* @param entity 要清除效果的实体.
|
|
151
|
+
* @param effectType 状态效果类型,可以是单个效果类型、效果类型数组、字符串、字符串数组或{@link EffectGroups}枚举值
|
|
152
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
153
|
+
*/
|
|
154
|
+
export function clearEffect(
|
|
155
|
+
entity: Entity,
|
|
156
|
+
effectType: EffectType | EffectType[] | string | string[] | EffectGroups
|
|
157
|
+
): void {
|
|
158
|
+
const effects =
|
|
159
|
+
effectGroupMap[effectType as EffectGroups] ||
|
|
160
|
+
(Array.isArray(effectType) ? effectType : [effectType]);
|
|
161
|
+
for (const effect of effects) {
|
|
162
|
+
entity.removeEffect(effect);
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* 向实体添加状态效果
|
|
168
|
+
* @param entity 要添加状态效果实体对象
|
|
169
|
+
* @param effectType 状态效果类型,可以是单个效果类型、效果类型数组、字符串、字符串数组或{@link EffectGroups}枚举值
|
|
170
|
+
* @param duration
|
|
171
|
+
* 状态效果持续时间,以刻为单位 *(20刻 = 1秒)*
|
|
172
|
+
*
|
|
173
|
+
* 其值必须在范围`[0, 20000000]`内
|
|
174
|
+
* @param options 状态效果选项
|
|
175
|
+
* @since Starock 0.6.0 (0.1.0)
|
|
176
|
+
*/
|
|
177
|
+
export function addEffect(
|
|
178
|
+
entity: Entity,
|
|
179
|
+
effectType: EffectType | EffectType[] | string | string[] | EffectGroups,
|
|
180
|
+
duration: number,
|
|
181
|
+
options?: EntityEffectOptions
|
|
182
|
+
): void {
|
|
183
|
+
const effects =
|
|
184
|
+
effectGroupMap[effectType as EffectGroups] ||
|
|
185
|
+
(Array.isArray(effectType) ? effectType : [effectType]);
|
|
186
|
+
for (const effect of effects) {
|
|
187
|
+
entity.addEffect(effect, duration, options);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 获取实体所有的族
|
|
193
|
+
* @param entity 要获取族的实体
|
|
194
|
+
* @return 实体的族数组,如果没有则返回`undefined`
|
|
195
|
+
* @see https://zh.minecraft.wiki/w/族
|
|
196
|
+
* @see https://minecraft.wiki/w/Family
|
|
197
|
+
*/
|
|
198
|
+
export function getFamilies(entity: Entity): string[] | undefined {
|
|
199
|
+
return entity.getComponent("minecraft:type_family")?.getTypeFamilies();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 返回实体是否含有指定族
|
|
204
|
+
* @param entity 要检查族的实体
|
|
205
|
+
* @return 实体是否含有指定族
|
|
206
|
+
* @see https://zh.minecraft.wiki/w/族
|
|
207
|
+
* @see https://minecraft.wiki/w/Family
|
|
208
|
+
*/
|
|
209
|
+
export function hasFamily(entity: Entity, family: string): boolean {
|
|
210
|
+
return (
|
|
211
|
+
entity.getComponent("minecraft:type_family")?.hasTypeFamily(family) ?? false
|
|
212
|
+
);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* 根据玩家等级计算经验消耗
|
|
217
|
+
* @param level 玩家等级
|
|
218
|
+
*/
|
|
219
|
+
export function getExpCost(level: number): number {
|
|
220
|
+
if (level >= 30) {
|
|
221
|
+
return 62 + (level - 30) * 7;
|
|
222
|
+
}
|
|
223
|
+
if (level >= 15) {
|
|
224
|
+
return 17 + (level - 15) * 3;
|
|
225
|
+
}
|
|
226
|
+
return 17;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* 获取玩家得到的所有经验值
|
|
231
|
+
* @param player
|
|
232
|
+
*/
|
|
233
|
+
export function getAllExp(player: Player): number {
|
|
234
|
+
const level: number = player.level;
|
|
235
|
+
let exp = 0;
|
|
236
|
+
for (let i = 1; i <= level; i++) {
|
|
237
|
+
exp += getExpCost(i);
|
|
238
|
+
}
|
|
239
|
+
return exp + player.xpEarnedAtCurrentLevel;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
function consumeAmount(item: ItemStack, value: number): ItemStack | undefined {
|
|
243
|
+
const amount: number = item.amount;
|
|
244
|
+
if (amount === value) {
|
|
245
|
+
return undefined;
|
|
246
|
+
}
|
|
247
|
+
if (amount - value < 0) {
|
|
248
|
+
throw new OccultusSDKError(
|
|
249
|
+
`The number of items is insufficient! Actual amount: ${amount} Consume amount: ${value}`,
|
|
250
|
+
`${item.typeId}`
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
if (amount - value > item.maxAmount) {
|
|
254
|
+
throw new OccultusSDKError(
|
|
255
|
+
`The max stack of items is insufficient!`,
|
|
256
|
+
`${item.typeId}`
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
const newItem: ItemStack = item.clone();
|
|
260
|
+
newItem.amount = amount - value;
|
|
261
|
+
return newItem;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* 消耗玩家装备物品的数量
|
|
266
|
+
* @param player 要消耗物品的玩家
|
|
267
|
+
* @param amount 消耗的数量
|
|
268
|
+
* @returns 是否消耗成功
|
|
269
|
+
*/
|
|
270
|
+
export function consumeEquipmentAmount(
|
|
271
|
+
player: Player,
|
|
272
|
+
amount: number = 1
|
|
273
|
+
): boolean {
|
|
274
|
+
const item = getEquipmentItem(player);
|
|
275
|
+
if (!item) return false;
|
|
276
|
+
return setEquipmentItem(player, consumeAmount(item, amount));
|
|
277
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { Container, ItemStack } from "@minecraft/server";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 获取容器中指定物品的数量
|
|
5
|
+
* @param container 容器对象
|
|
6
|
+
* @param typeId 要获取的物品 ID
|
|
7
|
+
* @returns 容器中指定物品的数量
|
|
8
|
+
* @author RawDiamondMC
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
export function getItemAmountInContainer(
|
|
12
|
+
container: Container,
|
|
13
|
+
typeId: string
|
|
14
|
+
): number {
|
|
15
|
+
let amount = 0;
|
|
16
|
+
for (let slot = 0; slot < container.size; slot++) {
|
|
17
|
+
const itemStack: undefined | ItemStack = container.getItem(slot);
|
|
18
|
+
if (itemStack?.typeId === typeId) {
|
|
19
|
+
amount += itemStack.amount;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return amount;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 从容器中移除指定数量的物品
|
|
27
|
+
* @param container 容器对象
|
|
28
|
+
* @param typeId 物品 ID
|
|
29
|
+
* @param amount 要移除物品的数量
|
|
30
|
+
* @author RawDiamondMC
|
|
31
|
+
*/
|
|
32
|
+
export function removeItemInContainer(
|
|
33
|
+
container: Container,
|
|
34
|
+
typeId: string,
|
|
35
|
+
amount: number
|
|
36
|
+
): void {
|
|
37
|
+
for (let slot = 0; slot < container.size; slot++) {
|
|
38
|
+
const itemStack: undefined | ItemStack = container.getItem(slot);
|
|
39
|
+
if (itemStack?.typeId === typeId) {
|
|
40
|
+
if (itemStack.amount > amount) {
|
|
41
|
+
itemStack.amount -= amount;
|
|
42
|
+
container.setItem(slot, itemStack);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
container.setItem(slot);
|
|
46
|
+
amount -= itemStack.amount;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* 在容器中查找替换物品
|
|
53
|
+
* @param item 要替换的物品,如果为`undefined`,则替换所有空槽
|
|
54
|
+
* @param newItem 替换后的物品,如果为`undefined`,则清空所有物品
|
|
55
|
+
* @param container 要搜索的容器
|
|
56
|
+
* @author RawDiamondMC
|
|
57
|
+
*/
|
|
58
|
+
export function replaceItemStack(
|
|
59
|
+
item: ItemStack | undefined,
|
|
60
|
+
newItem: ItemStack | undefined,
|
|
61
|
+
container: Container
|
|
62
|
+
): number {
|
|
63
|
+
let amount = 0;
|
|
64
|
+
for (let slot = 0; slot < container.size; slot++) {
|
|
65
|
+
const itemStack: undefined | ItemStack = container.getItem(slot);
|
|
66
|
+
if (itemStack?.typeId === item?.typeId) {
|
|
67
|
+
container.setItem(slot, newItem);
|
|
68
|
+
amount++;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
return amount;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* 在容器中根据标签查找替换物品
|
|
76
|
+
* @param itemTag 要替换的物品标签
|
|
77
|
+
* @param newItem 替换后的物品,如果为`undefined`,则清空所有物品
|
|
78
|
+
* @param container 要搜索的容器
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
export function replaceItemByTag(
|
|
82
|
+
itemTag: string,
|
|
83
|
+
newItem: ItemStack | undefined,
|
|
84
|
+
container: Container
|
|
85
|
+
): number {
|
|
86
|
+
let amount = 0;
|
|
87
|
+
for (let slot = 0; slot < container.size; slot++) {
|
|
88
|
+
const itemStack: undefined | ItemStack = container.getItem(slot);
|
|
89
|
+
if (itemStack?.hasTag(itemTag)) {
|
|
90
|
+
container.setItem(slot, newItem);
|
|
91
|
+
amount++;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return amount;
|
|
95
|
+
}
|
package/src/item/item.ts
ADDED
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ItemStack,
|
|
3
|
+
Entity,
|
|
4
|
+
ItemComponent,
|
|
5
|
+
ItemComponentTypes,
|
|
6
|
+
ItemDurabilityComponent,
|
|
7
|
+
Player,
|
|
8
|
+
GameMode,
|
|
9
|
+
} from "@minecraft/server";
|
|
10
|
+
import { OccultusSDKError } from "@occultus/core";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* 添加物品的损坏值,即消耗其耐久。当`entity`是创造模式或是`undefined`,会直接返回`item`
|
|
14
|
+
* @param item 要添加损坏值的物品
|
|
15
|
+
* @param value 要添加的损坏值
|
|
16
|
+
* @param entity 当物品损坏时,向手持物品的实体播放声音
|
|
17
|
+
* @returns 添加损坏值的 {@link ItemStack}
|
|
18
|
+
* @author RawDiamondMC, FangLimao
|
|
19
|
+
*/
|
|
20
|
+
export function consumeDurability(
|
|
21
|
+
item: ItemStack,
|
|
22
|
+
value: number,
|
|
23
|
+
entity?: Entity
|
|
24
|
+
): ItemStack | undefined {
|
|
25
|
+
const isPlayer = entity instanceof Player;
|
|
26
|
+
if (isPlayer && entity.getGameMode() === GameMode.Creative) {
|
|
27
|
+
// 创造模式下不消耗物品耐久
|
|
28
|
+
return item;
|
|
29
|
+
}
|
|
30
|
+
const durability: undefined | ItemComponent = item.getComponent(
|
|
31
|
+
ItemComponentTypes.Durability
|
|
32
|
+
);
|
|
33
|
+
if (
|
|
34
|
+
durability === undefined ||
|
|
35
|
+
!(durability instanceof ItemDurabilityComponent)
|
|
36
|
+
) {
|
|
37
|
+
return item;
|
|
38
|
+
}
|
|
39
|
+
if (durability.damage + value >= durability.maxDurability) {
|
|
40
|
+
if (isPlayer) {
|
|
41
|
+
entity.playSound("random.break");
|
|
42
|
+
}
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
45
|
+
durability.damage += value;
|
|
46
|
+
return item;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* 消耗物品的数量
|
|
51
|
+
* @param item 要消耗物品的数量
|
|
52
|
+
* @param value 要消耗的数量
|
|
53
|
+
* @returns 消耗后的物品堆
|
|
54
|
+
* @throws 如果物品数量不足,则抛出错误
|
|
55
|
+
* @author RawDiamondMC
|
|
56
|
+
*/
|
|
57
|
+
export function consumeAmount(
|
|
58
|
+
item: ItemStack,
|
|
59
|
+
value: number
|
|
60
|
+
): ItemStack | undefined {
|
|
61
|
+
const amount: number = item.amount;
|
|
62
|
+
if (amount === value) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
if (amount - value < 0) {
|
|
66
|
+
throw new OccultusSDKError(
|
|
67
|
+
`The number of items is insufficient! Actual amount: ${amount} Consume amount: ${value}`,
|
|
68
|
+
`${item.typeId}`
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
if (amount - value > item.maxAmount) {
|
|
72
|
+
throw new OccultusSDKError(
|
|
73
|
+
`The max stack of items is insufficient!`,
|
|
74
|
+
`${item.typeId}`
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
const newItem: ItemStack = item.clone();
|
|
78
|
+
newItem.amount = amount - value;
|
|
79
|
+
return newItem;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* 向物品添加新的 Lore
|
|
84
|
+
* @param loreText 要添加的 Lore文本
|
|
85
|
+
* @param item 要添加 Lore 文本的物品
|
|
86
|
+
* @returns 更新 Lore 后的物品
|
|
87
|
+
* @author FangLimao
|
|
88
|
+
*/
|
|
89
|
+
export function pushLore(loreText: string, item: ItemStack): ItemStack {
|
|
90
|
+
const lore = item.getLore();
|
|
91
|
+
lore.push(loreText);
|
|
92
|
+
item.setLore(lore);
|
|
93
|
+
return item;
|
|
94
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": ["src/**/*"],
|
|
3
|
+
"exclude": ["./out"],
|
|
4
|
+
"Modules": {
|
|
5
|
+
"resolvePackageJsonExports": true
|
|
6
|
+
},
|
|
7
|
+
"compilerOptions": {
|
|
8
|
+
"noEmit": true,
|
|
9
|
+
"noEmitOnError": true,
|
|
10
|
+
"target": "es2022",
|
|
11
|
+
"lib": ["es2020", "dom"],
|
|
12
|
+
"strict": true,
|
|
13
|
+
"moduleResolution": "bundler",
|
|
14
|
+
"esModuleInterop": true,
|
|
15
|
+
"module": "es2022",
|
|
16
|
+
"outDir": ".",
|
|
17
|
+
"removeComments": true,
|
|
18
|
+
"newLine": "lf",
|
|
19
|
+
"resolveJsonModule": true
|
|
20
|
+
}
|
|
21
|
+
}
|