This commit is contained in:
PC-20230316NUNE\Administrator
2023-10-23 18:56:01 +08:00
parent ac94959a45
commit 77d44ee300
328 changed files with 16429 additions and 2 deletions

View File

@@ -0,0 +1,20 @@
### 创建行为树
详细文档 https://www.exporter.top/behavior/#/zh-cn/?id=%e6%8f%92%e4%bb%b6%e5%85%a5%e5%8f%a3
行为树编辑器是由 `json` 数据驱动的,其入口已集成到 `BehaviorTree` 组件的`属性检查器`面板,可通过以下方式启动:
- 新建空节点,在节点上挂载 `BehaviorTree` 组件
- 新建内容为空`{}``json`资源,并关联到 `BehaviorTree``JsonAsset` 属性
- 点击 `Edit Behavior` 即可打开行为树编辑器
### 加载示例
在运行时目录`extensions\oreo-behavior-creator\runtime\examples\data` 中提供了一些简单示例。
### 示例项目地址
https://gitee.com/oreo-damowang/behavior-creator-examples
### 在线文档
https://www.exporter.top/behavior
### QQ交流群:
659064495

View File

@@ -0,0 +1,10 @@
"use strict";
module.exports = {
open_panel: "Default Panel",
send_to_panel: "Send message to Default Panel",
description: "Behavior Tree Editor",
close_other_panel: "Please close the Behavior Tree you are editing before opening other Behavior Tree.",
assign_json_asset: 'The "JsonAsset" property of the "BehaviorTree" component must be specified before editing the behavior tree.',
update_tree_panel: 'Update Tree Data',
tree_data_list: 'Data List'
};

View File

@@ -0,0 +1,10 @@
"use strict";
module.exports = {
open_panel: "新手指引",
send_to_panel: "发送消息给面板",
description: "行为树编辑器",
close_other_panel: "在打开其他行为树之前,请先关闭您正在编辑的行为树。",
assign_json_asset: '在编辑行为树之前必须先指定 "BehaviorTree" 组件中 "JsonAsset" 属性使用的资源。\n可以指定一个内容为空对象 {} 的json资源。',
update_tree_panel: '数据更新',
tree_data_list: '数据列表'
};

View File

@@ -0,0 +1,130 @@
{
"package_version": 2,
"version": "1.1.2",
"compatible_version": "1.0.2",
"name": "oreo-behavior-creator",
"description": "i18n:oreo-behavior-creator.description",
"author": "OreoWang",
"editor": ">=3.3.0",
"main": "./plugin/dist/main.js",
"panels": {
"default": {
"title": "oreo-behavior-creator -",
"type": "dockable",
"main": "./plugin/dist/panels/default/script",
"size": {
"min-width": 400,
"min-height": 300,
"width": 1024,
"height": 600
}
},
"usage": {
"title": "oreo-behavior-creator - usage",
"type": "dockable",
"main": "./plugin/dist/panels/usage/script",
"size": {
"min-width": 400,
"min-height": 300,
"width": 1024,
"height": 600
}
},
"update_tree": {
"title": "oreo-behavior-creator - update tree",
"type": "dockable",
"main": "./plugin/dist/panels/update_tree/script",
"size": {
"min-width": 400,
"min-height": 300,
"width": 1024,
"height": 600
}
}
},
"contributions": {
"asset-db": {
"mount": {
"path": "./runtime",
"readonly": true
}
},
"scene": {
"script": "./plugin/dist/scene.js"
},
"inspector": {
"section": {
"node": {
"BehaviorButton": "./plugin/dist/inspector/behavior.js"
}
}
},
"menu": [{
"path": "i18n:menu.extension/oreo-behavior-creator",
"label": "i18n:oreo-behavior-creator.open_panel",
"message": "open-panel"
},{
"path": "i18n:menu.extension/oreo-behavior-creator",
"label": "i18n:oreo-behavior-creator.update_tree_panel",
"message": "open_update_tree_panel"
}],
"messages": {
"open-panel": {
"methods": [
"open_panel"
]
},
"open_update_tree_panel": {
"methods": [
"open_update_tree_panel"
]
},
"edit-behavior": {
"methods": [
"edit_behavior"
]
},
"panel:edit-class": {
"methods": [
"default.onEditClass"
]
},
"send-to-panel": {
"methods": [
"default.hello"
]
},
"btclass-registered": {
"methods": [
"btclass_registered"
]
},
"get-asset-info": {
"methods": [
"getAssetInfo"
]
},
"get-class-info": {
"methods": [
"getClassInfo"
]
},
"save-asset-info": {
"methods": [
"onSaveAssetInfo"
]
},
"close-panel": {
"methods": [
"onClosePanel"
]
},
"asset-db:refresh-finish": {
"methods": [
"onAssetRefreshFinish",
"default.onAssetRefreshFinish"
]
}
}
}
}

View File

@@ -0,0 +1,7 @@
{
"type": ["bt.SharedBoolean", "bt.SharedNode", "bt.SharedNumber", "bt.SharedString"],
"global": {
},
"unsupported": ["bt.SharedArray", "bt.SharedCustom"]
}

View File

@@ -0,0 +1,3 @@
{
"ignore": ["RigidBodyComponent", "ColliderComponent", "RenderableComponent"]
}

View File

@@ -0,0 +1 @@
'use strict';var _0x20718a=_0x1fb7;function _0x1fb7(_0x3d2def,_0x217f1a){var _0x31a30f=_0x31a3();return _0x1fb7=function(_0x1fb7cb,_0x571680){_0x1fb7cb=_0x1fb7cb-0x167;var _0x22e6b1=_0x31a30f[_0x1fb7cb];return _0x22e6b1;},_0x1fb7(_0x3d2def,_0x217f1a);}(function(_0x29e29a,_0x35920b){var _0x4cf57f=_0x1fb7,_0xb2247a=_0x29e29a();while(!![]){try{var _0x4abea3=parseInt(_0x4cf57f(0x181))/0x1*(-parseInt(_0x4cf57f(0x182))/0x2)+parseInt(_0x4cf57f(0x17c))/0x3*(-parseInt(_0x4cf57f(0x17a))/0x4)+parseInt(_0x4cf57f(0x16f))/0x5*(-parseInt(_0x4cf57f(0x17b))/0x6)+-parseInt(_0x4cf57f(0x171))/0x7*(parseInt(_0x4cf57f(0x175))/0x8)+parseInt(_0x4cf57f(0x184))/0x9+parseInt(_0x4cf57f(0x16a))/0xa+-parseInt(_0x4cf57f(0x172))/0xb*(-parseInt(_0x4cf57f(0x18b))/0xc);if(_0x4abea3===_0x35920b)break;else _0xb2247a['push'](_0xb2247a['shift']());}catch(_0x3e18eb){_0xb2247a['push'](_0xb2247a['shift']());}}}(_0x31a3,0xd9ed7));var __createBinding=this&&this['__createBinding']||(Object[_0x20718a(0x174)]?function(_0x455d2d,_0xb4fceb,_0x30c036,_0x1efa5f){var _0x25e8e5=_0x20718a;void 0x0===_0x1efa5f&&(_0x1efa5f=_0x30c036);var _0x14010c=Object[_0x25e8e5(0x18e)](_0xb4fceb,_0x30c036);_0x14010c&&(_0x25e8e5(0x17d)in _0x14010c?_0xb4fceb['__esModule']:!_0x14010c[_0x25e8e5(0x193)]&&!_0x14010c[_0x25e8e5(0x194)])||(_0x14010c={'enumerable':!0x0,'get':function(){return _0xb4fceb[_0x30c036];}}),Object['defineProperty'](_0x455d2d,_0x1efa5f,_0x14010c);}:function(_0x44185c,_0x19ddea,_0x282a3e,_0x4f5a24){_0x44185c[_0x4f5a24=void 0x0===_0x4f5a24?_0x282a3e:_0x4f5a24]=_0x19ddea[_0x282a3e];}),__setModuleDefault=this&&this[_0x20718a(0x16c)]||(Object[_0x20718a(0x174)]?function(_0x433e72,_0x5f4733){Object['defineProperty'](_0x433e72,'default',{'enumerable':!0x0,'value':_0x5f4733});}:function(_0xa775dc,_0x15b5e6){var _0x340fd6=_0x20718a;_0xa775dc[_0x340fd6(0x176)]=_0x15b5e6;}),__importStar=this&&this[_0x20718a(0x179)]||function(_0x4da497){var _0xb25167=_0x20718a;if(_0x4da497&&_0x4da497[_0xb25167(0x177)])return _0x4da497;var _0x56574c={};if(null!=_0x4da497){for(var _0x1b7574 in _0x4da497)_0xb25167(0x176)!==_0x1b7574&&Object[_0xb25167(0x170)][_0xb25167(0x17f)][_0xb25167(0x189)](_0x4da497,_0x1b7574)&&__createBinding(_0x56574c,_0x4da497,_0x1b7574);}return __setModuleDefault(_0x56574c,_0x4da497),_0x56574c;};Object[_0x20718a(0x187)](exports,_0x20718a(0x177),{'value':!0x0});const packageJSON=__importStar(require(_0x20718a(0x180))),temp1=_0x20718a(0x188),temp2=_0x20718a(0x169);let component=null,root_uuid='';module[_0x20718a(0x18c)]=Editor[_0x20718a(0x185)][_0x20718a(0x183)]({'$':{'button':_0x20718a(0x198)},'template':temp1,'update'(_0x10f2b2){var _0x17193c=_0x20718a;(_0x10f2b2=((_0x10f2b2[_0x17193c(0x18d)]||{})[_0x17193c(0x18a)]||{})[_0x17193c(0x18d)]||{})[_0x17193c(0x192)]&&(root_uuid=_0x10f2b2['uuid'],this['getCompoennts'](_0x10f2b2[_0x17193c(0x192)]));},'ready'(){var _0x3d40cf=_0x20718a;this[_0x3d40cf(0x197)](!0x1);let _0x4ce06b=this[_0x3d40cf(0x17e)]();_0x4ce06b['addEventListener'](_0x3d40cf(0x16d),()=>{var _0x2039ec=_0x3d40cf;component&&component[_0x2039ec(0x16b)]?Editor[_0x2039ec(0x167)]['send'](packageJSON[_0x2039ec(0x168)],_0x2039ec(0x18f),{'component':component,'uuid':root_uuid}):Editor[_0x2039ec(0x167)][_0x2039ec(0x178)](packageJSON[_0x2039ec(0x168)],_0x2039ec(0x18f),{'msg':'You\x20must\x20assign\x20a\x20JsonAsset\x20before\x20editing\x20the\x20behavior\x20tree.'});});},'close'(){},'methods':{'getButton'(){var _0x3578ea=_0x20718a;return this['$'][_0x3578ea(0x16e)];},'showButton'(_0x714782){var _0x490476=_0x20718a;this[_0x490476(0x17e)]()[_0x490476(0x190)]['display']=_0x714782?_0x490476(0x173):_0x490476(0x186);},async 'getCompoennts'(_0x2190e4){var _0x332355=_0x20718a;_0x2190e4=await Editor['Message'][_0x332355(0x196)](_0x332355(0x195),'execute-scene-script',{'name':packageJSON[_0x332355(0x168)],'method':'getBehaviorTreeInfo','args':[_0x2190e4]}),_0x2190e4&&0x0<_0x2190e4[_0x332355(0x191)]?(component=_0x2190e4[0x0],this[_0x332355(0x197)](!0x0)):component=null;}}});function _0x31a3(){var _0x46d964=['send','__importStar','1909068kyPQnA','534dnQBoN','3QeraqM','get','getButton','hasOwnProperty','../../package.json','23620KCdRtA','2ZeZXiB','define','12028176XTsruJ','Panel','none','defineProperty','\x0a<ui-button\x20style=\x22width:\x2080%;\x20margin:\x2020px\x2010%\x205px;\x20border:\x20dashed\x201px\x22>Edit\x20Behavior</ui-button>\x0a','call','node','92208GpGHoO','exports','value','getOwnPropertyDescriptor','edit-behavior','style','length','uuid','writable','configurable','scene','request','showButton','ui-button','Message','name','\x0a<ui-prop>\x0a\x20\x20\x20\x20<ui-label\x20value=\x22Button\x22\x20slot=\x22label\x22></ui-label>\x0a\x20\x20\x20\x20<ui-button\x20slot=\x22content\x22>Edit\x20Behavior</ui-button>\x0a</ui-prop>\x0a','158340JBQFeU','jsonAsset','__setModuleDefault','confirm','button','36925oRUgUR','prototype','5384113zoTaAO','2101JeiGoo','block','create','8JBeUGJ','default','__esModule'];_0x31a3=function(){return _0x46d964;};return _0x31a3();}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
'use strict';const _0x3225c8=_0xb98f;function _0x28d3(){const _0x1c2b1b=['22023vgUMBw','getInstance','getOneVariable','bt.SharedBoolean','cc.Enum','getBlackboardAllType','name','number','2381GMqrnW','../../../utils/blackboard','isTypeVariable','bt.SharedDynamic','910bLKQGM','187624fvoTfw','default','bt.SharedVariable','TYPE','bt.SharedNumber','string','2496EExBDS','includes','bt.SharedNode','sort','common','Blackboard','defineProperty','enum','6072890rPgRFS','__esModule','boolean','3657006YHaUDc','10OFEdtl','getAllVariable','45xhjzlB','bt.SharedString','5830216rbMlFi','9025093TjuLZW','filter'];_0x28d3=function(){return _0x1c2b1b;};return _0x28d3();}function _0xb98f(_0x2f9119,_0x34a71f){const _0x28d353=_0x28d3();return _0xb98f=function(_0xb98ff9,_0x292f40){_0xb98ff9=_0xb98ff9-0x19c;let _0x5833df=_0x28d353[_0xb98ff9];return _0x5833df;},_0xb98f(_0x2f9119,_0x34a71f);}(function(_0x23ec1e,_0x4945ad){const _0x27779b=_0xb98f,_0x24802c=_0x23ec1e();while(!![]){try{const _0x3abcab=-parseInt(_0x27779b(0x1a6))/0x1*(parseInt(_0x27779b(0x1aa))/0x2)+parseInt(_0x27779b(0x1bf))/0x3*(parseInt(_0x27779b(0x1ab))/0x4)+-parseInt(_0x27779b(0x1bd))/0x5*(-parseInt(_0x27779b(0x1bc))/0x6)+-parseInt(_0x27779b(0x1c1))/0x7+-parseInt(_0x27779b(0x1b1))/0x8*(parseInt(_0x27779b(0x19e))/0x9)+parseInt(_0x27779b(0x1b9))/0xa+parseInt(_0x27779b(0x19c))/0xb;if(_0x3abcab===_0x4945ad)break;else _0x24802c['push'](_0x24802c['shift']());}catch(_0x4fc44b){_0x24802c['push'](_0x24802c['shift']());}}}(_0x28d3,0xa3bad));Object[_0x3225c8(0x1b7)](exports,_0x3225c8(0x1ba),{'value':!0x0}),exports[_0x3225c8(0x1b5)]=void 0x0;const blackboard_1=require(_0x3225c8(0x1a7)),blackboard=blackboard_1[_0x3225c8(0x1b6)][_0x3225c8(0x19f)]();exports[_0x3225c8(0x1b5)]={'getDefaultValue'(_0x557944){const _0x127a54=_0x3225c8;switch(_0x557944){case _0x127a54(0x1a5):case _0x127a54(0x1af):return 0x0;case _0x127a54(0x1b0):case _0x127a54(0x1c0):return'';case _0x127a54(0x1bb):case _0x127a54(0x1a1):return!0x1;default:return'';}},'isTypeString'(_0x3f0570){const _0x4ea495=_0x3225c8;return _0x3f0570[_0x4ea495(0x1ae)]?'bt.SharedString'==_0x3f0570[_0x4ea495(0x1ae)]:_0x4ea495(0x1b0)==typeof _0x3f0570[_0x4ea495(0x1ac)];},'isTypeNumber'(_0x489569){const _0x436428=_0x3225c8;return _0x489569[_0x436428(0x1ae)]?_0x436428(0x1af)==_0x489569['TYPE']:_0x436428(0x1a5)==typeof _0x489569[_0x436428(0x1ac)];},'isTypeBoolean'(_0x36d4b1){const _0x12c35d=_0x3225c8;return _0x36d4b1[_0x12c35d(0x1ae)]?_0x12c35d(0x1a1)==_0x36d4b1['TYPE']:'boolean'==typeof _0x36d4b1[_0x12c35d(0x1ac)];},'isTypeNode'(_0x1ed668){const _0x2686b6=_0x3225c8;return'cc.Node'==_0x1ed668[_0x2686b6(0x1ae)]||_0x2686b6(0x1b3)==_0x1ed668[_0x2686b6(0x1ae)];},'isTypeEnum'(_0x60b7d8){const _0x4a6684=_0x3225c8;return _0x4a6684(0x1a2)==_0x60b7d8[_0x4a6684(0x1ae)];},'isTypeBlackboard'(_0x4cbcc1){const _0x214d9b=_0x3225c8,_0x1c559c=this[_0x214d9b(0x1a3)]();return _0x1c559c instanceof Array&&_0x1c559c[_0x214d9b(0x1b2)](_0x4cbcc1[_0x214d9b(0x1ae)]);},'isTypeVariable'(_0xcb5c36){const _0xee0070=_0x3225c8;return _0xee0070(0x1ad)==_0xcb5c36['TYPE'];},'isTypeDynamic'(_0xf71c83){const _0x4b2861=_0x3225c8;return _0x4b2861(0x1a9)==_0xf71c83['TYPE'];},'getOneVariable'(_0x5c9238){const _0x12e01c=_0x3225c8;return blackboard[_0x12e01c(0x1a0)](_0x5c9238);},'getBlackboardAllType'(){return blackboard['getAllType']();},'getBlackboardVariableList'(_0x3c181e){const _0x548c88=_0x3225c8,_0x51af7d=blackboard['getAllVariable']();let _0xd39be5=_0x51af7d[_0x548c88(0x19d)](_0x5652f7=>_0x5652f7['value'][_0x548c88(0x1ae)]==_0x3c181e[_0x548c88(0x1ae)]);return _0xd39be5[_0x548c88(0x1b4)]((_0xb1d229,_0x4bba41)=>_0xb1d229[_0x548c88(0x1a4)]['localeCompare'](_0x4bba41[_0x548c88(0x1a4)])),_0xd39be5;},'getEnumVariableList'(_0x438ce0){const _0x4bd9a9=_0x3225c8;return _0x438ce0[_0x4bd9a9(0x1b8)];},'getAllVariableList'(_0x50e2d6){const _0x4ee880=_0x3225c8;let _0x273410=[];return this[_0x4ee880(0x1a8)](_0x50e2d6)&&(_0x273410=blackboard[_0x4ee880(0x1be)]())[_0x4ee880(0x1b4)]((_0x2f402d,_0x45fbb6)=>_0x2f402d[_0x4ee880(0x1a4)]['localeCompare'](_0x45fbb6[_0x4ee880(0x1a4)])),_0x273410;}};

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
'use strict';function _0x157d(){const _0x1a0202=['uuid','6MroAnn','path','3394106gfXInk','onSyncAllData','../../../utils/util','join','../../../../static/template/update_tree/index.html','request','运行时版本:','packageJSON','63779190swjEge','Message','exports','674020TewLOk','length','version_waring','8241462jXQhHo','utf-8','5683948IRuLiX','log','../../../../static/template/vue/update_tree.html','../../../../static/style/update_tree/index.css','1877379wIFdxf','get\x20json\x20file\x20error:\x20','runtime','version','default','blackboard','fs-extra','#tree_panel_app','defineProperty','readFileSync','app','localeCompare','refs','push','file','8oyXfpo','list','util','cc.JsonAsset','parse','hide','1234933IHkQhv','asset-db','show','query-assets','Panel','define','3DmiUft','version_error'];_0x157d=function(){return _0x1a0202;};return _0x157d();}const _0x187041=_0x2d92;(function(_0x4c7cd7,_0x172d30){const _0x4762bf=_0x2d92,_0x33bb14=_0x4c7cd7();while(!![]){try{const _0x45aed7=-parseInt(_0x4762bf(0x151))/0x1+parseInt(_0x4762bf(0x128))/0x2*(-parseInt(_0x4762bf(0x123))/0x3)+-parseInt(_0x4762bf(0x138))/0x4+parseInt(_0x4762bf(0x133))/0x5+parseInt(_0x4762bf(0x126))/0x6*(-parseInt(_0x4762bf(0x13c))/0x7)+parseInt(_0x4762bf(0x14b))/0x8*(-parseInt(_0x4762bf(0x136))/0x9)+parseInt(_0x4762bf(0x130))/0xa;if(_0x45aed7===_0x172d30)break;else _0x33bb14['push'](_0x33bb14['shift']());}catch(_0x225fcf){_0x33bb14['push'](_0x33bb14['shift']());}}}(_0x157d,0xee3db));var __importDefault=this&&this['__importDefault']||function(_0x2e7a4a){return _0x2e7a4a&&_0x2e7a4a['__esModule']?_0x2e7a4a:{'default':_0x2e7a4a};};function _0x2d92(_0x20665e,_0x4afb51){const _0x157d35=_0x157d();return _0x2d92=function(_0x2d9272,_0x90c4e2){_0x2d9272=_0x2d9272-0x123;let _0x616a9b=_0x157d35[_0x2d9272];return _0x616a9b;},_0x2d92(_0x20665e,_0x4afb51);}Object[_0x187041(0x144)](exports,'__esModule',{'value':!0x0});const fs_extra_1=require(_0x187041(0x142)),path_1=require(_0x187041(0x127)),vue_1=__importDefault(require('vue/dist/vue')),util_1=require(_0x187041(0x12a));module[_0x187041(0x132)]=Editor[_0x187041(0x155)][_0x187041(0x156)]({'listeners':{'show'(){const _0x16adf1=_0x187041;console[_0x16adf1(0x139)](_0x16adf1(0x153));},'hide'(){const _0xa9d722=_0x187041;console[_0xa9d722(0x139)](_0xa9d722(0x150));}},'template':(0x0,fs_extra_1['readFileSync'])((0x0,path_1[_0x187041(0x12b)])(__dirname,_0x187041(0x12c)),_0x187041(0x137)),'style':(0x0,fs_extra_1[_0x187041(0x145)])((0x0,path_1['join'])(__dirname,_0x187041(0x13b)),'utf-8'),'$':{'app':_0x187041(0x143)},'methods':{'hello'(){}},'ready'(){const _0x398a13=_0x187041;this['$'][_0x398a13(0x146)]&&new vue_1[(_0x398a13(0x140))]({'template':(0x0,fs_extra_1[_0x398a13(0x145)])((0x0,path_1[_0x398a13(0x12b)])(__dirname,_0x398a13(0x13a)),_0x398a13(0x137)),'data'(){return{'list':[]};},'mounted'(){this['initList']();},'methods':{async 'initList'(){const _0x1d8127=_0x398a13;this[_0x1d8127(0x14c)][_0x1d8127(0x134)]=0x0;let _0xd866b=await Editor[_0x1d8127(0x131)][_0x1d8127(0x12d)](_0x1d8127(0x152),_0x1d8127(0x154),{'ccType':_0x1d8127(0x14e),'pattern':'db://**'});_0xd866b['forEach'](_0x3df714=>{const _0x23e20f=_0x1d8127;try{let _0x229388={};_0x229388['url']=_0x3df714['url'],_0x229388[_0x23e20f(0x125)]=_0x3df714[_0x23e20f(0x125)];var _0xa3b96c=(0x0,fs_extra_1['readFileSync'])(_0x3df714[_0x23e20f(0x14a)],_0x23e20f(0x137)),_0x1810bb=JSON[_0x23e20f(0x14f)](_0xa3b96c);'string'==typeof(null==_0x1810bb?void 0x0:_0x1810bb['version'])&&((_0x1810bb[_0x23e20f(0x13e)]==util_1[_0x23e20f(0x14d)][_0x23e20f(0x12f)]['name']||_0x1810bb['root']&&_0x1810bb[_0x23e20f(0x141)]&&_0x1810bb[_0x23e20f(0x148)])&&(_0x229388[_0x23e20f(0x13f)]=_0x1810bb[_0x23e20f(0x13f)]),_0x229388[_0x23e20f(0x13f)]&&this[_0x23e20f(0x14c)][_0x23e20f(0x149)](_0x229388));}catch(_0x13cbcf){util_1[_0x23e20f(0x14d)]['error'](_0x23e20f(0x13d),_0x13cbcf);}});},'onSyncAllData'(){const _0x5e6a10=_0x398a13;console[_0x5e6a10(0x139)](_0x5e6a10(0x129));},'getVersion'(){const _0x56e5ff=_0x398a13;return _0x56e5ff(0x12e)+util_1[_0x56e5ff(0x14d)][_0x56e5ff(0x12f)][_0x56e5ff(0x13f)];},'getVersionColor'(_0x13cd92){const _0x298595=_0x398a13;return _0x13cd92['version'][_0x298595(0x147)](util_1[_0x298595(0x14d)][_0x298595(0x12f)][_0x298595(0x13f)])<0x0?_0x13cd92['version']['localeCompare'](util_1['util'][_0x298595(0x12f)]['compatible_version'])<0x0?_0x298595(0x124):_0x298595(0x135):'';}},'el':this['$']['app']});},'beforeClose'(){},'close'(){}});

