Skip to content

Commit 4a3b151

Browse files
Async interpreted API
This makes running commands in the interpreted API async, fixing #1 (infinite loops crashing the game and program) and allowing events to run without blocking each other (eg. code in events can now run if an infinite loop is running)
1 parent fc68c9c commit 4a3b151

File tree

7 files changed

+58
-54
lines changed

7 files changed

+58
-54
lines changed

app.js

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,11 @@ app.whenReady().then(() => {
4848

4949
window.loadFile(path.resolve(import.meta.dirname, 'wwwdist/index.html'));
5050

51-
ipcMain.on('command', (event, command) => {
52-
Client.clients.forEach((client) => {
53-
client.execute(command);
54-
});
55-
});
56-
5751
// TODO: handle multiple clients
58-
ipcMain.handle('command-with-response', (event, command) => {
52+
ipcMain.handle('command', (event, command) => {
5953
return Client.clients[0].execute(command);
6054
});
6155

62-
// same as above but synchronously
63-
ipcMain.on('command-with-response', async (event, command) => {
64-
// I don't know why Electron doesn't like it if I send over the original Promise.
65-
event.returnValue = await Client.clients[0].execute(command);
66-
});
67-
6856
ipcMain.handle('request-port', (event) => port);
6957

7058
ipcMain.handle('save-file-user', async (event, data) => {

preload.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ contextBridge.exposeInMainWorld('wsserver', {
1111
});
1212

1313
contextBridge.exposeInMainWorld('minecraft', {
14-
runCommand: (command) => ipcRenderer.send('command', command),
15-
runCommandWithResponse: (command) => ipcRenderer.sendSync('command-with-response', command),
14+
runCommand: (command) => ipcRenderer.invoke('command', command),
1615
resetEventListeners: () => {
1716
ipcRenderer.eventNames().forEach((name) => {
1817
if (name.substring(0, 6) === 'event:') {

wwwsrc/api/agent.js

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,41 +1,45 @@
11
export const agent = {
22
teleport(position) {
3-
minecraft.runCommand(`agent tp ${ position.x || '~' } ${ position.y || '~' } ${ position.z || '~' }`);
3+
return minecraft.runCommand(`agent tp ${ position.x || '~' } ${ position.y || '~' } ${ position.z || '~' }`);
44
},
5-
getPosition() {
6-
return minecraft.runCommandWithResponse('agent getposition');
5+
async getPosition() {
6+
return await minecraft.runCommand('agent getposition');
77
},
88
move(direction, blocks) {
9+
let commands = [];
10+
911
for (let i = 0; i < blocks; i++) {
10-
minecraft.runCommand(`agent move ${ direction }`);
12+
commands.push(minecraft.runCommand(`agent move ${ direction }`));
1113
}
14+
15+
return Promise.all(commands);
1216
},
1317
turn(direction) {
14-
minecraft.runCommand(`agent turn ${ direction }`);
18+
return minecraft.runCommand(`agent turn ${ direction }`);
1519
},
1620
attack(direction) {
17-
minecraft.runCommand(`agent attack ${ direction }`);
21+
return minecraft.runCommand(`agent attack ${ direction }`);
1822
},
1923
destroy(direction) {
20-
minecraft.runCommand(`agent destroy ${ direction }`);
24+
return minecraft.runCommand(`agent destroy ${ direction }`);
2125
},
2226
drop(slot, amount, direction) {
2327
if (slot === null) {
24-
minecraft.runCommand(`agent dropall ${ direction }`);
28+
return minecraft.runCommand(`agent dropall ${ direction }`);
2529
} else {
26-
minecraft.runCommand(`agent drop ${ slot } ${ amount } ${ direction }`);
30+
return minecraft.runCommand(`agent drop ${ slot } ${ amount } ${ direction }`);
2731
}
2832
},
2933
build(slot, direction) {
30-
minecraft.runCommand(`agent place ${ slot } ${ direction }`);
34+
return minecraft.runCommand(`agent place ${ slot } ${ direction }`);
3135
},
3236
till(direction) {
33-
minecraft.runCommand(`agent till ${ direction }`);
37+
return minecraft.runCommand(`agent till ${ direction }`);
3438
},
3539
collect(id) {
36-
minecraft.runCommand(`agent collect ${ id }`);
40+
return minecraft.runCommand(`agent collect ${ id }`);
3741
},
3842
transfer(srcSlotNum, quantity, dstSlotNum) {
39-
minecraft.runCommand(`agent transfer ${ srcSlotNum } ${ quantity } ${ dstSlotNum }`);
43+
return minecraft.runCommand(`agent transfer ${ srcSlotNum } ${ quantity } ${ dstSlotNum }`);
4044
}
4145
};

wwwsrc/api/lifecycle.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const lifecycle = {
2+
entrypoints: [],
3+
4+
on(eventName, callback) {
5+
switch (eventName) {
6+
case 'run':
7+
this.entrypoints.push(callback);
8+
}
9+
}
10+
};

wwwsrc/api/player.js

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ export const player = {
44
message: '',
55

66
teleport(position) {
7-
minecraft.runCommand(`tp ${ position.x || '~' } ${ position.y || '~' } ${ position.z || '~' }`);
7+
return minecraft.runCommand(`tp ${ position.x || '~' } ${ position.y || '~' } ${ position.z || '~' }`);
88
},
9-
getPosition() {
10-
const body = minecraft.runCommandWithResponse('querytarget @s');
9+
async getPosition() {
10+
const body = await minecraft.runCommand('querytarget @s');
1111
const playerDetails = JSON.parse(body.details)[0];
1212

1313
return playerDetails.position;
@@ -33,8 +33,5 @@ export const player = {
3333
});
3434
break;
3535
}
36-
if (eventName === 'die') {
37-
minecraft.onPlayerDied(callback);
38-
}
3936
}
4037
};

wwwsrc/generators/javascript.js

Lines changed: 21 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,9 @@ export const javascriptBlocks = {
1212
return [ `{ x: ${ x || 'null' }, y: ${ y || 'null' }, z: ${ z || 'null' } }`, Order.NONE ];
1313
},
1414
lifecycle_run(block, generator) {
15-
// Code inserted at top level
16-
return generator.statementToCode(block, 'DO');
15+
const code = generator.statementToCode(block, 'DO');
16+
17+
return `lifecycle.on('run', async () => {\n${ code }\n});\n`;
1718
},
1819
math_coordinate_value(block, generator) {
1920
const axis = block.getFieldValue('AXIS');
@@ -24,87 +25,87 @@ export const javascriptBlocks = {
2425
agent_teleport(block, generator) {
2526
const position = generator.valueToCode(block, 'POSITION', Order.NONE);
2627

27-
return `agent.teleport(${ position });\n`;
28+
return `await agent.teleport(${ position });\n`;
2829
},
2930
agent_position(block, generator) {
30-
return [ 'agent.getPosition()', Order.FUNCTION_CALL ];
31+
return [ 'await agent.getPosition()', Order.FUNCTION_CALL ];
3132
},
3233
agent_move(block, generator) {
3334
const direction = block.getFieldValue('DIRECTION');
3435
const blocks = generator.valueToCode(block, 'BLOCKS', Order.NONE);
3536

36-
return `agent.move('${ direction }', ${ blocks });\n`;
37+
return `await agent.move('${ direction }', ${ blocks });\n`;
3738
},
3839
agent_turn(block, generator) {
3940
const direction = block.getFieldValue('DIRECTION');
4041

41-
return `agent.turn('${ direction }');\n`;
42+
return `await agent.turn('${ direction }');\n`;
4243
},
4344
agent_attack(block, generator) {
4445
const direction = block.getFieldValue('DIRECTION');
4546

46-
return `agent.attack('${ direction }');\n`;
47+
return `await agent.attack('${ direction }');\n`;
4748
},
4849
agent_destroy(block, generator) {
4950
const direction = block.getFieldValue('DIRECTION');
5051

51-
return `agent.destroy('${ direction }');\n`;
52+
return `await agent.destroy('${ direction }');\n`;
5253
},
5354
agent_drop(block, generator) {
5455
const amount = generator.valueToCode(block, 'AMOUNT', Order.NONE);
5556
const slot = generator.valueToCode(block, 'SLOT', Order.NONE);
5657
const direction = block.getFieldValue('DIRECTION');
5758

58-
return `agent.drop(${ slot }, ${ amount }, '${ direction }');\n`;
59+
return `await agent.drop(${ slot }, ${ amount }, '${ direction }');\n`;
5960
},
6061
agent_drop_all(block, generator) {
6162
const direction = block.getFieldValue('DIRECTION');
6263

63-
return `agent.drop(null, null, '${ direction }');\n`;
64+
return `await agent.drop(null, null, '${ direction }');\n`;
6465
},
6566
agent_build(block, generator) {
6667
const slot = generator.valueToCode(block, 'SLOT', Order.NONE);
6768
const direction = block.getFieldValue('DIRECTION');
6869

69-
return `agent.build(${ slot }, '${ direction }');\n`;
70+
return `await agent.build(${ slot }, '${ direction }');\n`;
7071
},
7172
agent_till(block, generator) {
7273
const direction = block.getFieldValue('DIRECTION');
7374

74-
return `agent.till('${ direction }');\n`;
75+
return `await agent.till('${ direction }');\n`;
7576
},
7677
agent_collect(block, generator) {
77-
return 'agent.collect(\'all\');\n';
78+
return 'await agent.collect(\'all\');\n';
7879
},
7980
agent_collect_specify(block, generator) {
8081
const item = generator.valueToCode(block, 'ITEM', Order.NONE);
8182

82-
return `agent.collect(${ item });\n`;
83+
return `await agent.collect(${ item });\n`;
8384
},
8485
agent_transfer(block, generator) {
8586
const amount = generator.valueToCode(block, 'AMOUNT', Order.NONE);
8687
const fromSlot = generator.valueToCode(block, 'FROM', Order.NONE);
8788
const toSlot = generator.valueToCode(block, 'TO', Order.NONE);
8889

89-
return `agent.transfer(${ fromSlot }, ${ amount }, ${ toSlot });\n`;
90+
return `await agent.transfer(${ fromSlot }, ${ amount }, ${ toSlot });\n`;
9091
},
9192
player_died(block, generator) {
9293
const code = generator.statementToCode(block, 'DO');
9394

94-
return `player.on('die', () => {\n${ code }\n});\n`;
95+
return `player.on('die', async () => {\n${ code }\n});\n`;
9596
},
9697
player_teleport(block, generator) {
9798
const position = generator.valueToCode(block, 'POSITION', Order.NONE);
9899

99-
return `player.teleport(${ position });\n`;
100+
return `await player.teleport(${ position });\n`;
100101
},
101102
player_position(block, generator) {
102-
return [ 'player.getPosition()', Order.FUNCTION_CALL ];
103+
return [ 'await player.getPosition()', Order.FUNCTION_CALL ];
103104
},
104105
player_used_item(block, generator) {
105106
const code = generator.statementToCode(block, 'DO');
106107

107-
return `player.on('useItem', () => {\n${ code }\n});\n`;
108+
return `player.on('useItem', async () => {\n${ code }\n});\n`;
108109
},
109110
player_used_item_count(block, generator) {
110111
return [ 'player.itemAmountUsed', Order.MEMBER ];
@@ -115,7 +116,7 @@ export const javascriptBlocks = {
115116
player_chat(block, generator) {
116117
const code = generator.statementToCode(block, 'DO');
117118

118-
return `player.on('chat', () => {\n${ code }\n});\n`;
119+
return `player.on('chat', async () => {\n${ code }\n});\n`;
119120
},
120121
player_chat_message(block, generator) {
121122
return [ 'player.message', Order.MEMBER ];

wwwsrc/index.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { toolbox } from './toolbox.js';
1111
import Sval from 'sval';
1212
import { agent } from './api/agent.js';
1313
import { player } from './api/player.js';
14+
import { lifecycle } from './api/lifecycle.js';
1415
import './index.css';
1516
import 'vex-js/dist/css/vex.css';
1617
import 'vex-js/dist/css/vex-theme-default.css';
@@ -83,6 +84,7 @@ wsserver.onConnection(() => {
8384
const code = `\
8485
import { agent } from 'agent';
8586
import { player } from 'player';
87+
import { lifecycle } from 'lifecycle';
8688
8789
${ genCode }\
8890
`;
@@ -93,10 +95,13 @@ ${ genCode }\
9395

9496
interpreter.import('agent', { agent });
9597
interpreter.import('player', { player });
98+
interpreter.import('lifecycle', { lifecycle });
9699

97100
minecraft.resetEventListeners();
98101

99102
interpreter.run(code);
103+
104+
lifecycle.entrypoints.forEach((callback) => callback());
100105
});
101106
});
102107

0 commit comments

Comments
 (0)