blockmine 1.25.0 → 1.27.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (165) hide show
  1. package/CHANGELOG.md +46 -1
  2. package/backend/cli.js +1 -1
  3. package/backend/package.json +2 -2
  4. package/backend/prisma/migrations/20260328173000_add_plugin_source_ref/migration.sql +2 -0
  5. package/backend/prisma/migrations/migration_lock.toml +2 -2
  6. package/backend/prisma/schema.prisma +2 -0
  7. package/backend/src/api/routes/apiKeys.js +8 -0
  8. package/backend/src/api/routes/bots.js +258 -9
  9. package/backend/src/api/routes/eventGraphs.js +151 -1
  10. package/backend/src/api/routes/health.js +38 -0
  11. package/backend/src/api/routes/nodeRegistry.js +63 -0
  12. package/backend/src/api/routes/plugins.js +254 -29
  13. package/backend/src/container.js +11 -8
  14. package/backend/src/core/BotCommandLoader.js +161 -0
  15. package/backend/src/core/BotConnection.js +125 -0
  16. package/backend/src/core/BotEventHandlers.js +234 -0
  17. package/backend/src/core/BotIPCHandler.js +445 -0
  18. package/backend/src/core/BotManager.js +15 -7
  19. package/backend/src/core/BotProcess.js +75 -142
  20. package/backend/src/core/EventGraphManager.js +7 -3
  21. package/backend/src/core/GraphDebugHandler.js +229 -0
  22. package/backend/src/core/GraphDebugIPC.js +117 -0
  23. package/backend/src/core/GraphExecutionEngine.js +545 -978
  24. package/backend/src/core/GraphTraversal.js +80 -0
  25. package/backend/src/core/GraphValidation.js +73 -0
  26. package/backend/src/core/NodeDefinition.js +138 -0
  27. package/backend/src/core/NodeRegistry.js +153 -141
  28. package/backend/src/core/PluginManager.js +272 -31
  29. package/backend/src/core/RewindSignal.js +9 -0
  30. package/backend/src/core/config/ConfigValidator.js +72 -0
  31. package/backend/src/core/config/FeatureFlags.js +52 -0
  32. package/backend/src/core/config/__tests__/ConfigValidator.test.js +232 -0
  33. package/backend/src/core/domain/entities/Bot.js +39 -0
  34. package/backend/src/core/domain/entities/Command.js +41 -0
  35. package/backend/src/core/domain/entities/EventGraph.js +39 -0
  36. package/backend/src/core/domain/entities/Plugin.js +45 -0
  37. package/backend/src/core/domain/entities/User.js +40 -0
  38. package/backend/src/core/domain/services/DependencyResolver.js +168 -0
  39. package/backend/src/core/domain/services/GraphValidator.js +117 -0
  40. package/backend/src/core/domain/services/PermissionChecker.js +34 -0
  41. package/backend/src/core/domain/services/__tests__/DependencyResolver.test.js +126 -0
  42. package/backend/src/core/domain/valueObjects/BotConfig.js +27 -0
  43. package/backend/src/core/domain/valueObjects/DependencyGraph.js +86 -0
  44. package/backend/src/core/domain/valueObjects/PluginManifest.js +36 -0
  45. package/backend/src/core/errors/BaseError.js +29 -0
  46. package/backend/src/core/errors/ErrorHandler.js +81 -0
  47. package/backend/src/core/errors/__tests__/ErrorHandler.test.js +188 -0
  48. package/backend/src/core/errors/index.js +68 -0
  49. package/backend/src/core/infrastructure/BatchingUtility.js +66 -0
  50. package/backend/src/core/infrastructure/CircuitBreaker.js +103 -0
  51. package/backend/src/core/infrastructure/ConnectionPool.js +81 -0
  52. package/backend/src/core/infrastructure/RateLimiter.js +64 -0
  53. package/backend/src/core/infrastructure/__tests__/BatchingUtility.test.js +86 -0
  54. package/backend/src/core/infrastructure/__tests__/CircuitBreaker.test.js +156 -0
  55. package/backend/src/core/infrastructure/__tests__/ConnectionPool.test.js +146 -0
  56. package/backend/src/core/infrastructure/__tests__/RateLimiter.test.js +171 -0
  57. package/backend/src/core/ipc/botApiFactory.js +72 -0
  58. package/backend/src/core/ipc/ipcMessageTypes.js +115 -0
  59. package/backend/src/core/logging/AuditLogger.js +61 -0
  60. package/backend/src/core/logging/StructuredLogger.js +80 -0
  61. package/backend/src/core/logging/__tests__/StructuredLogger.test.js +213 -0
  62. package/backend/src/core/logging/index.js +7 -0
  63. package/backend/src/core/metrics/MetricsCollector.js +104 -0
  64. package/backend/src/core/metrics/__tests__/MetricsCollector.test.js +131 -0
  65. package/backend/src/core/node-registries/actionsNodes.js +191 -0
  66. package/backend/src/core/node-registries/arraysNodes.js +152 -0
  67. package/backend/src/core/node-registries/botNodes.js +48 -0
  68. package/backend/src/core/node-registries/containerNodes.js +141 -0
  69. package/backend/src/core/node-registries/dataNodes.js +284 -0
  70. package/backend/src/core/node-registries/debugNodes.js +23 -0
  71. package/backend/src/core/node-registries/eventsNodes.js +223 -0
  72. package/backend/src/core/node-registries/flowNodes.js +151 -0
  73. package/backend/src/core/node-registries/furnaceNodes.js +123 -0
  74. package/backend/src/core/node-registries/index.js +108 -0
  75. package/backend/src/core/node-registries/inventory.js +102 -106
  76. package/backend/src/core/node-registries/logicNodes.js +54 -0
  77. package/backend/src/core/node-registries/mathNodes.js +38 -0
  78. package/backend/src/core/node-registries/navigationNodes.js +109 -0
  79. package/backend/src/core/node-registries/objectsNodes.js +90 -0
  80. package/backend/src/core/node-registries/stringsNodes.js +165 -0
  81. package/backend/src/core/node-registries/timeNodes.js +105 -0
  82. package/backend/src/core/node-registries/typeNodes.js +22 -0
  83. package/backend/src/core/node-registries/usersNodes.js +126 -0
  84. package/backend/src/core/nodes/arrays/shuffle.js +14 -0
  85. package/backend/src/core/nodes/bot/get_name.js +8 -0
  86. package/backend/src/core/nodes/bot/stop_bot.js +5 -0
  87. package/backend/src/core/nodes/container/open.js +101 -111
  88. package/backend/src/core/nodes/data/store_read.js +26 -0
  89. package/backend/src/core/nodes/data/store_write.js +23 -0
  90. package/backend/src/core/nodes/event/call_event.js +31 -0
  91. package/backend/src/core/nodes/event/custom_event.js +8 -0
  92. package/backend/src/core/nodes/flow/timer.js +35 -0
  93. package/backend/src/core/nodes/inventory/drop.js +73 -65
  94. package/backend/src/core/nodes/inventory/equip.js +54 -45
  95. package/backend/src/core/nodes/inventory/select_slot.js +48 -46
  96. package/backend/src/core/nodes/navigation/follow.js +54 -51
  97. package/backend/src/core/nodes/navigation/go_to.js +41 -53
  98. package/backend/src/core/nodes/navigation/go_to_entity.js +65 -69
  99. package/backend/src/core/nodes/navigation/go_to_player.js +65 -70
  100. package/backend/src/core/nodes/navigation/stop.js +17 -26
  101. package/backend/src/core/nodes/users/add_to_group.js +24 -0
  102. package/backend/src/core/nodes/users/check_permission.js +26 -0
  103. package/backend/src/core/nodes/users/remove_from_group.js +24 -0
  104. package/backend/src/core/services/BotIPCMessageRouter.js +337 -0
  105. package/backend/src/core/services/BotLifecycleService.js +41 -632
  106. package/backend/src/core/services/CacheManager.js +83 -23
  107. package/backend/src/core/services/CrashRestartManager.js +42 -0
  108. package/backend/src/core/services/DebugSessionManager.js +114 -12
  109. package/backend/src/core/services/EventGraphService.js +69 -0
  110. package/backend/src/core/services/MinecraftBotManager.js +9 -1
  111. package/backend/src/core/services/PluginManagementService.js +84 -0
  112. package/backend/src/core/services/TestModeContext.js +65 -0
  113. package/backend/src/core/services/__tests__/CacheManager.test.js +168 -0
  114. package/backend/src/core/services.js +1 -11
  115. package/backend/src/core/validation/InputValidator.js +167 -0
  116. package/backend/src/core/validation/__tests__/InputValidator.test.js +296 -0
  117. package/backend/src/real-time/botApi/index.js +1 -1
  118. package/backend/src/real-time/socketHandler.js +26 -0
  119. package/backend/src/server.js +10 -5
  120. package/frontend/dist/assets/{browser-ponyfill-DN7pwmHT.js → browser-ponyfill-D8y0Ty7C.js} +1 -1
  121. package/frontend/dist/assets/index-CFJLS0dk.css +32 -0
  122. package/frontend/dist/assets/{index-LSy71uwm.js → index-D91UGNMG.js} +1880 -1881
  123. package/frontend/dist/index.html +2 -2
  124. package/frontend/dist/locales/en/bots.json +4 -1
  125. package/frontend/dist/locales/en/common.json +7 -1
  126. package/frontend/dist/locales/en/login.json +2 -0
  127. package/frontend/dist/locales/en/management.json +79 -1
  128. package/frontend/dist/locales/en/nodes.json +59 -4
  129. package/frontend/dist/locales/en/plugin-detail.json +24 -4
  130. package/frontend/dist/locales/en/plugins.json +226 -7
  131. package/frontend/dist/locales/en/setup.json +2 -0
  132. package/frontend/dist/locales/en/sidebar.json +171 -3
  133. package/frontend/dist/locales/en/visual-editor.json +230 -31
  134. package/frontend/dist/locales/ru/bots.json +4 -1
  135. package/frontend/dist/locales/ru/login.json +2 -0
  136. package/frontend/dist/locales/ru/management.json +79 -1
  137. package/frontend/dist/locales/ru/minecraft-viewer.json +3 -0
  138. package/frontend/dist/locales/ru/nodes.json +105 -51
  139. package/frontend/dist/locales/ru/plugins.json +103 -4
  140. package/frontend/dist/locales/ru/setup.json +2 -0
  141. package/frontend/dist/locales/ru/sidebar.json +171 -3
  142. package/frontend/dist/locales/ru/visual-editor.json +232 -33
  143. package/frontend/package.json +2 -0
  144. package/nul +12 -0
  145. package/package.json +3 -3
  146. package/scripts/postinstall.js +38 -0
  147. package/backend/package-lock.json +0 -6801
  148. package/backend/src/core/node-registries/actions.js +0 -202
  149. package/backend/src/core/node-registries/arrays.js +0 -155
  150. package/backend/src/core/node-registries/bot.js +0 -23
  151. package/backend/src/core/node-registries/container.js +0 -162
  152. package/backend/src/core/node-registries/data.js +0 -290
  153. package/backend/src/core/node-registries/debug.js +0 -26
  154. package/backend/src/core/node-registries/events.js +0 -201
  155. package/backend/src/core/node-registries/flow.js +0 -139
  156. package/backend/src/core/node-registries/furnace.js +0 -143
  157. package/backend/src/core/node-registries/logic.js +0 -62
  158. package/backend/src/core/node-registries/math.js +0 -42
  159. package/backend/src/core/node-registries/navigation.js +0 -111
  160. package/backend/src/core/node-registries/objects.js +0 -98
  161. package/backend/src/core/node-registries/strings.js +0 -187
  162. package/backend/src/core/node-registries/time.js +0 -113
  163. package/backend/src/core/node-registries/type.js +0 -25
  164. package/backend/src/core/node-registries/users.js +0 -79
  165. package/frontend/dist/assets/index-SfhKxI4-.css +0 -32