View File

@@ -0,0 +1 @@
'use strict';var _0x23e4cb=_0x1724;(function(_0x375846,_0x4a470b){var _0x17a05e=_0x1724,_0x174083=_0x375846();while(!![]){try{var _0x19c00c=parseInt(_0x17a05e(0x13d))/0x1*(-parseInt(_0x17a05e(0x132))/0x2)+-parseInt(_0x17a05e(0x140))/0x3+-parseInt(_0x17a05e(0x143))/0x4*(parseInt(_0x17a05e(0x13c))/0x5)+parseInt(_0x17a05e(0x142))/0x6+-parseInt(_0x17a05e(0x147))/0x7+parseInt(_0x17a05e(0x14a))/0x8+parseInt(_0x17a05e(0x130))/0x9*(parseInt(_0x17a05e(0x139))/0xa);if(_0x19c00c===_0x4a470b)break;else _0x174083['push'](_0x174083['shift']());}catch(_0x2adb25){_0x174083['push'](_0x174083['shift']());}}}(_0x4222,0xe1808));var __importDefault=this&&this[_0x23e4cb(0x150)]||function(_0x31b79c){var _0x2e3aae=_0x23e4cb;return _0x31b79c&&_0x31b79c[_0x2e3aae(0x134)]?_0x31b79c:{'default':_0x31b79c};};Object[_0x23e4cb(0x13e)](exports,_0x23e4cb(0x134),{'value':!0x0});function _0x4222(){var _0x243f80=['__esModule','Panel','join','../../../../static/template/usage/index.html','#app','26227030bxTcFn','default','define','7899245VVyYmJ','397GxXRUr','defineProperty','#text','1081299MeExmy','readFileSync','10413042OyRqYM','4yPStOE','log','innerHTML','hello','9369094igvkVN','exports','text','8811752lPLTCm','show','app','../../../../../README.md','counter','utf-8','__importDefault','path','9ZihDzH','fs-extra','6334mHOiYG','[cocos-panel-html.default]:\x20hello'];_0x4222=function(){return _0x243f80;};return _0x4222();}function _0x1724(_0x34ad52,_0x312f23){var _0x4222f8=_0x4222();return _0x1724=function(_0x1724dc,_0x5c5f27){_0x1724dc=_0x1724dc-0x12f;var _0x319242=_0x4222f8[_0x1724dc];return _0x319242;},_0x1724(_0x34ad52,_0x312f23);}const fs_extra_1=require(_0x23e4cb(0x131)),path_1=require(_0x23e4cb(0x12f)),vue_1=__importDefault(require('vue/dist/vue'));module[_0x23e4cb(0x148)]=Editor[_0x23e4cb(0x135)][_0x23e4cb(0x13b)]({'listeners':{'show'(){var _0x3ab556=_0x23e4cb;console[_0x3ab556(0x144)](_0x3ab556(0x14b));},'hide'(){var _0x1d297b=_0x23e4cb;console[_0x1d297b(0x144)]('hide');}},'template':(0x0,fs_extra_1[_0x23e4cb(0x141)])((0x0,path_1['join'])(__dirname,_0x23e4cb(0x137)),_0x23e4cb(0x14f)),'style':(0x0,fs_extra_1[_0x23e4cb(0x141)])((0x0,path_1['join'])(__dirname,'../../../../static/style/usage/index.css'),'utf-8'),'$':{'app':_0x23e4cb(0x138),'text':_0x23e4cb(0x13f)},'methods':{'hello'(){var _0x172762=_0x23e4cb;this['$'][_0x172762(0x149)]&&(this['$'][_0x172762(0x149)][_0x172762(0x145)]=_0x172762(0x146),console[_0x172762(0x144)](_0x172762(0x133)));}},'ready'(){var _0x2f2657=_0x23e4cb;this['$'][_0x2f2657(0x149)],this['$'][_0x2f2657(0x14c)]&&new vue_1[(_0x2f2657(0x13a))]({'template':(0x0,fs_extra_1[_0x2f2657(0x141)])((0x0,path_1['join'])(__dirname,'../../../../static/template/vue/usage.html'),_0x2f2657(0x14f)),'data'(){var _0xdc05eb=_0x2f2657;return{'counter':0x0,'content':(0x0,fs_extra_1['readFileSync'])((0x0,path_1[_0xdc05eb(0x136)])(__dirname,_0xdc05eb(0x14d)),_0xdc05eb(0x14f))};},'methods':{'addition'(){var _0x1ac8cf=_0x2f2657;this[_0x1ac8cf(0x14e)]+=0x1;},'subtraction'(){var _0x1ad71d=_0x2f2657;--this[_0x1ad71d(0x14e)];}},'el':this['$'][_0x2f2657(0x14c)]});},'beforeClose'(){},'close'(){}});

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
'use strict';var _0xdb3fe2=_0x2cb4;(function(_0x2e6740,_0x4f5499){var _0x2bd0fb=_0x2cb4,_0x411029=_0x2e6740();while(!![]){try{var _0x75a7f6=parseInt(_0x2bd0fb(0xf4))/0x1*(-parseInt(_0x2bd0fb(0xf1))/0x2)+parseInt(_0x2bd0fb(0xeb))/0x3*(parseInt(_0x2bd0fb(0xf6))/0x4)+-parseInt(_0x2bd0fb(0xf7))/0x5*(parseInt(_0x2bd0fb(0xec))/0x6)+-parseInt(_0x2bd0fb(0xea))/0x7*(parseInt(_0x2bd0fb(0xf3))/0x8)+-parseInt(_0x2bd0fb(0xf5))/0x9*(parseInt(_0x2bd0fb(0xef))/0xa)+parseInt(_0x2bd0fb(0xf0))/0xb+parseInt(_0x2bd0fb(0xed))/0xc;if(_0x75a7f6===_0x4f5499)break;else _0x411029['push'](_0x411029['shift']());}catch(_0x594138){_0x411029['push'](_0x411029['shift']());}}}(_0x1b65,0x9a965));function _0x1b65(){var _0x27d408=['1404590VBDRCZ','122762tyJoXA','defineProperty','90536kzKMhX','13Mgitnb','9hAwtnM','467708vrvgiz','91115VJZkWi','__esModule','707bWxIuq','27mYsoNW','54HJmTsS','20158956eTVdbG','components','1217800JGoirp'];_0x1b65=function(){return _0x27d408;};return _0x1b65();}function _0x2cb4(_0x2240c2,_0x5a2999){var _0x1b658c=_0x1b65();return _0x2cb4=function(_0x2cb47b,_0xea5f43){_0x2cb47b=_0x2cb47b-0xea;var _0x846fa1=_0x1b658c[_0x2cb47b];return _0x846fa1;},_0x2cb4(_0x2240c2,_0x5a2999);}Object[_0xdb3fe2(0xf2)](exports,_0xdb3fe2(0xf8),{'value':!0x0}),exports[_0xdb3fe2(0xee)]=void 0x0,exports[_0xdb3fe2(0xee)]={};

