UNPKG

@occultus/entity-api

Version:

Star Tenon entity api and utils

269 lines (252 loc) 7.77 kB
import { Container, Effect, EffectType, Entity, EntityEffectOptions, EntityEquippableComponent, EquipmentSlot, ItemStack, Player, } from "@minecraft/server"; import { EffectData, effectGroupMap, EffectGroups } from "@occultus/common"; import { OccultusSDKError } from "@occultus/core"; /** * 尝试对实体进行操作 * * @param entity 要操作的实体 * @param operate 操作函数,接受一个实体作为参数 * @returns 操作是否成功 * @since Starock 0.6.0 (0.1.0) */ export function tryOperateEntity( entity: Entity, operate: (entity: Entity) => void ): boolean { if (entity.isValid) { operate(entity); return true; } return false; } /** * 获取给定实体的指定槽位物品 * * **IMPORTANT: 受原版接口限制, 当前只能获取玩家的装备** * @param entity 要获取槽位的实体 * @param slot 要获取的槽位,默认为 {@link EquipmentSlot.Mainhand} * @return 槽位中的物品 * @since Starock 0.6.0 (0.1.0) */ export function getEquipmentItem( entity: Entity, slot = EquipmentSlot.Mainhand ): ItemStack | undefined { const equipment = entity?.getComponent( "minecraft:equippable" ) as EntityEquippableComponent; return equipment?.getEquipment(slot); } /** * 设置给定实体的指定槽位物品 * * **IMPORTANT: 受原版接口限制, 当前只能获取玩家的装备** * @param entity 要设置槽位的实体 * @param item 要设置的物品,如果为undefined则清空该槽位 * @param slot 要设置的槽位,默认为 {@link EquipmentSlot.Mainhand} * @since Starock 0.6.0 (0.1.0) */ export function setEquipmentItem( entity: Entity, item?: ItemStack, slot: EquipmentSlot = EquipmentSlot.Mainhand ): boolean { const equipment = entity?.getComponent( "minecraft:equippable" ) as EntityEquippableComponent; if(!equipment) return false; return equipment?.setEquipment(slot, item); } /** * 获取实体的容器 * * @param entity 要获取容器的实体 * @return 实体的容器,如果没有则返回`undefined` * @since Starock 0.6.0 (0.1.0) */ export function getContainer(entity: Entity): Container | undefined { return entity.getComponent("minecraft:inventory")?.container; } /** * 设置实体的槽位物品 * @param entity 要设置槽位物品的实体 * @param slot 槽位索引,从0开始依次递增 * @param item 要设置的物品 * @since Starock 0.6.0 (0.1.0) */ export function setSlot(entity: Entity, slot: number, item?: ItemStack): void { getContainer(entity)?.setItem(slot, item); } /** * 给予实体物品 * @param entity 要给予物品的实体 * @param item 要给予的物品 * @since Starock 0.6.0 (0.1.0) */ export function giveItem(entity: Entity, item: ItemStack): void { const container = getContainer(entity); if (container && container.emptySlotsCount > 0) { container.addItem(item); } else { entity.dimension.spawnItem(item, entity.location); } } /** * 清空实体的容器 * @param entity 要清空容器的实体 * @since Starock 0.6.0 (0.1.0) */ export function clearSlot(entity: Entity): void { getContainer(entity)?.clearAll(); } /** * 将 {@link EffectData} 应用到实体上 * @param entity 要应用 {@link EffectData} 的实体 * @param data 要应用的 {@link EffectData} * @returns 应用后的状态效果 * @since Starock 0.6.0 (0.1.0) */ export function applyEffectData( entity: Entity, data: EffectData | EffectData[] ): (Effect | undefined)[] { if (!Array.isArray(data)) { data = [data]; } return data.flatMap((effectData) => { return entity.addEffect(effectData.effectType, effectData.duration, { amplifier: effectData.amplifier, showParticles: effectData.showParticles, }); }); } /** * 向实体移除状态效果 * @param entity 要清除效果的实体. * @param effectType 状态效果类型,可以是单个效果类型、效果类型数组、字符串、字符串数组或{@link EffectGroups}枚举值 * @since Starock 0.6.0 (0.1.0) */ export function clearEffect( entity: Entity, effectType: EffectType | EffectType[] | string | string[] | EffectGroups ): void { const effects = effectGroupMap[effectType as EffectGroups] || (Array.isArray(effectType) ? effectType : [effectType]); for (const effect of effects) { entity.removeEffect(effect); } } /** * 向实体添加状态效果 * @param entity 要添加状态效果实体对象 * @param effectType 状态效果类型,可以是单个效果类型、效果类型数组、字符串、字符串数组或{@link EffectGroups}枚举值 * @param duration * 状态效果持续时间,以刻为单位 *(20刻 = 1秒)* * * 其值必须在范围`[0, 20000000]`内 * @param options 状态效果选项 * @since Starock 0.6.0 (0.1.0) */ export function addEffect( entity: Entity, effectType: EffectType | EffectType[] | string | string[] | EffectGroups, duration: number, options?: EntityEffectOptions ): void { const effects = effectGroupMap[effectType as EffectGroups] || (Array.isArray(effectType) ? effectType : [effectType]); for (const effect of effects) { entity.addEffect(effect, duration, options); } } /** * 获取实体所有的族 * @param entity 要获取族的实体 * @return 实体的族数组,如果没有则返回`undefined` * @see https://zh.minecraft.wiki/w/族 * @see https://minecraft.wiki/w/Family */ export function getFamilies(entity: Entity): string[] | undefined { return entity.getComponent("minecraft:type_family")?.getTypeFamilies(); } /** * 返回实体是否含有指定族 * @param entity 要检查族的实体 * @return 实体是否含有指定族 * @see https://zh.minecraft.wiki/w/族 * @see https://minecraft.wiki/w/Family */ export function hasFamily(entity: Entity, family: string): boolean { return ( entity.getComponent("minecraft:type_family")?.hasTypeFamily(family) ?? false ); } /** * 根据玩家等级计算经验消耗 * @param level 玩家等级 */ export function getExpCost(level: number): number { if (level >= 30) { return 62 + (level - 30) * 7; } if (level >= 15) { return 17 + (level - 15) * 3; } return 17; } /** * 获取玩家得到的所有经验值 * @param player */ export function getAllExp(player: Player): number { const level: number = player.level; let exp = 0; for (let i = 1; i <= level; i++) { exp += getExpCost(i); } return exp + player.xpEarnedAtCurrentLevel; } function consumeAmount(item: ItemStack, value: number): ItemStack | undefined { const amount: number = item.amount; if (amount === value) { return undefined; } if (amount - value < 0) { throw new OccultusSDKError( `The number of items is insufficient! Actual amount: ${amount} Consume amount: ${value}`, `${item.typeId}` ); } if (amount - value > item.maxAmount) { throw new OccultusSDKError( `The max stack of items is insufficient!`, `${item.typeId}` ); } const newItem: ItemStack = item.clone(); newItem.amount = amount - value; return newItem; } /** * 消耗玩家装备物品的数量 * @param player 要消耗物品的玩家 * @param amount 消耗的数量 * @returns 是否消耗成功 */ export function consumeEquipmentAmount(player: Player, amount: number = 1): boolean { const item = getEquipmentItem(player); if (!item) return false; return setEquipmentItem(player, consumeAmount(item, amount)); }