@@ -0,0 +1,126 @@
1
+ const { GRAPH_TYPES } = require('../../core/constants/graphTypes');
2
+
3
+ const usersNodes = [
4
+ {
5
+ type: 'user:check_blacklist',
6
+ label: '❓ В черном списке?',
7
+ category: 'Пользователи',
8
+ description: 'Проверяет, находится ли пользователь в черном списке.',
9
+ graphType: GRAPH_TYPES.ALL,
10
+ evaluator: require('../../core/nodes/users/check_blacklist').evaluate,
11
+ computeInputs: (data) => [
12
+ { id: 'user', name: 'Пользователь', type: 'User', required: true }
13
+ ],
14
+ computeOutputs: () => [
15
+ { id: 'is_blacklisted', name: 'В ЧС', type: 'Boolean' }
16
+ ],
17
+ defaultData: {},
18
+ theme: { headerColor: '#7c3aed', accentColor: '#8b5cf6' }
19
+ },
20
+ {
21
+ type: 'user:set_blacklist',
22
+ label: '🚫 Установить ЧС',
23
+ category: 'Пользователи',
24
+ description: 'Добавляет или убирает пользователя из черного списка.',
25
+ graphType: GRAPH_TYPES.ALL,
26
+ executor: require('../../core/nodes/users/set_blacklist').execute,
27
+ computeInputs: (data) => [
28
+ { id: 'exec', name: 'Выполнить', type: 'Exec', required: true },
29
+ { id: 'user', name: 'Пользователь', type: 'User', required: true },
30
+ { id: 'blacklist_status', name: 'Статус ЧС', type: 'Boolean', required: true, inlineField: true }
31
+ ],
32
+ computeOutputs: () => [
33
+ { id: 'exec', name: 'Далее', type: 'Exec' },
34
+ { id: 'updated_user', name: 'Обновленный пользователь', type: 'User' }
35
+ ],
36
+ defaultData: { blacklist_status: false },
37
+ theme: { headerColor: '#7c3aed', accentColor: '#8b5cf6' }
38
+ },
39
+ {
40
+ type: 'user:get_groups',
41
+ label: '👥 Получить группы',
42
+ category: 'Пользователи',
43
+ description: 'Возвращает массив названий групп, в которых состоит пользователь.',
44
+ graphType: GRAPH_TYPES.ALL,
45
+ evaluator: require('../../core/nodes/users/get_groups').evaluate,
46
+ computeInputs: (data) => [
47
+ { id: 'user', name: 'Пользователь', type: 'User', required: true }
48
+ ],
49
+ computeOutputs: () => [
50
+ { id: 'groups', name: 'Группы', type: 'Array' }
51
+ ],
52
+ defaultData: {},
53
+ theme: { headerColor: '#7c3aed', accentColor: '#8b5cf6' }
54
+ },
55
+ {
56
+ type: 'user:get_permissions',
57
+ label: '🔑 Получить права',
58
+ category: 'Пользователи',
59
+ description: 'Возвращает массив прав пользователя.',
60
+ graphType: GRAPH_TYPES.ALL,
61
+ evaluator: require('../../core/nodes/users/get_permissions').evaluate,
62
+ computeInputs: (data) => [
63
+ { id: 'user', name: 'Пользователь', type: 'User', required: true }
64
+ ],
65
+ computeOutputs: () => [
66
+ { id: 'permissions', name: 'Права', type: 'Array' }
67
+ ],
68
+ defaultData: {},
69
+ theme: { headerColor: '#7c3aed', accentColor: '#8b5cf6' }
70
+ },
71
+ {
72
+ type: 'user:check_permission',
73
+ label: '🔐 Проверить право',
74
+ category: 'Пользователи',
75
+ description: 'Проверяет, есть ли у пользователя указанное право.',
76
+ graphType: GRAPH_TYPES.ALL,
77
+ evaluator: require('../../core/nodes/users/check_permission').evaluate,
78
+ computeInputs: (data) => [
79
+ { id: 'user', name: 'Пользователь', type: 'User', required: true },
80
+ { id: 'permission', name: 'Право', type: 'String', required: true, inlineField: true, placeholder: 'admin.*' }
81
+ ],
82
+ computeOutputs: () => [
83
+ { id: 'has_permission', name: 'Есть право', type: 'Boolean' }
84
+ ],
85
+ defaultData: { permission: '' },
86
+ theme: { headerColor: '#7c3aed', accentColor: '#8b5cf6' }
87
+ },
88
+ {
89
+ type: 'user:add_to_group',
90
+ label: '➕ Добавить в группу',
91
+ category: 'Пользователи',
92
+ description: 'Добавляет пользователя в указанную группу.',
93
+ graphType: GRAPH_TYPES.ALL,
94
+ executor: require('../../core/nodes/users/add_to_group').execute,
95
+ computeInputs: (data) => [
96
+ { id: 'exec', name: 'Выполнить', type: 'Exec', required: true },
97
+ { id: 'user', name: 'Пользователь', type: 'User', required: true },
98
+ { id: 'group', name: 'Группа', type: 'String', required: true, inlineField: true, placeholder: 'Admin' }
99
+ ],
100
+ computeOutputs: () => [
101
+ { id: 'exec', name: 'Далее', type: 'Exec' }
102
+ ],
103
+ defaultData: { group: '' },
104
+ theme: { headerColor: '#7c3aed', accentColor: '#8b5cf6' }
105
+ },
106
+ {
107
+ type: 'user:remove_from_group',
108
+ label: '➖ Убрать из группы',
109
+ category: 'Пользователи',
110
+ description: 'Убирает пользователя из указанной группы.',
111
+ graphType: GRAPH_TYPES.ALL,
112
+ executor: require('../../core/nodes/users/remove_from_group').execute,
113
+ computeInputs: (data) => [
114
+ { id: 'exec', name: 'Выполнить', type: 'Exec', required: true },
115
+ { id: 'user', name: 'Пользователь', type: 'User', required: true },
116
+ { id: 'group', name: 'Группа', type: 'String', required: true, inlineField: true, placeholder: 'Admin' }
117
+ ],
118
+ computeOutputs: () => [
119
+ { id: 'exec', name: 'Далее', type: 'Exec' }
120
+ ],
121
+ defaultData: { group: '' },
122
+ theme: { headerColor: '#7c3aed', accentColor: '#8b5cf6' }
123
+ }
124
+ ];
125
+
126
+ module.exports = usersNodes;
@@ -0,0 +1,14 @@
1
+ async function evaluate(node, pinId, context, helpers) {
2
+ if (pinId !== 'shuffled') return null;
3
+ const { resolvePinValue } = helpers;
4
+ const array = await resolvePinValue(node, 'array', []);
5
+ if (!Array.isArray(array)) return [];
6
+ const result = [...array];
7
+ for (let i = result.length - 1; i > 0; i--) {
8
+ const j = Math.floor(Math.random() * (i + 1));
9
+ [result[i], result[j]] = [result[j], result[i]];
10
+ }
11
+ return result;
12
+ }
13
+
14
+ module.exports = { evaluate };
@@ -0,0 +1,8 @@
1
+ async function evaluate(node, pinId, context, helpers) {
2
+ if (pinId === 'name') {
3
+ return context.bot?.username || null;
4
+ }
5
+ return null;
6
+ }
7
+
8
+ module.exports = { evaluate };
@@ -0,0 +1,5 @@
1
+ async function execute(node, context, helpers) {
2
+ process.send({ type: 'stop' });
3
+ }
4
+
5
+ module.exports = { execute };
@@ -1,111 +1,101 @@
1
- const Vec3 = require('vec3');
2
-
3
- /**
4
- * container:open - Открыть контейнер по координатам
5
- *
6
- * Executor для action ноды с exec пинами.
7
- * Использует helpers.traverse для перехода к следующему exec выходу.
8
- */
9
- async function execute(node, context, helpers) {
10
- const { resolvePinValue, traverse, memo } = helpers;
11
- const bot = context.bot;
12
-
13
- if (!bot) {
14
- memo.set(`${node.id}:success`, false);
15
- memo.set(`${node.id}:container`, null);
16
- await traverse(node, 'exec_failed');
17
- return;
18
- }
19
-
20
- const x = await resolvePinValue(node, 'x', node.data?.x);
21
- const y = await resolvePinValue(node, 'y', node.data?.y);
22
- const z = await resolvePinValue(node, 'z', node.data?.z);
23
-
24
- const targetX = Number(x ?? 0);
25
- const targetY = Number(y ?? 64);
26
- const targetZ = Number(z ?? 0);
27
-
28
- try {
29
- const block = bot.blockAt(new Vec3(targetX, targetY, targetZ));
30
-
31
- if (!block) {
32
- memo.set(`${node.id}:success`, false);
33
- memo.set(`${node.id}:container`, null);
34
- await traverse(node, 'exec_failed');
35
- return;
36
- }
37
-
38
- const containerTypes = [
39
- 'chest', 'trapped_chest', 'barrel', 'shulker_box',
40
- 'hopper', 'dropper', 'dispenser', 'furnace',
41
- 'blast_furnace', 'smoker', 'brewing_stand'
42
- ];
43
- const isContainer = containerTypes.some(type => block.name.includes(type));
44
-
45
- if (!isContainer) {
46
- memo.set(`${node.id}:success`, false);
47
- memo.set(`${node.id}:container`, null);
48
- await traverse(node, 'exec_failed');
49
- return;
50
- }
51
-
52
- const distance = bot.entity.position.distanceTo(block.position);
53
-
54
- if (distance > 4) {
55
- if (bot.pathfinder) {
56
- const { goals } = require('mineflayer-pathfinder');
57
- const goal = new goals.GoalNear(block.position.x, block.position.y, block.position.z, 2);
58
- await bot.pathfinder.goto(goal);
59
- } else {
60
- memo.set(`${node.id}:success`, false);
61
- memo.set(`${node.id}:container`, null);
62
- await traverse(node, 'exec_failed');
63
- return;
64
- }
65
- }
66
-
67
- if (bot.currentWindow) {
68
- bot.closeWindow(bot.currentWindow);
69
- await new Promise(r => setTimeout(r, 300));
70
- }
71
-
72
- const blockCenter = block.position.offset(0.5, 0.5, 0.5);
73
- await bot.lookAt(blockCenter);
74
- await new Promise(r => setTimeout(r, 100));
75
-
76
- const container = await bot.openContainer(block);
77
-
78
- if (!container) {
79
- throw new Error('Container is null');
80
- }
81
-
82
- context.openContainer = container;
83
-
84
- memo.set(`${node.id}:success`, true);
85
- memo.set(`${node.id}:container`, container);
86
-
87
- await traverse(node, 'exec');
88
- } catch (error) {
89
- memo.set(`${node.id}:success`, false);
90
- memo.set(`${node.id}:container`, null);
91
- await traverse(node, 'exec_failed');
92
- }
93
- }
94
-
95
- /**
96
- * Evaluator для data пинов (success, container)
97
- */
98
- async function evaluate(node, pinId, context, helpers) {
99
- const { memo } = helpers;
100
-
101
- if (pinId === 'success') {
102
- return memo.get(`${node.id}:success`) ?? false;
103
- }
104
- if (pinId === 'container') {
105
- return memo.get(`${node.id}:container`) ?? context.openContainer ?? null;
106
- }
107
-
108
- return null;
109
- }
110
-
111
- module.exports = { execute, evaluate };
1
+ const Vec3 = require('vec3');
2
+
3
+ async function execute(node, context, helpers) {
4
+ const { resolvePinValue, traverse, memo } = helpers;
5
+ const bot = context.bot;
6
+
7
+ if (!bot) {
8
+ memo.set(`${node.id}:success`, false);
9
+ await traverse(node, 'exec');
10
+ return;
11
+ }
12
+
13
+ const x = await resolvePinValue(node, 'x', node.data?.x);
14
+ const y = await resolvePinValue(node, 'y', node.data?.y);
15
+ const z = await resolvePinValue(node, 'z', node.data?.z);
16
+
17
+ const targetX = Number(x ?? 0);
18
+ const targetY = Number(y ?? 64);
19
+ const targetZ = Number(z ?? 0);
20
+
21
+ try {
22
+ const block = bot.blockAt(new Vec3(targetX, targetY, targetZ));
23
+
24
+ if (!block) {
25
+ memo.set(`${node.id}:success`, false);
26
+ memo.set(`${node.id}:container`, null);
27
+ await traverse(node, 'exec_failed');
28
+ return;
29
+ }
30
+
31
+ const containerTypes = [
32
+ 'chest', 'trapped_chest', 'barrel', 'shulker_box',
33
+ 'hopper', 'dropper', 'dispenser', 'furnace',
34
+ 'blast_furnace', 'smoker', 'brewing_stand'
35
+ ];
36
+ const isContainer = containerTypes.some(type => block.name.includes(type));
37
+
38
+ if (!isContainer) {
39
+ memo.set(`${node.id}:success`, false);
40
+ memo.set(`${node.id}:container`, null);
41
+ await traverse(node, 'exec_failed');
42
+ return;
43
+ }
44
+
45
+ const distance = bot.entity.position.distanceTo(block.position);
46
+
47
+ if (distance > 4) {
48
+ if (bot.pathfinder) {
49
+ const { goals } = require('mineflayer-pathfinder');
50
+ const goal = new goals.GoalNear(block.position.x, block.position.y, block.position.z, 2);
51
+ await bot.pathfinder.goto(goal);
52
+ } else {
53
+ memo.set(`${node.id}:success`, false);
54
+ memo.set(`${node.id}:container`, null);
55
+ await traverse(node, 'exec_failed');
56
+ return;
57
+ }
58
+ }
59
+
60
+ if (bot.currentWindow) {
61
+ bot.closeWindow(bot.currentWindow);
62
+ await new Promise(r => setTimeout(r, 300));
63
+ }
64
+
65
+ const blockCenter = block.position.offset(0.5, 0.5, 0.5);
66
+ await bot.lookAt(blockCenter);
67
+ await new Promise(r => setTimeout(r, 100));
68
+
69
+ const container = await bot.openContainer(block);
70
+
71
+ if (!container) {
72
+ throw new Error('Container is null');
73
+ }
74
+
75
+ context.openContainer = container;
76
+
77
+ memo.set(`${node.id}:success`, true);
78
+ memo.set(`${node.id}:container`, container);
79
+
80
+ await traverse(node, 'exec');
81
+ } catch (error) {
82
+ memo.set(`${node.id}:success`, false);
83
+ memo.set(`${node.id}:container`, null);
84
+ await traverse(node, 'exec_failed');
85
+ }
86
+ }
87
+
88
+ async function evaluate(node, pinId, context, helpers) {
89
+ const { memo } = helpers;
90
+
91
+ if (pinId === 'success') {
92
+ return memo.get(`${node.id}:success`) ?? false;
93
+ }
94
+ if (pinId === 'container') {
95
+ return memo.get(`${node.id}:container`) ?? context.openContainer ?? null;
96
+ }
97
+
98
+ return null;
99
+ }
100
+
101
+ module.exports = { execute, evaluate };
@@ -0,0 +1,26 @@
1
+ const prismaService = require('../../PrismaService');
2
+ const prisma = prismaService.getClient();
3
+
4
+ async function evaluate(node, pinId, context, helpers) {
5
+ if (pinId !== 'value') return null;
6
+ const { resolvePinValue } = helpers;
7
+
8
+ const pluginName = await resolvePinValue(node, 'plugin_name', node.data?.plugin_name || '');
9
+ const key = await resolvePinValue(node, 'key', node.data?.key || '');
10
+
11
+ if (!pluginName || !key) return null;
12
+
13
+ const row = await prisma.pluginDataStore.findUnique({
14
+ where: { pluginName_botId_key: { pluginName, botId: context.botId, key } }
15
+ });
16
+
17
+ if (!row) return null;
18
+
19
+ try {
20
+ return JSON.parse(row.value);
21
+ } catch {
22
+ return row.value;
23
+ }
24
+ }
25
+
26
+ module.exports = { evaluate };
@@ -0,0 +1,23 @@
1
+ const prismaService = require('../../PrismaService');
2
+ const prisma = prismaService.getClient();
3
+
4
+ async function execute(node, context, helpers) {
5
+ const { resolvePinValue, traverse } = helpers;
6
+
7
+ const pluginName = await resolvePinValue(node, 'plugin_name', node.data?.plugin_name || '');
8
+ const key = await resolvePinValue(node, 'key', node.data?.key || '');
9
+ const value = await resolvePinValue(node, 'value', null);
10
+
11
+ if (pluginName && key) {
12
+ const stringValue = typeof value === 'string' ? value : JSON.stringify(value);
13
+ await prisma.pluginDataStore.upsert({
14
+ where: { pluginName_botId_key: { pluginName, botId: context.botId, key } },
15
+ update: { value: stringValue },
16
+ create: { pluginName, botId: context.botId, key, value: stringValue }
17
+ });
18
+ }
19
+
20
+ await traverse(node, 'exec');
21
+ }
22
+
23
+ module.exports = { execute };
@@ -0,0 +1,31 @@
1
+ async function executor(node, context, helpers) {
2
+ const { resolvePinValue, traverse, memo } = helpers;
3
+
4
+ const selectedEventId = node.data?.selectedEventId;
5
+ if (!selectedEventId) {
6
+ await traverse(node, 'exec');
7
+ return;
8
+ }
9
+
10
+ const targetNode = this.activeGraph.nodes.find(n => n.id === selectedEventId);
11
+ if (!targetNode || targetNode.type !== 'event:custom_event') {
12
+ await traverse(node, 'exec');
13
+ return;
14
+ }
15
+
16
+ const eventPins = targetNode.data?.pins || [];
17
+ for (const pin of eventPins) {
18
+ if (pin.type === 'Exec') continue;
19
+ const value = await resolvePinValue(node, pin.id);
20
+ memo.set(`${targetNode.id}:${pin.id}`, value);
21
+ }
22
+
23
+ const cacheKey = `${targetNode.id}_executed`;
24
+ memo.delete(cacheKey);
25
+
26
+ await traverse(targetNode, 'exec');
27
+
28
+ await traverse(node, 'exec');
29
+ }
30
+
31
+ module.exports = { executor };
@@ -0,0 +1,8 @@
1
+ async function evaluate(node, pinId, context, helpers) {
2
+ const { memo } = helpers;
3
+ const cached = memo.get(`${node.id}:${pinId}`);
4
+ if (cached !== undefined) return cached;
5
+ return null;
6
+ }
7
+
8
+ module.exports = { evaluate };
@@ -0,0 +1,35 @@
1
+ const BreakLoopSignal = require('../../BreakLoopSignal');
2
+
3
+ async function execute(node, context, helpers) {
4
+ const { resolvePinValue, traverse, clearLoopBodyMemo, memo } = helpers;
5
+
6
+ const intervalSec = await resolvePinValue(node, 'interval', 1);
7
+ const maxTicks = await resolvePinValue(node, 'max_ticks', 0);
8
+ const intervalMs = Math.max(100, (intervalSec || 1) * 1000);
9
+
10
+ let tick = 0;
11
+
12
+ const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
13
+
14
+ try {
15
+ while (maxTicks === 0 || tick < maxTicks) {
16
+ memo.set(`${node.id}:tick`, tick);
17
+ clearLoopBodyMemo(node);
18
+ await traverse(node, 'loop_body');
19
+ tick++;
20
+ await delay(intervalMs);
21
+ }
22
+ } catch (e) {
23
+ if (!(e instanceof BreakLoopSignal)) throw e;
24
+ }
25
+
26
+ await traverse(node, 'completed');
27
+ }
28
+
29
+ async function evaluate(node, pinId, context, helpers) {
30
+ const { memo } = helpers;
31
+ if (pinId === 'tick') return memo.get(`${node.id}:tick`) ?? 0;
32
+ return null;
33
+ }
34
+
35
+ module.exports = { execute, evaluate };
@@ -1,65 +1,73 @@
1
- /**
2
- * inventory:drop - Выбросить предмет из инвентаря
3
- */
4
- async function evaluate(node, pinId, context, helpers) {
5
- const bot = context.bot;
6
- const itemName = await helpers.resolvePinValue(node, 'itemName');
7
- const count = await helpers.resolvePinValue(node, 'count');
8
- const dropAll = await helpers.resolvePinValue(node, 'dropAll');
9
-
10
- if (pinId === 'exec') {
11
- return true; // Exec output
12
- }
13
-
14
- if (!bot?.inventory || !itemName) {
15
- if (pinId === 'dropped') return 0;
16
- return null;
17
- }
18
-
19
- try {
20
- // Ищем предмет(ы) в инвентаре
21
- const searchName = itemName.toLowerCase().replace('minecraft:', '');
22
- const items = bot.inventory.items().filter(i =>
23
- i.name.toLowerCase().includes(searchName) ||
24
- i.displayName?.toLowerCase().includes(searchName)
25
- );
26
-
27
- if (items.length === 0) {
28
- if (pinId === 'dropped') return 0;
29
- return null;
30
- }
31
-
32
- let totalDropped = 0;
33
-
34
- if (dropAll) {
35
- // Выбрасываем все такие предметы
36
- for (const item of items) {
37
- await bot.tossStack(item);
38
- totalDropped += item.count;
39
- }
40
- } else {
41
- // Выбрасываем указанное количество или один стак
42
- const item = items[0];
43
- const toDrop = count || item.count;
44
-
45
- if (toDrop >= item.count) {
46
- await bot.tossStack(item);
47
- totalDropped = item.count;
48
- } else {
49
- await bot.toss(item.type, item.metadata, toDrop);
50
- totalDropped = toDrop;
51
- }
52
- }
53
-
54
- if (pinId === 'dropped') {
55
- return totalDropped;
56
- }
57
- } catch (error) {
58
- console.error('[inventory:drop] Error:', error.message);
59
- if (pinId === 'dropped') return 0;
60
- }
61
-
62
- return null;
63
- }
64
-
65
- module.exports = { evaluate };
1
+ async function execute(node, context, helpers) {
2
+ const { resolvePinValue, traverse, memo } = helpers;
3
+ const bot = context.bot;
4
+
5
+ if (!bot?.inventory) {
6
+ memo.set(`${node.id}:dropped`, 0);
7
+ await traverse(node, 'exec');
8
+ return;
9
+ }
10
+
11
+ const itemName = await resolvePinValue(node, 'itemName', node.data?.itemName);
12
+ const count = await resolvePinValue(node, 'count', node.data?.count);
13
+ const dropAll = await resolvePinValue(node, 'dropAll', node.data?.dropAll);
14
+
15
+ if (!itemName) {
16
+ memo.set(`${node.id}:dropped`, 0);
17
+ await traverse(node, 'exec');
18
+ return;
19
+ }
20
+
21
+ try {
22
+ const searchName = itemName.toLowerCase().replace('minecraft:', '');
23
+ const items = bot.inventory.items().filter(i =>
24
+ i.name.toLowerCase().includes(searchName) ||
25
+ i.displayName?.toLowerCase().includes(searchName)
26
+ );
27
+
28
+ if (items.length === 0) {
29
+ memo.set(`${node.id}:dropped`, 0);
30
+ await traverse(node, 'exec');
31
+ return;
32
+ }
33
+
34
+ let totalDropped = 0;
35
+
36
+ if (dropAll) {
37
+ for (const item of items) {
38
+ await bot.tossStack(item);
39
+ totalDropped += item.count;
40
+ }
41
+ } else {
42
+ const item = items[0];
43
+ const toDrop = count || item.count;
44
+
45
+ if (toDrop >= item.count) {
46
+ await bot.tossStack(item);
47
+ totalDropped = item.count;
48
+ } else {
49
+ await bot.toss(item.type, item.metadata, toDrop);
50
+ totalDropped = toDrop;
51
+ }
52
+ }
53
+
54
+ memo.set(`${node.id}:dropped`, totalDropped);
55
+ await traverse(node, 'exec');
56
+ } catch (error) {
57
+ console.error('[inventory:drop] Error:', error.message);
58
+ memo.set(`${node.id}:dropped`, 0);
59
+ await traverse(node, 'exec');
60
+ }
61
+ }
62
+
63
+ async function evaluate(node, pinId, context, helpers) {
64
+ const { memo } = helpers;
65
+
66
+ if (pinId === 'dropped') {
67
+ return memo.get(`${node.id}:dropped`) ?? 0;
68
+ }
69
+
70
+ return null;
71
+ }
72
+
73
+ module.exports = { execute, evaluate };