View File

@@ -0,0 +1 @@
'use strict';var _0x2c8a6c=_0x48c0;(function(_0x2fe105,_0x2b9041){var _0x3f869f=_0x48c0,_0x222a53=_0x2fe105();while(!![]){try{var _0x59dd58=-parseInt(_0x3f869f(0x1c2))/0x1+-parseInt(_0x3f869f(0x1c1))/0x2+parseInt(_0x3f869f(0x1b3))/0x3*(parseInt(_0x3f869f(0x1b6))/0x4)+-parseInt(_0x3f869f(0x1c3))/0x5+parseInt(_0x3f869f(0x1bf))/0x6*(parseInt(_0x3f869f(0x1b4))/0x7)+parseInt(_0x3f869f(0x1ba))/0x8*(parseInt(_0x3f869f(0x1b9))/0x9)+-parseInt(_0x3f869f(0x1b5))/0xa;if(_0x59dd58===_0x2b9041)break;else _0x222a53['push'](_0x222a53['shift']());}catch(_0x13ae8e){_0x222a53['push'](_0x222a53['shift']());}}}(_0x9073,0x389b8));function _0x48c0(_0x5edc85,_0x528fb2){var _0x907324=_0x9073();return _0x48c0=function(_0x48c0d7,_0x111084){_0x48c0d7=_0x48c0d7-0x1b3;var _0x30d693=_0x907324[_0x48c0d7];return _0x30d693;},_0x48c0(_0x5edc85,_0x528fb2);}function _0x9073(){var _0x500282=['defineProperty','90142nkIWuF','183543JgnrKO','95300oVFVKI','REFRESH_COMPONENT','189765cmhynP','1358pWMXgA','2164510KIjrrr','8DsqFpS','__importDefault','event','752337gAuMKE','40XcNYmN','default','target','./onfire','__esModule','4686CdWInj'];_0x9073=function(){return _0x500282;};return _0x9073();}var __importDefault=this&&this[_0x2c8a6c(0x1b7)]||function(_0x47b78d){var _0x46f66b=_0x2c8a6c;return _0x47b78d&&_0x47b78d[_0x46f66b(0x1be)]?_0x47b78d:{'default':_0x47b78d};};Object[_0x2c8a6c(0x1c0)](exports,_0x2c8a6c(0x1be),{'value':!0x0}),exports[_0x2c8a6c(0x1b8)]=exports['target']=void 0x0;const onfire_1=__importDefault(require(_0x2c8a6c(0x1bd)));exports[_0x2c8a6c(0x1bc)]=new onfire_1[(_0x2c8a6c(0x1bb))](),exports[_0x2c8a6c(0x1b8)]={'MODIFY':'MODIFY','REFRESH_COMPONENT':_0x2c8a6c(0x1c4)};

View File

@@ -0,0 +1 @@
'use strict';const _0x4b5426=_0x222f;(function(_0x58746b,_0x4bd6ae){const _0x48115d=_0x222f,_0x2ac771=_0x58746b();while(!![]){try{const _0x24f2e6=parseInt(_0x48115d(0xe9))/0x1+-parseInt(_0x48115d(0xe5))/0x2*(-parseInt(_0x48115d(0xec))/0x3)+-parseInt(_0x48115d(0xea))/0x4*(parseInt(_0x48115d(0xe3))/0x5)+parseInt(_0x48115d(0xef))/0x6+parseInt(_0x48115d(0xe7))/0x7+parseInt(_0x48115d(0xe8))/0x8*(-parseInt(_0x48115d(0xe1))/0x9)+-parseInt(_0x48115d(0xf3))/0xa;if(_0x24f2e6===_0x4bd6ae)break;else _0x2ac771['push'](_0x2ac771['shift']());}catch(_0x3a0f6b){_0x2ac771['push'](_0x2ac771['shift']());}}}(_0x2af1,0xb4885));Object[_0x4b5426(0xde)](exports,_0x4b5426(0xf2),{'value':!0x0});function _0x222f(_0x466d93,_0xbec72){const _0x2af194=_0x2af1();return _0x222f=function(_0x222ff1,_0x2f9f06){_0x222ff1=_0x222ff1-0xdd;let _0x35e670=_0x2af194[_0x222ff1];return _0x35e670;},_0x222f(_0x466d93,_0xbec72);}class OnFire{constructor(){this['es']={};}['on'](_0x2a8dd3,_0x4e8b8a,_0x36e523=!0x1){const _0x175c5e=_0x4b5426;this['es'][_0x2a8dd3]||(this['es'][_0x2a8dd3]=[]),this['es'][_0x2a8dd3][_0x175c5e(0xdd)]({'cb':_0x4e8b8a,'once':_0x36e523});}[_0x4b5426(0xe6)](_0x9dfe26,_0x5edc5f){this['on'](_0x9dfe26,_0x5edc5f,!0x0);}[_0x4b5426(0xe0)](_0x2cb7f9,..._0x4c1c34){const _0x3ce30a=_0x4b5426,_0x3dc9cf=this['es'][_0x2cb7f9]||[];let _0x38dce8=_0x3dc9cf[_0x3ce30a(0xeb)];for(let _0x50a14a=0x0;_0x50a14a<_0x38dce8;_0x50a14a++){const {cb:_0x1a7d6f,once:_0x548731}=_0x3dc9cf[_0x50a14a];_0x1a7d6f[_0x3ce30a(0xee)](this,_0x4c1c34),_0x548731&&(_0x3dc9cf[_0x3ce30a(0xf0)](_0x50a14a,0x1),_0x50a14a--,_0x38dce8--);}}[_0x4b5426(0xdf)](_0x5c706b,_0x8e67b0){const _0x1ac398=_0x4b5426;if(void 0x0===_0x5c706b)this['es']={};else{if(void 0x0===_0x8e67b0)delete this['es'][_0x5c706b];else{const _0x4e7461=this['es'][_0x5c706b]||[];let _0x242c1c=_0x4e7461[_0x1ac398(0xeb)];for(let _0x16555f=0x0;_0x16555f<_0x242c1c;_0x16555f++)_0x4e7461[_0x16555f]['cb']===_0x8e67b0&&(_0x4e7461[_0x1ac398(0xf0)](_0x16555f,0x1),_0x16555f--,_0x242c1c--);}}}[_0x4b5426(0xed)](_0x2017c9,..._0x1a0b0d){this['fire'](_0x2017c9,..._0x1a0b0d);}}function _0x2af1(){const _0x3eb5f8=['5KTZdVF','default','6RpktmN','once','9339596TOdFhu','1583096FGMhSV','1012308btHKtG','283252FVrudJ','length','1302057yuSpQn','emit','apply','7804260PMqEiA','splice','__VERSION__','__esModule','35453680hIDjEa','push','defineProperty','off','fire','27TNTEpX','ver'];_0x2af1=function(){return _0x3eb5f8;};return _0x2af1();}(exports[_0x4b5426(0xe4)]=OnFire)[_0x4b5426(0xe2)]=_0x4b5426(0xf1);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.container[data-v-f54e8984]{overflow:hidden;height:100%}#scene[data-v-f54e8984]{width:100%;height:100%;background-color:#fff}.tools-main[data-v-f54e8984]{height:100%;width:100%}.sider[data-v-f54e8984]{right:0;overflow:auto}.edit_props[data-v-f54e8984],.sider[data-v-f54e8984]{background-color:#303030;color:#eee;position:absolute;top:0;height:100%}.edit_props[data-v-f54e8984]{left:0;width:100px}.tabs[data-v-f54e8984]{color:#eee!important}.menu[data-v-f54e8984]{position:absolute;top:0;left:250px;overflow:visible;text-align:left;margin-left:10px;margin-top:10px}.menu-buildin[data-v-f54e8984]{left:0}.ivu-dropdown[data-v-f54e8984]{margin-left:10px}.sider[data-v-f54e8984] .ivu-tabs-bar{margin-bottom:2px}.sider[data-v-f54e8984] .ivu-tabs.ivu-tabs-card>.ivu-tabs-bar .ivu-tabs-tab{border-color:grey;background:transparent;padding:5px 10px 4px;margin-right:2px;color:#e4e4e4}.sider[data-v-f54e8984] .ivu-tabs.ivu-tabs-card>.ivu-tabs-bar .ivu-tabs-tab-active{color:#65acf8}.sider[data-v-f54e8984] .ivu-collapse{background-color:transparent;border-left:0;border-top:0;border-right:0}.sider[data-v-f54e8984] .ivu-collapse>.ivu-collapse-item>.ivu-collapse-header{color:#e4e4e4;background-color:#1f1f1f}.sider[data-v-f54e8984] .ivu-collapse>.ivu-collapse-item>.ivu-collapse-content{background-color:rgba(31,31,31,.1843137254901961)}.sider[data-v-f54e8984] .ivu-btn{text-align:left;cursor:-webkit-grab;cursor:grab;background-color:#363636;color:#e4e4e4;margin-bottom:2px;border-color:rgba(220,222,226,.3215686274509804)}.panel-group[data-v-f54e8984]{font-size:14px}.button-type[data-v-f54e8984]{font-size:12px}.button-icon[data-v-f54e8984]{font-size:20px;margin-left:-5px;margin-right:5px}.button-icon-large[data-v-f54e8984]{font-size:24px}.tab-row[data-v-f54e8984]{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;line-height:30px;color:#e4e4e4}.tab-row-height[data-v-f54e8984]{line-height:inherit;-ms-flex-item-align:center;align-self:center}.tab-row-icon[data-v-f54e8984]{font-size:20px;margin-left:-5px;margin-right:5px;padding-bottom:2px}.tab-row-icon-small[data-v-f54e8984]{font-size:16px;margin-left:-5px;margin-right:5px;padding-bottom:2px}#app{font-family:Avenir,Helvetica,Arial,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-align:center;color:#2c3e50;overflow:hidden}#app,.tools-main{height:100%;width:100%}.layout{border:1px solid #d7dde4;background:#f5f7f9;position:relative;border-radius:4px;overflow:hidden;height:100%}.layout-logo{width:40px;border-radius:3px;left:20px}.layout-logo,.layout-title{height:40px;float:left;position:relative;top:15px}.layout-title{width:100px;color:#fff;line-height:40px}.layout-nav{width:420px;margin:0 auto;margin-right:20px}.CodeMirror{border:1px solid #eee;height:600px}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

After

