// ==UserScript==
const gameConfig = {
type: "BehaviorLib",
title: "BehaviorLib",
doc: `EasyBox3Lib的附属库,用于控制对象行为,需要安装EasyBox3Lib。EasyBox3Lib的安装见帮助链接`,
help: "https://qndm.github.io/EasyBox3Lib",
file: true,
isClient: false
}
// ==UserScript==
/**
* BehaviorLib 库
* 用于控制实体/非实体行为的库
* 依赖EasyBox3Lib 0.1.6
* @author qndm
* @module BehaviorLib
* @version 0.0.6
* @license MIT
*/
/**
* 调用其他行为的函数
* @async
* @callback CallBehaviorCallback
* @param {string} behaviorId 要调用的行为id
* @param {any} data 传入行动的数据
* @returns {any} 行为返回结果
*/
/**
* 行为函数
* @async
* @callback BehaviorInitCallback
* @param {object} self 行为自身
* @param {any} data 行为数据。若不是`CallBehaviorCallback`中则为`null`
* @param {CallBehaviorCallback} callBehavior 调用其他行为
* @returns {any} 行为返回结果
*/
/**
* 行为组数据
* @typedef BehaviorGroupData
* @property {string} behavior 行为id
* @property {any} data id为`id`的行为的数据
*/
/**
* 行为目标对象行为
* @typedef BehaviorTargetBehavior
* @property {string} id 行为/行为组id
* @property {number} priority 行为优先级
* @property {boolean} disabled 是否禁用行为
*/
/**
* EasyBox3Lib
*/
const EBL = global.EasyBox3Lib,
/**
* 配置文件
*/
CONFIG = require('./EasyBox3Lib.config.js'),
/**
* 建议EasyBox3Lib版本
* @type {number[]}
*/
EBL_VERSION = [0, 1, 6],
/**
* 当前版本
* @type {number[]}
*/
VERSION = [0, 0, 6];
/**
* @type {Map<string, Behavior>}
*/
var behaviorRegistry = new Map();
if (EBL === undefined)
throw "EasyBox3Lib 未安装";
if (global.BehaviorLib)
throw "请勿重复加载 BehaviorLib"
if (EBL.version.toString() !== EBL_VERSION.toString())
EBL.output("warn", 'EasyBox3Lib 版本', EBL.version.join('.'), '建议', EBL_VERSION.join('.'));
/**
* 空值合并
* @param {*} a
* @param {*} b
* @returns {*}
*/
function nullc(a, b) {
if (a === null || a === undefined)
return b;
else return a;
}
// ----- BehaviorLib Start -----
/**
* 定义一种行为
* @param {string} 该行为的id,不可重复
* @param {BehaviorInitCallback} init 行为主函数
* @param {number} defaultPriority 行为默认优先级,越高越先执行
*/
function Behavior(id, init, defaultPriority = 1) {
/**
* 该行为的id,不可重复
* @type {string}
*/
this.id = id;
/**
* 行为主函数
* @type {BehaviorInitCallback}
*/
this.init = init;
/**
* 行为默认优先级,越高越先执行
* @type {number}
*/
this.defaultPriority = defaultPriority;
}
/**
* 行为目标对象
*/
class BehaviorTarget {
/**
* 行为目标自身
* @type {any}
*/
self = undefined;
/**
* 行为目标所具有的行为
* @type {BehaviorTargetBehavior[]}
*/
behaviors = [];
/**
* @type {EasyBox3Lib.onTickEventToken | undefined}
*/
onTickEvent = undefined;
/**
* 行为对象数据
*/
data = {};
constructor(self) {
this.self = self;
this.behaviors = [];
this.onTickEvent = undefined;
this.data = {};
}
async _runBehaviorTick() {
for (const behavior of this.behaviors) {
if (behavior.disabled)
continue;
await behaviorRegistry.get(behavior.id).init(this.self, null, this.callBehavior);
}
}
/**
* 查找行为在行为列表里的位置
* 如果不存在,返回`-1`
* @param {string} behavior 行为id
* @private
* @returns {number} 行为在行为列表里的位置
*/
_getBehaviorIndex(behavior) {
for (const i in this.behaviors) {
if (this.behaviors[i].id === behavior)
return i;
}
return -1;
}
/**
* 添加行为
* @param {string} behavior 行为id
* @param {number} priority 行为优先级
*/
addBehavior(behavior, priority = behavior.priority) {
if (this.hasBehavior(behavior))
EBL.thr("[BEHAVIOR_TARGET] 添加行为失败:行为已存在");
this.behaviors.push({ id: behavior, priority, disabled: false });
this.behaviors.sort(a, b => b.priority - a.priority);
}
/**
* 移除行为
* @param {string} behavior 行为id
*/
removeBehavior(behavior) {
if (!this.hasBehavior(behavior))
EBL.thr('[BEHAVIOR]', behavior, '行为不存在');
this.behaviors.splice(this._getBehaviorIndex(behavior), 1);
}
/**
* 对该对象启用行为
* @param {string} behavior 行为id
*/
enableBehavior(behavior) {
if (!this.hasBehavior(behavior))
EBL.thr('[BEHAVIOR]', behavior, '行为不存在');
this.behaviors[this._getBehaviorIndex(behavior)].disabled = false;
}
/**
* 对该对象禁用行为
* 禁用后,该对象将不会执行该行为
* @param {string} behavior 行为id
*/
disabledBehavior(behavior) {
if (!this.hasBehavior(behavior))
EBL.thr('[BEHAVIOR]', behavior, '行为不存在');
this.behaviors[this._getBehaviorIndex(behavior)].disabled = true;
}
/**
* 检查是否有某种行为
* @param {string} id 行为id
* @returns {boolean} 是否有行为
*/
hasBehavior(id) {
return this.behaviors.some(behavior => behavior.id == id);
}
/**
* 调用其他行为的函数
* @async
* @param {string} behaviorId 要调用的行为id
* @param {any} data 传入行为的数据
* @returns {any} 行为返回结果
*/
async callBehavior(behaviorId, data) {
await behaviorRegistry.get(behaviorId).init(this.self, data, this.callBehavior);
}
/**
* 为该对象的行为创建onTick
* @param {number} tpc 每循环执行次数
* @param {number} performanceImpact 性能影响程度
* @returns {EasyBox3Lib.onTickEventToken} 事件令牌
*/
createOnTickEvent(tpc = nullc(CONFIG.BehaviorLib.defaultTpc, 2), performanceImpact = nullc(CONFIG.BehaviorLib.defaultPerformanceImpact, 1)) {
this.onTickEvent = EBL.ot(async () => {
await this._runBehaviorTick();
}, tpc, performanceImpact);
return this.onTickEvent;
}
}
/**
* 注册一种行为
* @param {Behavior} behavior 要注册的行为
*/
function registerBehavior(behavior) {
if (!(behavior instanceof Behavior)) {
EBL.thr("[BEHAVIOR] 注册失败:未知行为类型");
}
if (behaviorRegistry.has(behavior.id)) {
EBL.thr("[BEHAVIOR] 注册失败:行为 " + behavior.id + " 已注册类型");
}
behaviorRegistry.set(behavior.id, behavior);
}
// ----- BehaviorLib End -----
EBL.regIndex(Behavior, registerBehavior)
const BehaviorLib = {
Behavior,
B: Behavior,
BehaviorTarget,
BT: BehaviorTarget,
registerBehavior,
regB: registerBehavior,
version: VERSION
};
/**
* BehaviorLib的全局对象
* @global
*/
global.BehaviorLib = BehaviorLib;
console.log("BehaviorLib", VERSION.join('.'));
module.exports = BehaviorLib;