Width:  |  Height:  |  Size: 434 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 542 KiB

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,378 @@
{
"name": "oreo-behavior-creator",
"version": "1.0.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"@electron/remote": {
"version": "2.0.8",
"resolved": "https://registry.npmmirror.com/@electron/remote/-/remote-2.0.8.tgz",
"integrity": "sha512-P10v3+iFCIvEPeYzTWWGwwHmqWnjoh8RYnbtZAb3RlQefy4guagzIwcWtfftABIfm6JJTNQf4WPSKWZOpLmHXw=="
},
"ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmmirror.com/ajv/-/ajv-6.12.6.tgz",
"integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==",
"requires": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
"json-schema-traverse": "^0.4.1",
"uri-js": "^4.2.2"
}
},
"asn1": {
"version": "0.2.6",
"resolved": "https://registry.npmmirror.com/asn1/-/asn1-0.2.6.tgz",
"integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==",
"requires": {
"safer-buffer": "~2.1.0"
}
},
"assert-plus": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/assert-plus/-/assert-plus-1.0.0.tgz",
"integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw=="
},
"asynckit": {
"version": "0.4.0",
"resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz",
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
},
"aws-sign2": {
"version": "0.7.0",
"resolved": "https://registry.npmmirror.com/aws-sign2/-/aws-sign2-0.7.0.tgz",
"integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA=="
},
"aws4": {
"version": "1.11.0",
"resolved": "https://registry.npmmirror.com/aws4/-/aws4-1.11.0.tgz",
"integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA=="
},
"bcrypt-pbkdf": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
"integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==",
"requires": {
"tweetnacl": "^0.14.3"
}
},
"caseless": {
"version": "0.12.0",
"resolved": "https://registry.npmmirror.com/caseless/-/caseless-0.12.0.tgz",
"integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw=="
},
"combined-stream": {
"version": "1.0.8",
"resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz",
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
"requires": {
"delayed-stream": "~1.0.0"
}
},
"core-util-is": {
"version": "1.0.2",
"resolved": "https://registry.npmmirror.com/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ=="
},
"dashdash": {
"version": "1.14.1",
"resolved": "https://registry.npmmirror.com/dashdash/-/dashdash-1.14.1.tgz",
"integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==",
"requires": {
"assert-plus": "^1.0.0"
}
},
"delayed-stream": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz",
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ=="
},
"ecc-jsbn": {
"version": "0.1.2",
"resolved": "https://registry.npmmirror.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
"integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==",
"requires": {
"jsbn": "~0.1.0",
"safer-buffer": "^2.1.0"
}
},
"extend": {
"version": "3.0.2",
"resolved": "https://registry.npmmirror.com/extend/-/extend-3.0.2.tgz",
"integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
},
"extsprintf": {
"version": "1.3.0",
"resolved": "https://registry.npmmirror.com/extsprintf/-/extsprintf-1.3.0.tgz",
"integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g=="
},
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmmirror.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
"integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="
},
"fast-json-stable-stringify": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz",
"integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="
},
"forever-agent": {
"version": "0.6.1",
"resolved": "https://registry.npmmirror.com/forever-agent/-/forever-agent-0.6.1.tgz",
"integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw=="
},
"form-data": {
"version": "2.3.3",
"resolved": "https://registry.npmmirror.com/form-data/-/form-data-2.3.3.tgz",
"integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
"requires": {
"asynckit": "^0.4.0",
"combined-stream": "^1.0.6",
"mime-types": "^2.1.12"
}
},
"fs-extra": {
"version": "10.1.0",
"resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-10.1.0.tgz",
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"requires": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
"universalify": "^2.0.0"
}
},
"getpass": {
"version": "0.1.7",
"resolved": "https://registry.npmmirror.com/getpass/-/getpass-0.1.7.tgz",
"integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==",
"requires": {
"assert-plus": "^1.0.0"
}
},
"graceful-fs": {
"version": "4.2.10",
"resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.10.tgz",
"integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA=="
},
"har-schema": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/har-schema/-/har-schema-2.0.0.tgz",
"integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q=="
},
"har-validator": {
"version": "5.1.5",
"resolved": "https://registry.npmmirror.com/har-validator/-/har-validator-5.1.5.tgz",
"integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==",
"requires": {
"ajv": "^6.12.3",
"har-schema": "^2.0.0"
}
},
"http-signature": {
"version": "1.2.0",
"resolved": "https://registry.npmmirror.com/http-signature/-/http-signature-1.2.0.tgz",
"integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==",
"requires": {
"assert-plus": "^1.0.0",
"jsprim": "^1.2.2",
"sshpk": "^1.7.0"
}
},
"is-typedarray": {
"version": "1.0.0",
"resolved": "https://registry.npmmirror.com/is-typedarray/-/is-typedarray-1.0.0.tgz",
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
},
"isstream": {
"version": "0.1.2",
"resolved": "https://registry.npmmirror.com/isstream/-/isstream-0.1.2.tgz",
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g=="
},
"jsbn": {
"version": "0.1.1",
"resolved": "https://registry.npmmirror.com/jsbn/-/jsbn-0.1.1.tgz",
"integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg=="
},
"json-schema": {
"version": "0.4.0",
"resolved": "https://registry.npmmirror.com/json-schema/-/json-schema-0.4.0.tgz",
"integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA=="
},
"json-schema-traverse": {
"version": "0.4.1",
"resolved": "https://registry.npmmirror.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
"integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
},
"json-stringify-safe": {
"version": "5.0.1",
"resolved": "https://registry.npmmirror.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
"integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA=="
},
"jsonfile": {
"version": "6.1.0",
"resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz",
"integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==",
"requires": {
"graceful-fs": "^4.1.6",
"universalify": "^2.0.0"
}
},
"jsprim": {
"version": "1.4.2",
"resolved": "https://registry.npmmirror.com/jsprim/-/jsprim-1.4.2.tgz",
"integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==",
"requires": {
"assert-plus": "1.0.0",
"extsprintf": "1.3.0",
"json-schema": "0.4.0",
"verror": "1.10.0"
}
},
"mime-db": {
"version": "1.52.0",
"resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg=="
},
"mime-types": {
"version": "2.1.35",
"resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
"requires": {
"mime-db": "1.52.0"
}
},
"oauth-sign": {
"version": "0.9.0",
"resolved": "https://registry.npmmirror.com/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
},
"performance-now": {
"version": "2.1.0",
"resolved": "https://registry.npmmirror.com/performance-now/-/performance-now-2.1.0.tgz",
"integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow=="
},
"psl": {
"version": "1.8.0",
"resolved": "https://registry.npmmirror.com/psl/-/psl-1.8.0.tgz",
"integrity": "sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ=="
},
"punycode": {
"version": "2.1.1",
"resolved": "https://registry.npmmirror.com/punycode/-/punycode-2.1.1.tgz",
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
},
"qs": {
"version": "6.5.3",
"resolved": "https://registry.npmmirror.com/qs/-/qs-6.5.3.tgz",
"integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA=="
},
"request": {
"version": "2.88.2",
"resolved": "https://registry.npmmirror.com/request/-/request-2.88.2.tgz",
"integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==",
"requires": {
"aws-sign2": "~0.7.0",
"aws4": "^1.8.0",
"caseless": "~0.12.0",
"combined-stream": "~1.0.6",
"extend": "~3.0.2",
"forever-agent": "~0.6.1",
"form-data": "~2.3.2",
"har-validator": "~5.1.3",
"http-signature": "~1.2.0",
"is-typedarray": "~1.0.0",
"isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0",
"qs": "~6.5.2",
"safe-buffer": "^5.1.2",
"tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0",
"uuid": "^3.3.2"
}
},
"safe-buffer": {
"version": "5.2.1",
"resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz",
"integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
},
"safer-buffer": {
"version": "2.1.2",
"resolved": "https://registry.npmmirror.com/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"sshpk": {
"version": "1.17.0",
"resolved": "https://registry.npmmirror.com/sshpk/-/sshpk-1.17.0.tgz",
"integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==",
"requires": {
"asn1": "~0.2.3",
"assert-plus": "^1.0.0",
"bcrypt-pbkdf": "^1.0.0",
"dashdash": "^1.12.0",
"ecc-jsbn": "~0.1.1",
"getpass": "^0.1.1",
"jsbn": "~0.1.0",
"safer-buffer": "^2.0.2",
"tweetnacl": "~0.14.0"
}
},
"tough-cookie": {
"version": "2.5.0",
"resolved": "https://registry.npmmirror.com/tough-cookie/-/tough-cookie-2.5.0.tgz",
"integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==",
"requires": {
"psl": "^1.1.28",
"punycode": "^2.1.1"
}
},
"tunnel-agent": {
"version": "0.6.0",
"resolved": "https://registry.npmmirror.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
"integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==",
"requires": {
"safe-buffer": "^5.0.1"
}
},
"tweetnacl": {
"version": "0.14.5",
"resolved": "https://registry.npmmirror.com/tweetnacl/-/tweetnacl-0.14.5.tgz",
"integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA=="
},
"universalify": {
"version": "2.0.0",
"resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.0.tgz",
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
},
"uri-js": {
"version": "4.4.1",
"resolved": "https://registry.npmmirror.com/uri-js/-/uri-js-4.4.1.tgz",
"integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==",
"requires": {
"punycode": "^2.1.0"
}
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmmirror.com/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A=="
},
"verror": {
"version": "1.10.0",
"resolved": "https://registry.npmmirror.com/verror/-/verror-1.10.0.tgz",
"integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==",
"requires": {
"assert-plus": "^1.0.0",
"core-util-is": "1.0.2",
"extsprintf": "^1.2.0"
}
},
"vue": {
"version": "2.6.14",
"resolved": "https://registry.npmmirror.com/vue/-/vue-2.6.14.tgz",
"integrity": "sha512-x2284lgYvjOMj3Za7kqzRcUSxBboHqtgRE2zlos1qWaOye5yUmHn42LB1250NJBLRwEcdrB0JRwyPTEPhfQjiQ=="
}
}
}

View File

@@ -0,0 +1,16 @@
{
"package_version": 2,
"version": "1.0.0",
"name": "oreo-behavior-creator",
"dependencies": {
"@electron/remote": "^2.0.8",
"fs-extra": "^10.0.0",
"request": "^2.88.2",
"vue": "^2.6.14"
},
"scripts": {
"build": "tsc -b",
"watch": "tsc -w"
}
}

View File

@@ -0,0 +1,37 @@
.blackboard {
margin: 0px 10px;
}
.blackboard-content {
margin: 0px 10px;
}
.section-header {
margin-top: 10px;
}
.btn-create {
width: 80%;
line-height: 22px;
margin: 5px 10% 5px;
/* border: dashed 1px */
}
.btn-apply {
width: 30%;
line-height: 22px;
margin: 5px 5% 5px 15%;
/* border: dashed 1px */
}
.btn-cancel {
width: 30%;
line-height: 22px;
margin: 5px 12% 5px 5%;
/* border: dashed 1px */
}
.line {
margin: 5px 0px;
border-bottom: solid 2px rgba(128, 128, 128, 0.5);
}

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,47 @@
:host {
/* display: flex; */
overflow-y: scroll;
}
/* #tree_panel_app {
overflow-y: scroll;
}
#tree_panel {
overflow-y: scroll;
} */
.title {
font-size: large;
}
.version_error {
color: red;
}
.version_waring {
color: orange;
}
.div_mg8 {
margin: 10px 8px;
}
.div_mgt8 {
margin: 5px 8px 0px;
}
.div_line {
border-bottom: solid 1px rgb(155, 155, 106);
margin: 0px 0px 0px 8px;
}
.div_mg10 {
margin: 0px 10px;
}
.prop-script {
padding-top: 5px;
margin-top: 2px;
align-items: center;
/* border-top: dashed 1px rgba(128, 128, 128, 0.2); */
}
.row_item {
margin: 5px 8px;
}
.label_asset {
margin: 5px 8px;
min-width: 150px;
width: 100%;
}

View File

@@ -0,0 +1,8 @@
#text {
color: var(--color-normal-contrast-weakest);
margin: auto;
width: 180px;
}
.counter {
text-align: center;
}

View File

@@ -0,0 +1,12 @@
<!--
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-23 10:12:09
* @LastEditors: OreoWang
* @LastEditTime: 2022-03-23 14:23:33
* @Description:
-->
<div>
<div id="default-app"></div>
<h1 id="text"></h1>
</div>

View File

@@ -0,0 +1,12 @@
<!--
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-23 10:12:09
* @LastEditors: OreoWang
* @LastEditTime: 2022-03-23 14:23:33
* @Description:
-->
<!-- <div> -->
<div id="tree_panel_app"></div>
<!-- <h1 id="text"></h1> -->
<!-- </div> -->

View File

@@ -0,0 +1,4 @@
<div>
<div id="app"></div>
<!-- <h1 id="text"></h1> -->
</div>

View File

@@ -0,0 +1,14 @@
<div>
<!-- <div class="counter">
<h2> {{counter}}</h2>
<ui-button class="blue"
@click="addition">+</ui-button>
<ui-button @click="subtraction">-</ui-button>
</div> -->
<div>
<ui-markdown>
{{content}}
</ui-markdown>
</div>
</div>

View File

@@ -0,0 +1,94 @@
<!--
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-04-12 10:26:27
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-12 18:37:17
* @Description:
-->
<div id="props-root">
<div class="settings" >
<div class="content">
<div class="wrap">
<div class="">
<ui-section expand="" :header="getEditingHeader()">
<ui-prop class="">
<div slot="label" class="row_item prop-label-content">
<ui-label tabindex="-1" value="Name" tooltip="Name of the variable"></ui-label>
<ui-icon v-if="isEditing" class="prop-icon" value="lock"></ui-icon>
</div>
<ui-input :readonly="isEditing" class="row_item" slot="content" :value="props.name" v-on:change="onChangeName">
</ui-input>
</ui-prop>
<ui-prop class="">
<div slot="label" class="row_item prop-label-content">
<ui-label tabindex="-1" value="Type" tooltip="Type of the variable"></ui-label>
<ui-icon v-if="isEditing" class="prop-icon" value="lock"></ui-icon>
</div>
<ui-select :readonly="isEditing" class="row_item" slot="content" v-on:change="onSelectType($event)" v-bind:value="props.type">
<template v-for="(ctype, ckey) in getBlackboardAllType()">
<option :value=ctype>{{ctype}}</option>
</template>
</ui-select>
</ui-prop>
<ui-prop class="">
<div slot="label" class="row_item">
<ui-label tabindex="-1" value="Description" tooltip="Description of the variable"></ui-label>
</div>
<ui-textarea class="row_item" slot="content" placeholder="Description of the variable" :value="props.tooltip" v-on:change="onChangeDescription">
</ui-textarea>
</ui-prop>
<div v-if="isEditing">
<ui-button class="btn-apply" @confirm="onApplyEditing()">apply</ui-button> <ui-button class="btn-cancel" @confirm="onCancelEditing()">cancel</ui-button>
</div>
<div v-else>
<ui-button class="btn-create" @confirm="onAddVariable()">create</ui-button>
</div>
<div class="line"></div>
</ui-section>
<ui-section class="section-header" expand="" header="Shared Variables">
<!-- <div class="blackboard-content"> -->
<template v-for="(item, key) in getAllVariable()">
<ui-prop class="">
<div slot="label" class="row_item">
<ui-label tabindex="-1" :value="item.name" :tooltip="getVariableTooltip(item)"></ui-label>
</div>
<div slot="content" class="prop-content">
<ui-input v-if="isTypeString(item.value)" class="row_item prop-mr2" v-on:change="onValueChange($event, key, item)" v-bind:value="item.value.default">
</ui-input>
<ui-num-input v-if="isTypeNumber(item.value)" class="row_item prop-mr2" slot="content" v-on:change="onValueChange($event, key, item)" v-bind:value="item.value.default">
</ui-num-input>
<ui-checkbox v-if="isTypeBoolean(item.value)" class="row_item prop-mr2" slot="content" v-on:change="onValueChange($event, key, item)" v-bind:value="item.value.default">
</ui-checkbox>
<ui-node v-if="isTypeNode(item.value)" class="row_item prop-mr2" slot="content" v-on:change="onNodeValueChange($event, key, item)" v-bind:value="getSharedNodeUUID(item.value)" type="cc.Node" droppable="cc.Node" typename="Node" tabindex="-1">
</ui-node>
<span v-if="isTypeBoolean(item.value)" class="prop-span"></span>
<!-- <div v-if="isTypeBoolean(item.value)">
</div> -->
<ui-button class="transparent prop-button" tooltip="Edit" tabindex="-1" @confirm="onEditVariable(item)">
<ui-icon class="prop-icon" value="edit"></ui-icon>
</ui-button>
<ui-button class="transparent prop-button" tooltip="Delete" tabindex="-1" @confirm="onDelVariable(item)">
<ui-icon class="prop-icon" value="del"></ui-icon>
</ui-button>
</div>
</ui-prop>
</template>
<!-- </div> -->
</ui-section>
</div>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,178 @@
<!--
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-23 10:12:09
* @LastEditors: OreoWang
* @LastEditTime: 2022-06-07 17:19:26
* @Description:
-->
<div id="props-root">
<div class="settings" >
<div class="content">
<div class="wrap">
<ui-section expand="" header="Inspector">
<ui-prop class="prop-script" v-if="!isRootNode()">
<div slot="label" class="row_item prop-label-content">
<ui-label tabindex="-1" value="Script" tooltip="Script"></ui-label>
<ui-icon class="prop-icon" value="lock"></ui-icon>
</div>
<ui-asset class="row_item" slot="content" v-bind:value="getScriptUUID(props.uuid)"
droppable="cc.Script" readonly tabindex="-1">
</ui-asset>
</ui-prop>
<ui-prop class="" v-if="!isRootNode()">
<div slot="label" class="row_item prop-label-content">
<ui-label tabindex="-1" value="Type" tooltip="Type"></ui-label>
<ui-icon class="prop-icon" value="lock"></ui-icon>
</div>
<ui-input class="row_item" slot="content" v-bind:value="props.group" :tooltip="props.group" readonly>
</ui-input>
</ui-prop>
<ui-prop class="" v-if="!isRootNode()">
<div slot="label" class="row_item prop-label-content">
<ui-label tabindex="-1" value="Component" tooltip="Component"></ui-label>
<ui-icon class="prop-icon" value="lock"></ui-icon>
</div>
<ui-input class="row_item" slot="content" v-bind:value="props.name" :tooltip="props.name" readonly>
</ui-input>
</ui-prop>
<ui-prop class="prop-script" v-if="isRootNode()">
<div slot="label" class="row_item prop-label-content">
<ui-label tabindex="-1" value="TargetNode" tooltip="Target Node"></ui-label>
<ui-icon class="prop-icon" value="lock"></ui-icon>
</div>
<!-- <ui-input class="row_item" slot="content" v-bind:value="props.name" :tooltip="props.name" readonly>
</ui-input> -->
<ui-node readonly class="row_item" slot="content" v-bind:value="getRootNodeUUID()" type="cc.Node" droppable="cc.Node" typename="Node" tabindex="-1">
</ui-node>
</ui-prop>
<ui-prop class="" v-if="!isRootNode()">
<div slot="label" class="row_item prop-label-content">
<ui-label tabindex="-1" value="Tag" tooltip="Tag in tree"></ui-label>
<!-- <ui-icon v-if="!isRootNode()" class="prop-icon" value="refresh"></ui-icon> -->
<ui-button v-if="!isRootNode()" class="transparent prop-button" tooltip="Refresh Tag" tabindex="-1" @confirm="onRefreshTag()">
<ui-icon class="prop-icon" value="refresh"></ui-icon>
</ui-button>
</div>
<ui-input class="row_item" slot="content" v-on:change="onChangeTag" v-bind:value="props.tag" :tooltip="props.tag" :readonly="isRootNode()">
</ui-input>
</ui-prop>
<ui-prop class="">
<div slot="label" class="row_item prop-label-content">
<ui-label tabindex="-1" value="Title" tooltip="Title"></ui-label>
<ui-icon v-if="isRootNode()" class="prop-icon" value="lock"></ui-icon>
</div>
<ui-input class="row_item" slot="content" v-on:change="onChangeTitle" v-bind:value="props.title" :tooltip="props.title" :readonly="isRootNode()">
</ui-input>
</ui-prop>
<div v-show="showProps()">
<div class="group-line"></div>
<div v-for="(value, key) in props.properties" :key="key">
<ui-prop class="" v-show="showOneProperty(key, value)">
<div slot="label" class="row_item prop-label-content">
<ui-label tabindex="-1" :value="key" :tooltip="getPropertyTooltip(key, value)"></ui-label>
<div v-if="isTypeBlackboard(value)">
<ui-icon class="prop-icon" value="edit" tooltip="Shared Variable"></ui-icon>
</div>
</div>
<div v-if="isTypeDynamic(value)" slot="content" class="prop=content">
<ui-input v-if="isDynamicTypeString(value)" class="row_item" slot="content" v-on:change="onValueChange($event, key, value)" v-bind:value="value.default">
</ui-input>
<ui-num-input v-if="isDynamicTypeNumber(value)" class="row_item" slot="content" v-on:change="onValueChange($event, key, value)" v-bind:value="value.default">
</ui-num-input>
<ui-checkbox v-if="isDynamicTypeBoolean(value)" class="row_item" slot="content" v-on:change="onValueChange($event, key, value)" v-bind:value="value.default">
</ui-checkbox>
<ui-node v-if="isDynamicTypeNode(value)" class="row_item" slot="content" v-on:change="onDynamicNodeValueChange($event, key, value)" v-bind:value="getDynamicNodeUUID(value)" type="cc.Node" droppable="cc.Node" typename="Node" tabindex="-1">
</ui-node>
</div>
<div v-else-if="isTypeEnum(value)" slot="content" class="prop=content">
<ui-select class="row_item" v-on:change="onEnumValueChange($event, key, value)" v-bind:value="value.default">
<option v-for="(cvalue, ckey) in getEnumVariableList(key, value)" :key="ckey" :value="cvalue">
{{ckey}}
</option>
</ui-select>
</div>
<div v-else-if="isTypeBlackboard(value)" slot="content" class="prop=content">
<ui-select class="row_item" v-on:change="onBlackboardValueChange($event, key, value)" v-bind:value="value.default">
<option v-for="(item, ckey) in getBlackboardVariableList(value)" :key="ckey" :value="item.name">
{{item.name}}
</option>
</ui-select>
</div>
<div v-else-if="isTypeVariable(value)" slot="content" class="prop=content">
<ui-select class="row_item" v-on:change="onSharedVariableChange($event, key, value)" v-bind:value="value.default">
<option v-for="(item, ckey) in getAllVariableList(value)" :key="ckey" :value="item.name">
{{item.name}}
</option>
</ui-select>
</div>
<div v-else slot="content">
<ui-input v-if="isTypeString(value)" class="row_item" slot="content" v-on:change="onValueChange($event, key, value)" v-bind:value="value.default">
</ui-input>
<ui-num-input v-if="isTypeNumber(value)" class="row_item" slot="content" v-on:change="onValueChange($event, key, value)" v-bind:value="value.default">
</ui-num-input>
<ui-checkbox v-if="isTypeBoolean(value)" class="row_item" slot="content" v-on:change="onValueChange($event, key, value)" v-bind:value="value.default">
</ui-checkbox>
<ui-node v-if="isTypeNode(value)" class="row_item" slot="content" v-on:change="onNodeValueChange($event, key, value)" v-bind:value="getPropertyNodeUUID(value)" type="cc.Node" droppable="cc.Node" typename="Node" tabindex="-1">
</ui-node>
</div>
</ui-prop>
</div>
</div>
</ui-section>
<ui-section expand="" header="Delegate" v-if="!isRootNode()&&showEvent()" class="section-mt10">
<div v-for="(event, key) in props.events" :key="key">
<ui-section expand="" :header="key" class="config section-mt10">
<div class="">
<div class="">
<ui-prop class="prop-node">
<div slot="label" class="row_item">
<ui-label tabindex="-1" value="Target" tooltip="Target"></ui-label>
</div>
<ui-node class="row_item" slot="content" v-bind:value="getDelegateNodeUUID(event.node)" v-on:change="onDelegateNodeChange($event, key)"
droppable="cc.Node" :tooltip="event.node.name" type="cc.Node" typename="Node" tabindex="-1">
</ui-node>
</ui-prop>
<ui-prop class="">
<div slot="label" class="row_item">
<ui-label tabindex="-1" value="Component" tooltip="Component"></ui-label>
</div>
<ui-select class="row_item" slot="content" v-bind:value="event.component.uuid" v-on:change="onComponentChange($event, key)"
:tooltip="event.component.name">
<option v-for="(component, ckey) in eventData[key].components" :key="ckey" :value="component.uuid">
{{component.name}}
</option>
</ui-select>
</ui-prop>
<ui-prop class="">
<div slot="label" class="row_item">
<ui-label tabindex="-1" value="Method" tooltip="Method"></ui-label>
</div>
<ui-select class="row_item" slot="content" v-bind:value="event.method" v-on:change="onMethodChange($event, key)"
:tooltip="event.method">
<option v-for="(method, key) in eventData[key].methods" :key="method" :value="method">
{{method}}
</option>
</ui-select>
</ui-prop>
</div>
<ui-prop class="">
<div slot="label" class="row_item">
<ui-label tabindex="-1" value="Data" tooltip="Arguments(string)"></ui-label>
</div>
<ui-input class="row_item" slot="content" v-on:change="onDataChange($event, key)" v-bind:value="event.data">
</ui-input>
</ui-prop>
</div>
</ui-section>
</div>
</ui-section>
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,53 @@
<!--
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-05-23 09:39:48
* @LastEditors: OreoWang
* @LastEditTime: 2022-06-06 15:48:17
* @Description:
-->
<div id="tree_panel">
<div class="div_mgt8">
<!-- <ui-button class="yellow" @click="onSyncAllData">
同步
</ui-button> -->
</div>
<div class="div_mg8">
<ui-label class="title" :value="getVersion()">
</ui-label>
<br>
<ui-label class="" value="数据版本为 红色 表示版本不兼容,需要手动更新">
</ui-label>
</div>
<div class="div_line">
</div>
<div>
<div v-for="(item, key) in list" :key="key">
<ui-prop class="prop-script">
<ui-asset class="label_asset" slot="label" v-bind:value="item.uuid" droppable="cc.JsonAsset" readonly>
</ui-asset>
<ui-input class="" slot="content" v-bind:value="item.url" readonly>
</ui-input>
</ui-prop>
<div class="div_mg10">
<ui-label value="数据版本">
</ui-label>
<ui-label :class="getVersionColor(item)" v-bind:value="item.version">
</ui-label>
<!-- <ui-label value="待更新">
</ui-label> -->
</div>
<div class="div_line">
</div>
</div>
</div>
</div>

View File

@@ -0,0 +1,14 @@
<div>
<!-- <div class="counter">
<h2> {{counter}}</h2>
<ui-button class="blue"
@click="addition">+</ui-button>
<ui-button @click="subtraction">-</ui-button>
</div> -->
<div>
<ui-markdown>
{{content}}
</ui-markdown>
</div>
</div>

View File

@@ -0,0 +1,12 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "20169a05-4939-4f5c-8cc5-cb46d02353a2",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,16 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-04-07 14:12:09
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-25 09:47:07
* @Description: 用于在 Inspector 中显示编辑按钮
*/
import { _decorator, Component } from "cc";
const {ccclass, disallowMultiple} = _decorator;
@ccclass("BehaviorButton")
@disallowMultiple
export default class BehaviorButton extends Component {
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "57329531-3fd5-4e01-af0c-7224cf8483a6",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,71 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-04-07 14:12:09
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-26 10:51:23
* @Description: 行为树日志输出选项
*/
import { _decorator, Component } from "cc";
const { ccclass, property, requireComponent, disallowMultiple } = _decorator;
import { IBehaviorLogOptions } from "../core/behavior/behavior-tree-interface";
import BehaviorButton from "./BehaviorButton";
export const DefaultLogOptions: IBehaviorLogOptions = {
logAbort: true,
logInterrupt: true,
logExecute: true,
logUpdate: false,
logEnter: false,
logExit: false,
logEnable: false,
logDisable: false,
logLoad: false,
logDestroy: false,
}
@ccclass("BehaviorLogOptions")
@requireComponent(BehaviorButton)
@disallowMultiple
export default class BehaviorLogOptions extends Component implements IBehaviorLogOptions {
@property({
tooltip: "当任务被中止时是否打印日志",
})
logAbort: boolean = true;
@property({
tooltip: "当中断产生时是否打印日志",
})
logInterrupt: boolean = true;
@property
logExecute: boolean = true;
@property
logUpdate: boolean = false;
@property
logLoad: boolean = false;
@property
logDestroy: boolean = false;
@property
logEnter: boolean = false;
@property
logExit: boolean = false;
@property
logEnable: boolean = false;
@property
logDisable: boolean = false;
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "0047be34-4c09-4525-a687-e428f9a9b00f",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,190 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:50:54
* @LastEditors: OreoWang
* @LastEditTime: 2022-07-15 09:30:18
* @Description:
*/
import { game, _decorator } from "cc";
import * as core from "../core/main";
import { BehaviorStatus } from "../core/main";
const logger = console;
export default class BehaviorManager {
/** 运行 */
running: Set<core.IBehaviorTree> = new Set();
/** 挂起 */
suspend: Set<core.IBehaviorTree> = new Set();
/**
* 行为树统一帧率
* 默认为 cc.game.frameRate
*/
private frameRate = 0;
/** 期望帧率对应的每帧时间(以 s 为单位) */
private frameTime = 0;
/** 每帧时间增量 */
private deltaTime = 0;
// /** 行为树持续时间(是每帧时间增量叠加后的时间总和) */
// private duration = 0;
// /** 行为树 tick 次数 */
// private ticks = 0;
protected static _instance: BehaviorManager = null;
static getInstance() {
if (!BehaviorManager._instance) {
BehaviorManager._instance = new BehaviorManager();
}
return BehaviorManager._instance;
}
static deleteInstance() {
BehaviorManager._instance = null;
}
constructor() {
// this.duration = 0
// this.ticks = 0
this.setFrameRate(Number(game.frameRate));
}
getFrameRate(){
return this.frameRate;
}
/**
* 设置行为树执行帧率但真正的FPS还取决于 cc.game.frameRate
* 注意:行为树的帧率不会比 cc.game.frameRate 大
* @param frameRate
*/
setFrameRate(frameRate: number){
const gRate = Number(game.frameRate);
if(frameRate <= 0 || frameRate > gRate){
logger.warn("Invalid frame rate!");
frameRate = gRate;
}
if(this.frameRate != frameRate){
this.frameRate = frameRate;
this.frameTime = (1000 / this.frameRate) / 1000 - 0.0001;
this.running.forEach(context=>{
if(context.getFrameRate() > this.frameRate){
context.setFrameRate(this.frameRate);
}
})
this.suspend.forEach(context => {
if(context.getFrameRate() > this.frameRate){
context.setFrameRate(this.frameRate);
}
})
}
}
/**
* 将行为树添加到 running 集合中
* @param context
*/
runBehavior(context: core.IBehaviorTree) {
this.resumeBehavior(context);
}
/**
* 将行为树添加到集合中
* @description context.startWhenEnabled 为 true 时,行为树添加到 running 集合,否则添加到 suspend 集合
* @param context
*/
addBehavior(context) {
if (context.startWhenEnabled) {
this.resumeBehavior(context);
}
else {
this.pauseBehavior(context);
}
}
removeBehavior(context: core.IBehaviorTree) {
if (this.running.has(context)) {
this.running.delete(context);
}
if (this.suspend.has(context)) {
this.suspend.delete(context);
}
}
pauseBehavior(context: core.IBehaviorTree) {
if (!this.suspend.has(context)) {
context.onPause();
this.suspend.add(context);
}
if (this.running.has(context)) {
this.running.delete(context);
}
}
resumeBehavior(context: core.IBehaviorTree) {
if (!this.running.has(context)) {
context.onResume();
this.running.add(context);
}
if (this.suspend.has(context)) {
this.suspend.delete(context);
}
}
stopBehavior(context: core.IBehaviorTree) {
if (this.running.has(context)) {
context.onStop();
this.running.delete(context);
}
if (!this.suspend.has(context)) {
this.suspend.add(context);
}
}
/**
* 更新状态
* @param {*} delta 上一次tick时间间隔
*/
tick(delta: number) {
// this.duration += delta
// this.ticks += 1
this.running.forEach(context => {
const status = context.onTick(delta);
if (status != BehaviorStatus.Running) {
if (context.restartWhenComplete) {
context.onRestart();
}
else {
context.onFinished();
this.stopBehavior(context);
}
}
})
}
update(delta: number) {
this.deltaTime += delta;
if(this.deltaTime < this.frameTime){
return;
}
this.tick(delta);
this.deltaTime -= this.frameTime;
}
onEnable() {
this.suspend.forEach(context => {
if (context.isSuspended) {
this.resumeBehavior(context);
}
})
}
onDisable() {
this.running.forEach(context => {
if (context.pauseWhenDisabled) {
this.pauseBehavior(context);
}
})
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "aadd8789-6a9d-43da-aa6a-08a96c22acea",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,356 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-04-07 14:12:09
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-26 10:51:23
* @Description:
*/
import { _decorator, Component, JsonAsset } from "cc";
import { DEV } from "cc/env";
const { ccclass, property, requireComponent, disallowMultiple } = _decorator;
import * as btNode from "../node/main";
import * as btCore from "../core/main";
import { BehaviorEntity, IBehaviorTree, Blackboard, logger, BehaviorStatus, TTreeAsset, BehaviorNode, BehaviorTask, BehaviorEventTarget, TBehaviorTreeEventInterface } from "../core/main";
import BehaviorLogOptions, { DefaultLogOptions } from "./BehaviorLogOptions";
import BehaviorManager from "./BehaviorManager";
import { game } from "cc";
@ccclass("BehaviorTree")
// @requireComponent(BehaviorButton)
@requireComponent(BehaviorLogOptions)
@disallowMultiple
export default class BehaviorTree extends Component implements IBehaviorTree {
@property({
type: JsonAsset,
tooltip: "绑定行为树编辑器数据资源"
})
jsonAsset: JsonAsset = null;
@property({
tooltip: `设置当前行为树执行帧率,为 0 表示与 BehaviorManager.frameRate 保持一致。
如需统一设置帧率,可以使用 BehaviorManager.getInstance().setFrameRate(rate)。
注意:行为树的帧率不会比 cc.game.frameRate 大`,
min: 0,
step: 1,
})
frameRate = 0;
@property({
tooltip: "节点激活时开始运行"
})
startWhenEnabled = true;
@property({
tooltip: "节点禁用时暂停运行"
})
pauseWhenDisabled = false;
@property({
tooltip: "当一次行为树全部结束时,重新开始执行该行为树"
})
restartWhenComplete = false;
@property({
tooltip: "当重新开始执行行为树时,重置各节点数据"
})
resetValuesOnRestart = false;
@property({
tooltip: "当行为树状态变动时输出日志"
})
logTaskChanges = false;
/**
* 行为树事件委托对象
* 事件类型详见: IBehaviorTreeEventInterface
*/
delegate: BehaviorEventTarget<TBehaviorTreeEventInterface> = new BehaviorEventTarget<TBehaviorTreeEventInterface>();
/** 行为树执行日志粒度控制 */
logOptions: BehaviorLogOptions = null;
/** 行为树持续时间(是每帧时间增量叠加后的时间总和) */
duration = 0;
/** 行为树 tick 总次数 */
ticks = 0;
tickLoggers: Array<string> = [];
lastLoggers: Array<string> = [];
/** 所有节点(包括组合节点、任务节点、装饰器等所有节点) */
allNodes: Array<BehaviorNode> = [];
/** 所有任务节点(key为该节点在行为树编辑器中对应的序号) */
allTasks: Array<BehaviorTask> = [];
/** 行为树使用的黑板变量 */
blackboard: Blackboard = null;
/** 行为树当前状态 */
status: BehaviorStatus = BehaviorStatus.None;
/** 行为树是否已挂起 */
isSuspended: boolean = false;
/** 行为树是否已执行结束 */
isCompleted: boolean = false;
protected _inited = false;
// protected _utils: BehaviorTreeUtils = null;
protected _root: BehaviorEntity = null;
protected get _manager() {
return BehaviorManager.getInstance();
}
onLoad() {
if (!this.jsonAsset?.json) return;
this.reuse();
}
onDestroy() {
this.unuse();
}
unuse(){
if(!this._inited){
return;
}
this._inited = false;
this.status = BehaviorStatus.None;
this.duration = 0;
this.ticks = 0;
this.allNodes.length = 0;
this.allTasks.length = 0;
this.tickLoggers.length = 0;
this.lastLoggers.length = 0;
this.isSuspended = false;
this.isCompleted = false;
if (this._root) {
this._root.destroy();
this._root = null;
}
if (this.blackboard) {
this.blackboard.destroy();
this.blackboard = null;
}
this._manager.removeBehavior(this);
}
reuse(){
this.loadJsonAsset(this.jsonAsset);
}
loadJsonAsset(jsonAsset: JsonAsset){
if(!jsonAsset || !jsonAsset.json) return;
if(this._inited) return;
this._inited = true;
this.setFrameRate(this.frameRate);
this.jsonAsset = jsonAsset;
this.logOptions = this.getComponent(BehaviorLogOptions);
if(!this.logOptions){
this.logOptions = this.addComponent(BehaviorLogOptions);
for (const key in DefaultLogOptions) {
this.logOptions[key] = !!DefaultLogOptions[key];
}
}
const jsonObect = jsonAsset.json;
const json: TTreeAsset = jsonObect as TTreeAsset;
this.blackboard = new Blackboard(this, json.blackboard);
if (this.loadTree(json)) {
this._manager.addBehavior(this);
}
}
private loadTree(tree: TTreeAsset) {
if (!tree?.root) {
logger.error('load failed -- tree is invalid')
return false;
}
this._root = null;
this.allNodes.length = 0;
this.allTasks.length = 0;
this.tickLoggers.length = 0;
this.lastLoggers.length = 0;
let successs = false;
this.delegate.emit("onDeserializeBefore");
// 创建根节点
const options = tree.root.config?.label || {} as btCore.ILabelConfig;
if (options.uuid) {
const instance: BehaviorEntity = btCore.deserializeNode(null, tree.root, this);
if (instance) {
this._root = instance
successs = true;
}
else {
logger.error("Can't find class by uuid: ", options.uuid);
}
}
this.delegate.emit("onDeserializeAfter");
return successs;
}
getFrameRate(){
return this.frameRate;
}
/**
* 设置当前行为树执行帧率但真正的FPS还取决于 BehaviorManager.frameRate 和 cc.game.frameRate
* 如需统一设置帧率,可以使用 BehaviorManager.getInstance().setFrameRate(rate)
* 注意:行为树的帧率不会比 cc.game.frameRate 大
* @param frameRate
*/
setFrameRate(frameRate: number){
const mRate = this._manager.getFrameRate();
if(frameRate <= 0 || frameRate > mRate){
if(frameRate != 0){
logger.warn(`Invalid frame rate! tree.frameRate=${frameRate}, manage.frameRate=${mRate}, game.frameRate=${game.frameRate}`);
}
frameRate = mRate;
}
this.frameRate = frameRate;
this.frameTime = (1000 / this.frameRate) / 1000 - 0.0001;
}
/** 期望帧率对应的每帧时间(以 s 为单位) */
private frameTime = 0;
/**
* 行为树反序列化每个节点回调
* @param node
*/
onDeserialize(node: BehaviorNode) {
this.allNodes.push(node);
if(node instanceof btNode.Task){
/** 开发环境下,检查任务节点的 tag 是否有重复。一般来说tag 都是唯一的 */
if(DEV){
const {tag, order} = node.nodeConfig;
if(!!tag){
let temp = this.getTask(tag);
if(temp){
console.warn(`The node has duplicate tags. tag:${tag}, orders:[${temp.nodeConfig.order}, ${order}]`)
}
}
}
this.allTasks.push(node);
}
this.delegate.emit("onDeserialize", node);
}
/**
* 行为树根节点
* @returns
*/
getRoot(): btCore.BehaviorEntity | null{
return this._root;
}
/**
* 根据指定的 tag 获取某个任务
* @param tag string
* @returns
*/
getTask(tag: string): btNode.Task | null{
let node = this.allTasks.find(v=>v.nodeConfig.tag == tag);
return node;
}
/**
* 根据任务在行为树中的序号获取某个任务
* @param order number
* @returns
*/
getTaskByOrder(order: number): btNode.Task | null{
let node = this.allTasks.find(v=>v.nodeConfig.order == order);
return node;
}
/** 行为树组件被附加到的 cc.Node 节点 */
getTargetRoot() {
return this.node;
}
/**
* 根据子节点路径获取 cc.Node 节点
* @param path
* @returns
*/
getTargetByPath(path: string){
return btCore.getTargetByPath(this.node, path);
}
/** 某个类型的 log 是否启用 */
isLogEnabled(key: btCore.TBehaviorLogKey): boolean {
return this.logOptions[key];
}
private _isLogTaskChanged: boolean = false;
onHandleTreeLog(msg: string){
if(this.logTaskChanges){
if(!this._isLogTaskChanged){
let length = this.tickLoggers.length;
if(this.lastLoggers.length > length){
let temp = this.lastLoggers[length];
if(temp != msg){
this._isLogTaskChanged = true;
}
}
else{
this._isLogTaskChanged = true;
}
}
this.tickLoggers.push(msg);
}
}
onTick(delta: number) {
if (!this._root) {
logger.error('tick failed -- root is null')
return BehaviorStatus.None;
}
this.duration += delta;
this.ticks += 1;
this.tickLoggers.length = 0;
this._isLogTaskChanged = false;
this.status = this._root.execute();
if(this._isLogTaskChanged){
let msg = `[ BehaviorTree - <${this._root.nodeTitle}> onTick(${this.ticks}) : status = ${BehaviorStatus[this.status]} ]\n` + this.tickLoggers.join("\n");
logger.log(msg);
this.lastLoggers = this.tickLoggers;
this.tickLoggers = [];
}
// this.deltaTime -= this.frameTime;
return this.status;
}
onFinished() {
this.isCompleted = true;
}
onRestart() {
this.isCompleted = false;
if (this.resetValuesOnRestart) {
this._root.reset();
}
}
onPause() {
this.isSuspended = true;
};
onResume() {
this.isSuspended = false;
};
onStop() {
this.isSuspended = false;
this.isCompleted = false;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "e021fcd1-5fdd-4265-b7e2-b1677d99aa04",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "b984fcf4-64af-453f-b850-c2a4a8c63935",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "1ccd7aaf-8fa6-4e7d-9f9f-f1f3efa54f09",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "896d1aa0-bf42-4a94-a570-b3d697ce5c90",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.1.0",
"importer": "directory",
"imported": true,
"uuid": "9a75f94e-4879-4193-bf1f-068858fa88e6",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "b69ca0bc-cd0a-4eb4-a933-16ab1e9e100c",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "a8421e4d-2f1b-4682-abae-ac35a211c620",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,107 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:43:14
* @LastEditors: OreoWang
* @LastEditTime: 2022-03-22 18:11:37
* @Description:
*/
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:59:27
* @LastEditors: OreoWang
* @LastEditTime: 2022-03-22 14:41:21
* @Description:
*/
import { __private } from "cc";
// import * as _ from "../index";
declare module "cc" {
namespace Node {
namespace Behavior {
/**
* @en Declare a standard class as a CCClass, please refer to the [document](https://docs.cocos.com/creator3d/manual/zh/scripting/ccclass.html)
* @zh 将标准写法的类声明为 CC 类,具体用法请参阅[类型定义](https://docs.cocos.com/creator3d/manual/zh/scripting/ccclass.html)。
* @param name - The class name used for serialization.
* @example
* ```ts
* import { _decorator, Component } from 'cc';
* const {ccclass} = _decorator;
*
* // define a CCClass, omit the name
* @ccclass
* class NewScript extends Component {
* // ...
* }
*
* // define a CCClass with a name
* @ccclass('LoginData')
* class LoginData {
* // ...
* }
* ```
*/
export const btclass: ((name?: string) => ClassDecorator) & ClassDecorator;
/**
* @en Declare as a CCClass property with options
* @zh 声明属性为 CCClass 属性。
* @param options property options
*/
export function property(options?: __private.cocos_core_data_decorators_property_IPropertyOptions): __private.cocos_core_data_decorators_utils_LegacyPropertyDecorator;
/**
* @en Declare as a CCClass property with the property type
* @zh 标注属性为 cc 属性。<br/>
* 等价于`@property({type})`。
* @param type A {{ccclass}} type or a {{ValueType}}
*/
export function property(type: __private.cocos_core_data_decorators_property_PropertyType): __private.cocos_core_data_decorators_utils_LegacyPropertyDecorator;
/**
* @en Declare as a CCClass property
* @zh 标注属性为 cc 属性。<br/>
* 等价于`@property()`。
*/
export function property(...args: Parameters<__private.cocos_core_data_decorators_utils_LegacyPropertyDecorator>): void;
export enum BehaviorStatus {
Idle = -1,
Failure = 0,
Success = 1,
Running = 2
}
type ValueOf<T> = T[keyof T];
type TBehaviorStatus = ValueOf<typeof BehaviorStatus>;
export class Manager {
constructor (data?: any);
load(tree);
tick(delta: number);
reset();
}
export class BehaviorNode {
constructor (parent, config, context);
update(delta: number): TBehaviorStatus
}
export class Decorator extends BehaviorNode {
update(delta: number): TBehaviorStatus
}
export class Service extends BehaviorNode {
update(delta: number): TBehaviorStatus
}
export class Task extends BehaviorNode {
update(delta: number): TBehaviorStatus
}
export class Composite extends BehaviorNode {
update(delta: number): TBehaviorStatus
}
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "94a8a794-69d1-43f7-9645-587339155ebb",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,12 @@
{
"ver": "1.2.0",
"importer": "directory",
"imported": true,
"uuid": "45a0138c-34cd-4cda-9adc-72a79ae5b000",
"files": [],
"subMetas": {},
"userData": {
"compressionType": {},
"isRemoteBundle": {}
}
}

View File

@@ -0,0 +1,56 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:47:14
* @LastEditors: OreoWang
* @LastEditTime: 2022-07-18 11:55:37
* @Description: 组合节点
* https://docs.unrealengine.com/4.26/zh-CN/InteractiveExperiences/ArtificialIntelligence/BehaviorTrees/BehaviorTreeNodeReference/BehaviorTreeNodeReferenceComposites/
*/
import { BehaviorEntity } from "./behavior-node-entity";
import { BehaviorStatus } from "./behavior-status";
export class BehaviorComposite extends BehaviorEntity {
isComposite = true;
lastRunning = -1;
constructor(parent, config, context) {
super(parent, config, context)
this.isComposite = true
this.lastRunning = -1 // 上一次running的索引
}
public getLogSymbol(){
return "comp --"
}
abort(){
if(this.lastRunning != -1){
let child = this.children[this.lastRunning];
this.lastRunning = -1;
if(child){
child.abort();
}
}
return super.abort();
}
reset() {
super.reset()
this.lastRunning = -1;
}
disable(){
if(this.lastRunning != -1){
let child = this.children[this.lastRunning];
if(child){
child.status = this.status;
child.disable();
}
}
super.disable();
this.lastRunning = -1;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "fc7c1aca-767a-4f0e-b044-c68525175231",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,20 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:47:14
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-22 21:02:40
* @Description: 条件装饰器
* https://docs.unrealengine.com/4.26/zh-CN/InteractiveExperiences/ArtificialIntelligence/BehaviorTrees/BehaviorTreeNodeReference/BehaviorTreeNodeReferenceDecorators/
*/
import { BehaviorDecorator } from "./behavior-decorator";
import { BehaviorStatus } from "./behavior-status"
export class BehaviorConditional extends BehaviorDecorator{
isCondition = true;
public getLogSymbol(){
return "cond &?"
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "c3b96b68-f4a2-4842-9387-54e37444820a",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,20 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:47:14
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-22 12:56:35
* @Description: 装饰器
* https://docs.unrealengine.com/4.26/zh-CN/InteractiveExperiences/ArtificialIntelligence/BehaviorTrees/BehaviorTreeNodeReference/BehaviorTreeNodeReferenceDecorators/
*/
import { BehaviorElement } from "./behavior-node-element";
import { BehaviorStatus } from "./behavior-status"
export class BehaviorDecorator extends BehaviorElement {
isCondition = false;
public getLogSymbol(){
return "deco &@"
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "b1634f8a-3e56-422b-9be3-18fba853fb67",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,73 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-04-08 11:09:25
* @LastEditors: OreoWang
* @LastEditTime: 2022-05-17 14:44:54
* @Description:
*/
import { utils } from "../utils/utils";
import { IBehaviorNodeInterface } from "./behavior-node-interface";
import { BehaviorStatus } from "./behavior-status";
export function CloneEventOption(){
return utils.clone(BehaviorEventOption);
}
export const BehaviorEventOption = {
node: {
// uuid: '',
name: '',
path: '',
},
component: {
uuid: '',
name: '',
},
method: '',
data: '',
}
export type TBehaviorEventOption = typeof BehaviorEventOption;
export type AnyFunction = (...args: any[]) => any;
export type TBehaviorEventRecord<T> = {
[key in keyof T]: T[key]
}
export type TBehaviorEventInterface = Record<string, AnyFunction>;
export interface IBehaviorTreeEventInterface {
onDeserializeBefore: () => void;
onDeserializeAfter: () => void;
onDeserialize: (node: IBehaviorNodeInterface) => void;
}
export type TBehaviorTreeEventInterface = TBehaviorEventRecord<IBehaviorTreeEventInterface>;
export interface IBehaviorNodeEventInterface {
onEnter: (node: IBehaviorNodeInterface) => void;
onExit: (node: IBehaviorNodeInterface) => void;
onEnable: (node: IBehaviorNodeInterface) => void;
onDisable: (node: IBehaviorNodeInterface) => void;
onUpdate: (node: IBehaviorNodeInterface, status: BehaviorStatus) => BehaviorStatus;
}
export type TBehaviorNodeEventInterface = TBehaviorEventRecord<IBehaviorNodeEventInterface>;
export type TDelegateEvents = keyof IBehaviorNodeEventInterface;
export type TArrayDelegateEvents = Array<TDelegateEvents>;
export type TBehaviorEvents = {
[key in TDelegateEvents]?: TBehaviorEventOption
}
export interface IBehaviorEventListener<T extends TBehaviorEventInterface> {
on<Key extends keyof T>(key: Key, callback: T[Key], target?: unknown, once?: boolean): AnyFunction;
once<Key extends keyof T>(key: Key, callback: T[Key], target?: unknown): AnyFunction;
off<Key extends keyof T> (key: Key, callback?: AnyFunction, target?: any): void;
targetOff(typeOrTarget: any): void;
emit<Key extends keyof T>(key: Key, ...params: Parameters<T[Key]>): ReturnType<T[Key]>;
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "87489bb0-ed6c-4858-bcd0-8d2df16c49f3",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,88 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-04-08 11:09:25
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-21 17:46:56
* @Description:
*/
import { logger } from "../utils/logger";
import { TBehaviorEventOption, TBehaviorEvents, TBehaviorNodeEventInterface } from "./behavior-event-declaration";
import { BehaviorEventHandler } from "./behavior-event-handler";
import { BehaviorEventTarget } from "./behavior-event-target";
import { IBehaviorNodeInterface } from "./behavior-node-interface";
import { BehaviorStatus } from "./behavior-status";
import { IBehaviorTree } from "./behavior-tree-interface";
export class BehaviorEventDelegate extends BehaviorEventTarget<TBehaviorNodeEventInterface>{
protected _btNode: IBehaviorNodeInterface = null;
protected _events: TBehaviorEvents = null;
protected _context: IBehaviorTree = null;
private _onEnterHandler: BehaviorEventHandler = null;
private _onExitHandler: BehaviorEventHandler = null;
private _onEnableHandler: BehaviorEventHandler = null;
private _onDisableHandler: BehaviorEventHandler = null;
private _onUpdateHandler: BehaviorEventHandler = null;
constructor(btNode: IBehaviorNodeInterface, events: TBehaviorEvents, context: IBehaviorTree){
super();
if(!btNode || !events || !context) return;
this._btNode = btNode;
this._events = events;
this._context = context;
this._onEnterHandler = this.createHandler(events.onEnter);
this._onExitHandler = this.createHandler(events.onExit);
this._onUpdateHandler = this.createHandler(events.onUpdate);
this._onEnableHandler = this.createHandler(events.onEnable);
this._onDisableHandler = this.createHandler(events.onDisable);
}
protected createHandler(event: TBehaviorEventOption){
if(!event || !event.node?.path) return null;
let target = this._context.getTargetByPath(event.node.path);
if(!target){
logger.warn("getTargetByPath error: path =", event.node.path);
return null;
}
let component = target.getComponent(event.component.name);
if(!component){
logger.warn("cann't find component by name = " + event.component.name);
return null;
}
let handler = new BehaviorEventHandler();
handler.target = target;
handler.component = event.component.name;
handler.handler = event.method;
handler.customEventData = event.data;
return handler;
}
onEnter(){
this._onEnterHandler?.emit([this._btNode]);
this.emit("onEnter", this._btNode);
}
onEnable(){
this._onEnableHandler?.emit([this._btNode]);
this.emit("onEnable", this._btNode);
}
onUpdate(status: BehaviorStatus): BehaviorStatus{
if(this._onUpdateHandler){
status = this._onUpdateHandler.invoke(this._btNode, status);
}
status = this.emit("onUpdate", this._btNode, status);
return status;
}
onDisable(){
this._onDisableHandler?.emit([this._btNode]);
this.emit("onDisable", this._btNode);
}
onExit(){
this._onExitHandler?.emit([this._btNode]);
this.emit("onExit", this._btNode);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "350f3e0b-8ce3-447b-806c-8774edb942f4",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,45 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-04-08 11:09:25
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-21 17:47:27
* @Description:
*/
import { Node, EventHandler, isValid, js } from "cc";
import { logger } from "../utils/logger";
import { BehaviorStatus } from "./behavior-status";
export class BehaviorEventHandler extends EventHandler{
invoke(...params: any[]): BehaviorStatus{
const target = this.target;
if (!isValid(target)) { return; }
//@ts-ignore
this._genCompIdIfNeeded();
const compType: any = js._getClassById(this._componentId);
if(!compType){
logger.warn("invalid component type!");
return;
}
const comp = target!.getComponent(compType);
if (!isValid(comp)) {
logger.warn("invalid component type!");
return;
}
const handler = comp![this.handler];
if (typeof (handler) !== 'function') { return; }
if (this.customEventData != null && this.customEventData !== '') {
params = params.slice();
params.push(this.customEventData);
}
let res: BehaviorStatus = handler.apply(comp, params);
return res;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "8944dcea-05e3-4d6b-b6d2-6e695b0fc717",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,68 @@
import { EventTarget } from "cc";
import { AnyFunction, IBehaviorEventListener, TBehaviorEventInterface } from "./behavior-event-declaration";
type CallbackList = any;
export class BehaviorEventTarget<T extends TBehaviorEventInterface> implements IBehaviorEventListener<T> {
protected eventTarget = new EventTarget();
on<Key extends keyof T>(key: Key, callback: T[Key], target?: unknown, once?: boolean): AnyFunction{
return this.eventTarget.on(`${key}`, callback, target, once);
}
once<Key extends keyof T>(key: Key, callback: T[Key], target?: unknown): AnyFunction {
return this.eventTarget.once(`${key}`, callback, target);
}
off<Key extends keyof T> (key: Key, callback?: AnyFunction, target?: any): void {
this.eventTarget.off(`${key}`, callback, target);
}
targetOff (typeOrTarget: any): void {
this.eventTarget.targetOff(typeOrTarget);
}
emit<Key extends keyof T>(key: Key, ...params: Parameters<T[Key]>): ReturnType<T[Key]>{
//@ts-ignore
const list: CallbackList = this.eventTarget._callbackTable && this.eventTarget._callbackTable[key]!;
let arg0 = params[0];
let arg1 = params[1];
if (list) {
const rootInvoker = !list.isInvoking;
list.isInvoking = true;
const infos = list.callbackInfos;
for (let i = 0, len = infos.length; i < len; ++i) {
const info = infos[i];
if (info) {
const callback = info.callback;
const target = info.target;
// Pre off once callbacks to avoid influence on logic in callback
if (info.once) {
this.eventTarget.off(`${key}`, callback, target);
}
// Lazy check validity of callback target,
// if target is CCObject and is no longer valid, then remove the callback info directly
if (!info.check()) {
this.eventTarget.off(`${key}`, callback, target);
} else if (target) {
let result = callback.call(target, arg0, arg1);
if(typeof arg1 != "undefined"){
arg1 = result;
}
} else {
let result = callback(arg0, arg1);
if(typeof arg1 != "undefined"){
arg1 = result;
}
}
}
}
if (rootInvoker) {
list.isInvoking = false;
if (list.containCanceled) {
list.purgeCanceled();
}
}
}
return arg1 as ReturnType<T[Key]>;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "321f5098-933f-4df8-82c0-d6630ea4e9de",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,67 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:47:14
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-19 14:52:02
* @Description: 节点附加元素。元素只能附加到 entity 节点上。
*/
import { BehaviorNode } from "./behavior-node"
import { BehaviorStatus } from "./behavior-status"
import { IElementConfig, IElementInfo, INodeInfo } from "./behavior-node-interface";
import { BehaviorEntity } from "./behavior-node-entity";
import { IBehaviorTree } from "./behavior-tree-interface";
export class BehaviorElement extends BehaviorNode {
/** element(附属节点) 元素的拥有者 */
owner: BehaviorEntity = null;
isCondition = false;
isInterrupter = false;
get parent(){
return this._parent as BehaviorEntity;
};
get nodeInfo() {
return this._nodeInfo as IElementInfo;
}
get nodeConfig() {
return this._nodeConfig as IElementConfig;
}
constructor(parent: BehaviorEntity, nodeInfo: INodeInfo, context: IBehaviorTree) {
super(parent, nodeInfo, context);
this._parent = parent.parent;
this.owner = parent;
}
public getLogSymbol(){
return "elem &-"
}
execute(status: BehaviorStatus) {
status = this.update(status);
this.status = status = super.execute(status);
return status;
}
executeDecorator(status: BehaviorStatus){
if(status == BehaviorStatus.None){
//装饰器默认都返回 Failure ,需要 execute 处理
status = BehaviorStatus.Failure;
}
this.enter();
this.enable();
status = this.execute(status);
this.disable();
this.exit();
return status;
}
executeInterrupt(parent: BehaviorEntity, child: BehaviorEntity): BehaviorStatus{
return BehaviorStatus.Failure;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "bfa1f9c5-63fa-49d0-b812-f8945a7403d6",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,293 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:47:14
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-26 17:10:32
* @Description: 独立子节点,可直接添加到节点树上。 相对 element 元素,元素只能附加到 entity 上。
*/
import { BehaviorNode } from "./behavior-node";
import { BehaviorStatus } from "./behavior-status";
import { deserializeNode } from "./behavior-tree-utils";
import { logger } from "../utils/logger";
import { IEntityInfo, ILabelConfig, INodeInfo } from "./behavior-node-interface";
import { IBehaviorTree } from "./behavior-tree-interface";
import { BehaviorElement } from "./behavior-node-element";
import { BehaviorDecorator } from "./behavior-decorator";
import { BehaviorService } from "./behavior-service";
export class BehaviorEntity extends BehaviorNode {
get parent(): BehaviorEntity{
return this._parent as BehaviorEntity;
};
get nodeInfo() {
return this._nodeInfo as IEntityInfo;
}
get nodeConfig() {
return this._nodeConfig as ILabelConfig;
}
interrupters: Set<BehaviorDecorator> = new Set();
decorators: BehaviorDecorator[] = [];
services: BehaviorService[] = [];
children: BehaviorEntity[] = [];
constructor(parent: BehaviorEntity, nodeInfo: INodeInfo, context: IBehaviorTree) {
super(parent, nodeInfo, context);
}
public getLogSymbol(){
return "enti *-"
}
setLogEnabled(enabled: boolean, withChildren: boolean = false) {
super.setLogEnabled(enabled, withChildren);
this.decorators.forEach(v=>{
v.setLogEnabled(enabled, withChildren);
})
this.services.forEach(v=>{
v.setLogEnabled(enabled, withChildren);
})
if(withChildren){
this.children.forEach(v=>{
v.setLogEnabled(enabled, withChildren);
})
}
}
deserialize(){
let { $context, nodeInfo } = this;
if (nodeInfo.children) {
for (let child of nodeInfo.children) {
const options = child.config.label;
if(options.uuid){
const instance = deserializeNode<BehaviorEntity>(this, child, $context);
if(instance){
this.children.push(instance);
}
else{
logger.error("Can't find class by uuid: ", options.uuid);
}
}
else{
logger.error("Can't find class uuid: ", options);
}
}
}
if (nodeInfo.elements) {
for (let elem of nodeInfo.elements) {
const options = elem.config;
if(options.uuid){
const instance = deserializeNode<BehaviorElement>(this, elem, $context, true);
if(instance){
if (elem.type === 'decorator') {
this.decorators.push(instance)
} else if (elem.type === 'service') {
this.services.push(instance)
}
}
else{
logger.error("Can't find class by uuid: ", options.uuid);
}
}
}
}
super.deserialize();
}
destroy(){
for (let dec of this.decorators) {
dec.destroy()
}
for (let ser of this.services) {
ser.destroy()
}
for (let child of this.children) {
child.destroy()
}
this.decorators.length = 0;
this.services.length = 0;
this.children.length = 0;
this.clearInterrupter();
super.destroy();
}
reset(): void {
for (let dec of this.decorators) {
dec.reset()
}
for (let ser of this.services) {
ser.reset()
}
for (let child of this.children) {
child.reset()
}
super.reset();
}
disable(){
if(this.status==BehaviorStatus.Running){
this.status = BehaviorStatus.Abort;
}
super.disable();
}
abort(){
if(this.status==BehaviorStatus.Running){
this.disable();
}
else{
this.status = BehaviorStatus.Abort;
}
return this.onAbort(this.status);
}
onAbort(status: BehaviorStatus){
this.logLifeStatus("abort", status);
return status;
}
interrupt(){
this.onInterrupt(this.status);
return null;
}
onInterrupt(status: BehaviorStatus){
this.logLifeStatus("interrupt", status);
return status;
}
addInterrupter(node: BehaviorDecorator){
if(!this.interrupters.has(node)){
this.interrupters.add(node);
}
}
removeInterrupter(node: BehaviorDecorator){
if(this.interrupters.has(node)){
this.interrupters.delete(node);
}
}
clearInterrupter(){
this.interrupters.clear();
}
/**
* 节点执行逻辑。顺序为:
* @describe 条件装饰器执行成功时:
* @describe execute => condition(get result success) -> service -> self -> decorator => return
* @describe 条件装饰器执行失败时:
* @describe execute => condition(get result fail) => return
* @param status
* @returns
*/
execute(status?: BehaviorStatus){
if(typeof status == 'undefined'){
status = this.status==BehaviorStatus.Running ? BehaviorStatus.Running : BehaviorStatus.None;
}
//如果当前节点是以打断其它节点的方式执行的,说明当前节点已经满足执行条件,这里不需要再执行条件判断了
if(status == BehaviorStatus.Interrupting){
}
else{
status = this.executeCondition(status);
//如果节点执行条件不成功
if(status != BehaviorStatus.Success){
if(this.status==BehaviorStatus.Running){
this.status = status;
this.disable();
}
else{
this.status = status;
}
return this.status;
}
}
this.enter();
if(this.status != BehaviorStatus.Running){
this.enable();
}
this.executeServices(status);
this.status = status = this.update(status);
this.logLifeStatus("execute");
this.status = status = this.executeDecorator(status);
if(status == BehaviorStatus.Running){
}
else{
if(status == BehaviorStatus.Failure){
}
this.disable();
}
this.exit();
return this.status;
}
/**
* 前置条件装饰器
* @description 主要用于判断当前节点是否可执行,比如可实现类似 ConditionalInverter.ts 中条件反转逻辑
* @param status
* @returns
*/
protected executeCondition(status: BehaviorStatus){
let array = this.decorators;
if(array.length > 0){
//装饰器的执行顺序都是从最后一个开始往上执行的
for (let index = array.length-1; index>=0; index--) {
const element = array[index];
if(!element.isInterrupter && element.isCondition){
//将上一个 status 作为参数传入
//该参数使用比较灵活,视具体的 element.execute 方法实现而定
//比如可实现类似 ConditionalInverter 条件反转逻辑
status = element.executeDecorator(status);
}
}
}
else{
//当节点没有挂载前置条件装饰器时,节点必然是可执行的
status = BehaviorStatus.Success;
}
return status;
}
/**
* 后置结果装饰器
* @description 主要用于修改节点执行结果,比如可实现类似 Inverter.ts 中结果反转逻辑
* @param status
* @returns
*/
protected executeDecorator(status: BehaviorStatus){
let array = this.decorators;
//装饰器的执行顺序都是从最后一个开始往上执行的
for (let index = array.length-1; index>=0; index--) {
const element = array[index];
if(!element.isInterrupter && !element.isCondition){
//将上一个 status 作为参数传入
//该参数使用比较灵活,视具体的 element.execute 方法实现而定
//比如可实现类似 Inverter 结果反转逻辑
status = element.executeDecorator(status);
}
}
return status;
}
/**
* 节点服务,每次 tick 周期都会执行
* @param status
*/
protected executeServices(status: BehaviorStatus){
const array = this.services;
for (let index = array.length-1; index>=0; index--) {
const element = array[index];
element.update(status);
}
}
public checkCondition(status: BehaviorStatus){
return this.executeCondition(status);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "d187fd32-d28b-4feb-a544-bd09d1daf092",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,85 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-04-11 10:03:31
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-19 10:17:33
* @Description:
*/
import { IBehaviorEventListener, TBehaviorEvents, TBehaviorNodeEventInterface } from "./behavior-event-declaration";
import { BehaviorStatus } from "./behavior-status";
import { IBehaviorTree } from "./behavior-tree-interface";
export interface IBehaviorNodeInterface {
$context: IBehaviorTree;
delegate: IBehaviorEventListener<TBehaviorNodeEventInterface>;
parent: IBehaviorNodeInterface;
status: BehaviorStatus;
// isInterrupter: boolean;
// isElement: boolean;
// isCondition: boolean;
nodeInfo: INodeInfo;
nodeConfig: INodeConfig;
nodeType: TNodeType;
nodeTag: string;
nodeOrder: number;
nodeTitle: string;
setLogEnabled(enabled: boolean, withChildren: boolean);
}
export type TNodeOrder = number;
export type TNodeType = "selector" | "sequence" | "parallel" | "condition" | "decorator" | "service" | "task";
export interface ILabelConfig {
events: TBehaviorEvents,
group: string,
name: string,
tag: string,
title: string,
order: number
properties: {[key: string]: any},
uuid: string,
}
export interface IElementConfig extends ILabelConfig {
type: TNodeType,
isCondition: boolean,
label?: undefined,
}
export interface IEntityConfig {
type: TNodeType,
label: ILabelConfig,
}
export interface IElementInfo {
type: TNodeType,
config: IElementConfig,
}
export interface IEntityInfo {
type: TNodeType;
config: IEntityConfig;
// label: any;
// /** 平行节点可同时执行的数目 */
// threshold: number;
children: Array<IEntityInfo>;
elements: Array<IElementInfo>;
}
export type INodeInfo = IElementInfo | IEntityInfo;
export type INodeConfig = IElementConfig | ILabelConfig;
export interface INodeProperty {
default: any;
TYPE?: string;
path?: string;
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "db4c226a-e591-429f-85ce-431da6014933",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,194 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-04-08 11:09:25
* @LastEditors: OreoWang
* @LastEditTime: 2022-06-06 14:45:35
* @Description:
*/
import { IElementConfig, ILabelConfig, INodeInfo, INodeConfig } from "./behavior-node-interface";
import { BehaviorEventDelegate } from "./behavior-event-delegate";
import { IBehaviorNodeInterface } from "./behavior-node-interface";
import { BehaviorStatus, TBehaviorStatus } from "./behavior-status";
import { IBehaviorTree, TBehaviorLogKey } from "./behavior-tree-interface";
export class BehaviorNode implements IBehaviorNodeInterface {
$context: IBehaviorTree = null;
delegate: BehaviorEventDelegate = null;
status: TBehaviorStatus = BehaviorStatus.None;
/** 父节点 */
protected _parent: BehaviorNode = null;
get parent(){
return this._parent;
}
protected _nodeInfo: INodeInfo = null;
get nodeInfo() {
return this._nodeInfo;
}
protected _nodeConfig: INodeConfig = null;
get nodeConfig() {
return this._nodeConfig;
}
get nodeType(){
return this.nodeInfo.type;
}
get nodeTag(){
return this.nodeConfig.tag;
}
get nodeOrder(){
return this.nodeConfig.order;
}
get nodeTitle(){
return this.nodeConfig.title;
}
protected _isEnabled = false;
constructor(parent: BehaviorNode, nodeInfo: INodeInfo, context: IBehaviorTree) {
this.$context = context;
this._parent = parent;
this._nodeInfo = nodeInfo;
/** element */
if(!nodeInfo.config.label){
this._nodeConfig = nodeInfo.config as IElementConfig;
}
else{
this._nodeConfig = nodeInfo.config.label as ILabelConfig;
}
if(!this._nodeConfig.tag){
this._nodeConfig.tag = `TAG${this._nodeConfig.order}`;
}
this.delegate = new BehaviorEventDelegate(this, this.nodeConfig.events, context);
}
deserialize(){
this.$context.onDeserialize(this);
}
load(){
this.logLifeStatus("load");
}
destroy(){
this.delegate = null;
this.logLifeStatus("destroy");
}
enter(){
this.logLifeStatus("enter");
this.delegate.onEnter();
}
exit(){
this.logLifeStatus("exit");
this.delegate.onExit();
}
enable(){
if(this._isEnabled){
return;
}
this._isEnabled = true;
this.delegate.onEnable();
this.logLifeStatus("enable");
}
disable(){
if(!this._isEnabled){
return;
}
this._isEnabled = false;
this.delegate.onDisable();
this.logLifeStatus("disable");
}
update(status: BehaviorStatus): TBehaviorStatus {
return this.onUpdate(status);
}
execute(status?: BehaviorStatus): TBehaviorStatus{
return this.onExecute(status);
}
protected onUpdate(status: BehaviorStatus): TBehaviorStatus {
status = this.delegate.onUpdate(status);
this.logLifeStatus("update", status);
return status;
}
protected onExecute(status?: BehaviorStatus): TBehaviorStatus{
this.logLifeStatus("execute", status);
return status;
}
reset() {
this.status = BehaviorStatus.None;
}
_mapStageKey: Map<string, string> = new Map();
protected getStageKey(stage: string): TBehaviorLogKey{
let key = this._mapStageKey.get(stage);
if(!key){
key = `log${stage.substring(0, 1).toUpperCase()}${stage.substring(1)}`;
this._mapStageKey.set(stage, key);
}
return key as TBehaviorLogKey;
}
public clearStageKey(){
this._mapStageKey.clear();
}
public getLogSymbol(){
return "node --"
}
public getLogPrefix(){
return `bt-${this.getLogSymbol()} `;
}
protected isLogEnabled(stage: string){
let key = this.getStageKey(stage);
return this.$context.isLogEnabled(key) && this._logEnabled;
}
protected _logEnabled = true;
/**
* 设置节点是否可以打印log
* @param enabled
* @param withChildren 是否同时设置子节点
*/
setLogEnabled(enabled: boolean, withChildren: boolean = false) {
this._logEnabled = enabled;
if(withChildren){
}
}
/**
* 生命周期各阶段执行状态日志输出(内部调用)
* @param stage
* @param status
*/
protected logLifeStatus(stage: string, status?: BehaviorStatus){
if(typeof status == 'undefined'){
status = this.status;
}
if(this.isLogEnabled(stage)){
this.$context.onHandleTreeLog(`${this.getLogPrefix()} [${this.nodeConfig.order}]-[${stage}] [${this.nodeConfig.title}] ${BehaviorStatus[status]} ${this.getAppendedLog(stage, status)}`);
}
}
/**
* 生命周期各阶段执行状态附加日志(子类按需要重写)
* @param stage
* @param status
* @returns
*/
protected getAppendedLog(stage: string, status?: BehaviorStatus){
return '';
}
/**
* 生命周期各阶段信息日志输出(可在外部按需要调用)
* @param stage
* @param info
*/
public logLifeInfo(stage: string, info: string){
if(this.isLogEnabled(stage)){
this.$context.onHandleTreeLog(`${this.getLogPrefix()} [${this.nodeConfig.order}]-[${stage}] [${this.nodeConfig.title}] : info = ${info} `);
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "561ac289-ce77-4380-81c5-4c8c658f3277",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,112 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:47:14
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-26 17:16:25
* @Description:
*/
import { SharedNumber } from "../blackboard/shared-number";
import { BehaviorComposite } from "./behavior-composite";
import { BehaviorStatus } from "./behavior-status";
export class BehaviorParallel extends BehaviorComposite {
//0 全部成功 -1 全部失败 XXX 指定数目
threshold: SharedNumber = null;
_cacheStatus: Array<BehaviorStatus> = [];
constructor(parent, config, context) {
super(parent, config, context)
this._cacheStatus = [] // children执行状态Cache
}
public getLogSymbol(){
return "para *="
}
update(status: BehaviorStatus) {
let entity = this.interrupt();
if(entity){
}
let threshold = this.threshold && typeof this.threshold.value == 'number' ? this.threshold.value : 0;
if (threshold == 0 || threshold > this.children.length) {
threshold = this.children.length
}
else if(threshold < 0){
threshold = 0
}
// 执行子节点
let success = 0
let running = 0
for (let i = 0; i < this.children.length; i++) {
if (this._cacheStatus[i] == null || this._cacheStatus[i] === BehaviorStatus.Running) {
status = this.children[i].execute()
this._cacheStatus[i] = status
if (status === BehaviorStatus.Running) {
running++
}
}
if (this._cacheStatus[i] === BehaviorStatus.Success) {
success++
}
}
if (running === 0) {
status = (success === threshold) ? BehaviorStatus.Success : BehaviorStatus.Failure
} else {
status = BehaviorStatus.Running
}
return super.update(status);
}
interrupt(){
const running = this._cacheStatus.filter((status)=>{
return status == BehaviorStatus.Running;
})
// 执行子节点中断评估
if(this.interrupters.size>0 && running.length>0){
for(let i=0; i<this.children.length; i++){
const child = this.children[i];
if(child.status!=BehaviorStatus.Running){
for (const element of this.interrupters) {
let status = element.executeInterrupt(this, child);
if(status == BehaviorStatus.Success){
this.abort();
// Sequence 序列节点,需要从 0 开始重新执行
// this.lastRunning = i;
return child;
}
}
}
}
}
return null;
}
abort(){
if(this._cacheStatus.length > 0){
for (let index = 0; index < this._cacheStatus.length; index++) {
const status = this._cacheStatus[index];
if(status == BehaviorStatus.Running){
this._cacheStatus[index] = BehaviorStatus.None;
this.children[index].abort();
}
}
this._cacheStatus.length = 0;
}
return super.abort();
}
reset(){
super.reset();
this._cacheStatus.length = 0
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "725cc9b3-cb0c-471f-ad40-61d46b34f47c",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,71 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:47:14
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-26 17:14:42
* @Description:
*/
import { BehaviorComposite } from "./behavior-composite";
import { BehaviorStatus } from "./behavior-status";
export class BehaviorSelector extends BehaviorComposite {
public getLogSymbol(){
return "sele *?"
}
update(status: BehaviorStatus) {
let entity = this.interrupt();
if(entity){
}
// 执行子节点
let start = this.lastRunning >= 0 ? this.lastRunning : 0
this.lastRunning = -1
for (let i=start; i < this.children.length; i++) {
const child = this.children[i];
if(entity && child == entity){
status = child.execute(BehaviorStatus.Interrupting);
}
else{
status = child.execute();
}
if (status === BehaviorStatus.Success) {
break
}
else if (status === BehaviorStatus.Running) {
this.lastRunning = i
break
}
else{
continue;
}
}
return super.update(status);
}
interrupt(){
let start = this.lastRunning >= 0 ? this.lastRunning : 0
// 执行子节点中断评估
if(this.interrupters.size>0 && start>0){
for(let i=0; i<start; i++){
const child = this.children[i];
for (const element of this.interrupters) {
if(element.owner == this || element.owner == child){
let status = element.executeInterrupt(this, child);
if(status == BehaviorStatus.Success){
this.abort();
this.lastRunning = i;
return child;
}
break;
}
}
}
}
return null;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "32365a9f-4afa-41ef-9b02-43d2933043c9",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,70 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:47:14
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-26 17:17:26
* @Description:
*/
import { BehaviorComposite } from "./behavior-composite";
import { BehaviorStatus } from "./behavior-status";
export class BehaviorSequence extends BehaviorComposite {
public getLogSymbol(){
return "sequ *>"
}
update(status: BehaviorStatus) {
let entity = this.interrupt();
if(entity){
}
// 执行子节点
let start = this.lastRunning >= 0 ? this.lastRunning : 0
this.lastRunning = -1
for (let i=start; i < this.children.length; i++) {
const child = this.children[i];
if(entity && child == entity){
status = child.execute(BehaviorStatus.Interrupting);
}
else{
status = child.execute();
}
if (status === BehaviorStatus.Success) {
continue
}
else if (status === BehaviorStatus.Running) {
this.lastRunning = i
}
break;
}
return super.update(status);
}
interrupt(){
let start = this.lastRunning >= 0 ? this.lastRunning : 0
// 执行子节点中断评估
if(this.interrupters.size>0 && start>0){
for(let i=0; i<start; i++){
const child = this.children[i];
for (const element of this.interrupters) {
if(element.owner == this || element.owner == child){
let status = element.executeInterrupt(this, child);
if(status == BehaviorStatus.Success){
this.abort();
this.lastRunning = i;
return child;
}
break;
}
}
}
}
return null;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "59a0c931-0f73-470b-96ef-13276d1555cf",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,23 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:47:14
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-22 12:56:01
* @Description:
*/
import { BehaviorElement } from "./behavior-node-element";
import { BehaviorStatus } from "./behavior-status"
export class BehaviorService extends BehaviorElement {
public getLogSymbol(){
return "serv &$"
}
execute(status: BehaviorStatus) {
status = super.execute(status);
status = this.update(status);
return status;
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "d33b70da-842d-4600-990a-18cef2ef057b",
"files": [],
"subMetas": {},
"userData": {}
}

View File

@@ -0,0 +1,22 @@
/*
* @Author: OreoWang
* @Email: ihc523@163.com
* @Date: 2022-03-22 21:48:12
* @LastEditors: OreoWang
* @LastEditTime: 2022-04-19 11:29:22
* @Description:
*/
export enum BehaviorStatus {
// Idle = -1,
None = 0,
Success,
Failure,
Running,
Abort,
Interrupting,
}
type ValueOf<T> = T[keyof T];
export type TBehaviorStatus = ValueOf<typeof BehaviorStatus>;
export type KBehaviorStatus = keyof typeof BehaviorStatus;

View File

@@ -0,0 +1,9 @@
{
"ver": "4.0.23",
"importer": "typescript",
"imported": true,
"uuid": "8fed9137-b8a3-457f-9f5d-1415b31e97fd",
"files": [],
"subMetas": {},
"userData": {}
}

Some files were not shown because too many files have changed in this diff Show More