redscript-mc 1.2.28 → 1.2.30
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.
- package/README.md +29 -28
- package/README.zh.md +28 -28
- package/demo.gif +0 -0
- package/dist/__tests__/cli.test.js +12 -12
- package/dist/__tests__/optimizer-advanced.test.js +4 -4
- package/dist/compile.d.ts +3 -2
- package/dist/compile.js +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -1
- package/dist/lexer/index.js +9 -1
- package/dist/lowering/index.js +17 -2
- package/editors/vscode/out/extension.js +1797 -1157
- package/editors/vscode/package-lock.json +3 -3
- package/editors/vscode/package.json +1 -1
- package/editors/vscode/src/hover.ts +18 -0
- package/editors/vscode/syntaxes/redscript.tmLanguage.json +12 -3
- package/examples/readme-demo.mcrs +44 -66
- package/package.json +1 -1
- package/src/__tests__/cli.test.ts +12 -12
- package/src/__tests__/optimizer-advanced.test.ts +4 -4
- package/src/compile.ts +4 -3
- package/src/index.ts +5 -4
- package/src/lexer/index.ts +9 -1
- package/src/lowering/index.ts +20 -4
package/README.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
<img src="./logo.png" alt="RedScript Logo" width="64" />
|
|
4
4
|
|
|
5
|
-
<img src="https://img.shields.io/badge/RedScript-1.2.
|
|
5
|
+
<img src="https://img.shields.io/badge/RedScript-1.2.29-red?style=for-the-badge&logo=minecraft&logoColor=white" alt="RedScript" />
|
|
6
6
|
|
|
7
7
|
**A typed scripting language that compiles to Minecraft datapacks.**
|
|
8
8
|
|
|
9
9
|
Write clean game logic. RedScript handles the scoreboard spaghetti.
|
|
10
10
|
|
|
11
11
|
[](https://github.com/bkmashiro/redscript/actions/workflows/ci.yml)
|
|
12
|
-
[](https://github.com/bkmashiro/redscript)
|
|
13
13
|
[](https://www.npmjs.com/package/redscript-mc)
|
|
14
14
|
[](https://www.npmjs.com/package/redscript-mc)
|
|
15
15
|
[](https://marketplace.visualstudio.com/items?itemName=bkmashiro.redscript-vscode)
|
|
@@ -20,9 +20,11 @@ Write clean game logic. RedScript handles the scoreboard spaghetti.
|
|
|
20
20
|
|
|
21
21
|
### 🚀 [Try it online — no install needed!](https://redscript-ide.pages.dev)
|
|
22
22
|
|
|
23
|
-
<img src="./demo.gif" alt="RedScript Demo" width="
|
|
23
|
+
<img src="./demo.gif" alt="RedScript Demo — math curves drawn with particles in Minecraft" width="520" />
|
|
24
24
|
|
|
25
|
-
*↑
|
|
25
|
+
*↑ Five mathematical curves rendered in real-time with particles — 100% vanilla, no mods!*
|
|
26
|
+
*`y = x·sin(x)` · `y = sin(x) + ½sin(2x)` · `y = e⁻ˣsin(4x)` · `y = tanh(2x)` · `r = cos(2θ)` rose curve*
|
|
27
|
+
*Each curve is computed tick-by-tick using RedScript's fixed-point math stdlib.*
|
|
26
28
|
|
|
27
29
|
</div>
|
|
28
30
|
|
|
@@ -32,34 +34,33 @@ Write clean game logic. RedScript handles the scoreboard spaghetti.
|
|
|
32
34
|
|
|
33
35
|
RedScript is a typed scripting language that compiles to vanilla Minecraft datapacks. Write clean code with variables, functions, loops, and events — RedScript handles the scoreboard commands and `.mcfunction` files for you.
|
|
34
36
|
|
|
35
|
-
**The demo above?**
|
|
37
|
+
**The demo above?** Five math curves drawn with 64 sample points each. The core logic:
|
|
36
38
|
|
|
37
39
|
```rs
|
|
38
|
-
|
|
39
|
-
let running: bool = false;
|
|
40
|
-
|
|
41
|
-
@tick fn demo_tick() {
|
|
42
|
-
if (!running) { return; }
|
|
43
|
-
counter = counter + 1;
|
|
44
|
-
|
|
45
|
-
foreach (p in @a) at @s {
|
|
46
|
-
particle("minecraft:end_rod", ~0, ~1, ~0, 0.5, 0.5, 0.5, 0.1, 5);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (counter % 20 == 0) {
|
|
50
|
-
say(f"Running for {counter} ticks");
|
|
51
|
-
}
|
|
52
|
-
}
|
|
40
|
+
import "stdlib/math.mcrs"
|
|
53
41
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
42
|
+
let phase: int = 0;
|
|
43
|
+
let frame: int = 0;
|
|
44
|
+
|
|
45
|
+
// 5 curves cycle every 128 ticks (~6.5 s each)
|
|
46
|
+
@tick fn _wave_tick() {
|
|
47
|
+
phase = (phase + 4) % 360;
|
|
48
|
+
frame = frame + 1;
|
|
49
|
+
|
|
50
|
+
let curve_id: int = (frame / 128) % 5;
|
|
51
|
+
|
|
52
|
+
// Compute sin at 9 column offsets (40° apart = full sine wave span)
|
|
53
|
+
let s0: int = sin_fixed((phase + 0) % 360);
|
|
54
|
+
let s1: int = sin_fixed((phase + 40) % 360);
|
|
55
|
+
// ... s2 through s8 ...
|
|
56
|
+
|
|
57
|
+
// Draw bar chart: each column height = sin value
|
|
58
|
+
// (64 fixed particle positions per curve, all respawned each tick)
|
|
59
|
+
if (curve_id == 0) { _draw_xsinx(); }
|
|
60
|
+
if (curve_id == 1) { _draw_harmonic(); }
|
|
61
|
+
// ...
|
|
59
62
|
|
|
60
|
-
|
|
61
|
-
running = false;
|
|
62
|
-
say(f"Demo stopped at {counter} ticks.");
|
|
63
|
+
actionbar(@a, f"§e y = x·sin(x) phase: {phase}° center: {s0}‰");
|
|
63
64
|
}
|
|
64
65
|
```
|
|
65
66
|
|
package/README.zh.md
CHANGED
|
@@ -2,14 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
<img src="./logo.png" alt="RedScript Logo" width="64" />
|
|
4
4
|
|
|
5
|
-
<img src="https://img.shields.io/badge/RedScript-1.2.
|
|
5
|
+
<img src="https://img.shields.io/badge/RedScript-1.2.29-red?style=for-the-badge&logo=minecraft&logoColor=white" alt="RedScript" />
|
|
6
6
|
|
|
7
7
|
**一个编译到 Minecraft Datapack 的类型化脚本语言。**
|
|
8
8
|
|
|
9
9
|
写干净的游戏逻辑,把记分板的面条代码交给 RedScript 处理。
|
|
10
10
|
|
|
11
11
|
[](https://github.com/bkmashiro/redscript/actions/workflows/ci.yml)
|
|
12
|
-
[](https://github.com/bkmashiro/redscript)
|
|
13
13
|
[](https://www.npmjs.com/package/redscript-mc)
|
|
14
14
|
[](https://www.npmjs.com/package/redscript-mc)
|
|
15
15
|
[](https://marketplace.visualstudio.com/items?itemName=bkmashiro.redscript-vscode)
|
|
@@ -20,9 +20,11 @@
|
|
|
20
20
|
|
|
21
21
|
### 🚀 [在线试用 — 无需安装!](https://redscript-ide.pages.dev)
|
|
22
22
|
|
|
23
|
-
<img src="./demo.gif" alt="RedScript Demo" width="
|
|
23
|
+
<img src="./demo.gif" alt="RedScript Demo — 用粒子在 Minecraft 中绘制数学曲线" width="520" />
|
|
24
24
|
|
|
25
|
-
*↑
|
|
25
|
+
*↑ 五条数学函数图像实时粒子渲染 — 纯原版,无需 MOD!*
|
|
26
|
+
*`y = x·sin(x)` · `y = sin(x) + ½sin(2x)` · `y = e⁻ˣsin(4x)` · `y = tanh(2x)` · 玫瑰曲线 `r = cos(2θ)`*
|
|
27
|
+
*每条曲线由 RedScript 定点数学库逐 tick 计算,64 个采样点动态绘制。*
|
|
26
28
|
|
|
27
29
|
</div>
|
|
28
30
|
|
|
@@ -32,34 +34,32 @@
|
|
|
32
34
|
|
|
33
35
|
RedScript 是一门编译到原版 Minecraft 数据包的脚本语言。用变量、函数、循环、事件写代码,RedScript 帮你生成记分板命令和 `.mcfunction` 文件。
|
|
34
36
|
|
|
35
|
-
**上面的演示?**
|
|
37
|
+
**上面的演示?** 五条数学曲线,每条 64 个采样点,核心逻辑:
|
|
36
38
|
|
|
37
39
|
```rs
|
|
38
|
-
|
|
39
|
-
let running: bool = false;
|
|
40
|
-
|
|
41
|
-
@tick fn demo_tick() {
|
|
42
|
-
if (!running) { return; }
|
|
43
|
-
counter = counter + 1;
|
|
44
|
-
|
|
45
|
-
foreach (p in @a) at @s {
|
|
46
|
-
particle("minecraft:end_rod", ~0, ~1, ~0, 0.5, 0.5, 0.5, 0.1, 5);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
if (counter % 20 == 0) {
|
|
50
|
-
say(f"已运行 {counter} ticks");
|
|
51
|
-
}
|
|
52
|
-
}
|
|
40
|
+
import "stdlib/math.mcrs"
|
|
53
41
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
42
|
+
let phase: int = 0;
|
|
43
|
+
let frame: int = 0;
|
|
44
|
+
|
|
45
|
+
// 5 条曲线每 128 tick (~6.5 秒) 自动切换
|
|
46
|
+
@tick fn _wave_tick() {
|
|
47
|
+
phase = (phase + 4) % 360;
|
|
48
|
+
frame = frame + 1;
|
|
49
|
+
|
|
50
|
+
let curve_id: int = (frame / 128) % 5;
|
|
51
|
+
|
|
52
|
+
// 计算 9 列的 sin 值(每列相差 40°,刚好覆盖完整周期)
|
|
53
|
+
let s0: int = sin_fixed((phase + 0) % 360);
|
|
54
|
+
let s1: int = sin_fixed((phase + 40) % 360);
|
|
55
|
+
// ... s2 到 s8 ...
|
|
56
|
+
|
|
57
|
+
// 绘制图像:每条曲线有 64 个固定坐标粒子,每 tick 全部重绘
|
|
58
|
+
if (curve_id == 0) { _draw_xsinx(); }
|
|
59
|
+
if (curve_id == 1) { _draw_harmonic(); }
|
|
60
|
+
// ...
|
|
59
61
|
|
|
60
|
-
@
|
|
61
|
-
running = false;
|
|
62
|
-
say(f"Demo 已停止,共运行 {counter} ticks。");
|
|
62
|
+
actionbar(@a, f"§e y = x·sin(x) phase: {phase}° center: {s0}‰");
|
|
63
63
|
}
|
|
64
64
|
```
|
|
65
65
|
|
package/demo.gif
CHANGED
|
Binary file
|
|
@@ -77,7 +77,7 @@ describe('CLI API', () => {
|
|
|
77
77
|
const source = fs.readFileSync(mainPath, 'utf-8');
|
|
78
78
|
const result = (0, index_1.compile)(source, { namespace: 'mygame', filePath: mainPath });
|
|
79
79
|
const tickTimer = result.files.find(file => file.path.endsWith('/tick_timer.mcfunction'));
|
|
80
|
-
expect(tickTimer?.content).toContain('scoreboard players set #rs
|
|
80
|
+
expect(tickTimer?.content).toContain('scoreboard players set #rs __mygame.timer_ticks 1');
|
|
81
81
|
});
|
|
82
82
|
it('adds a call-site hash for stdlib internal scoreboard objectives', () => {
|
|
83
83
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-stdlib-hash-'));
|
|
@@ -125,8 +125,8 @@ describe('CLI API', () => {
|
|
|
125
125
|
const result = (0, index_1.compile)(source, { namespace: 'timernew', filePath: mainPath });
|
|
126
126
|
expect(result.typeErrors).toEqual([]);
|
|
127
127
|
const newFn = result.files.find(file => file.path.endsWith('/Timer_new.mcfunction'));
|
|
128
|
-
expect(newFn?.content).toContain('scoreboard players set timer_ticks
|
|
129
|
-
expect(newFn?.content).toContain('scoreboard players set timer_active
|
|
128
|
+
expect(newFn?.content).toContain('scoreboard players set timer_ticks __timernew 0');
|
|
129
|
+
expect(newFn?.content).toContain('scoreboard players set timer_active __timernew 0');
|
|
130
130
|
});
|
|
131
131
|
it('Timer.start/pause/reset', () => {
|
|
132
132
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-timer-state-'));
|
|
@@ -149,9 +149,9 @@ describe('CLI API', () => {
|
|
|
149
149
|
const startFn = result.files.find(file => file.path.endsWith('/Timer_start.mcfunction'));
|
|
150
150
|
const pauseFn = result.files.find(file => file.path.endsWith('/Timer_pause.mcfunction'));
|
|
151
151
|
const resetFn = result.files.find(file => file.path.endsWith('/Timer_reset.mcfunction'));
|
|
152
|
-
expect(startFn?.content).toContain('scoreboard players set timer_active
|
|
153
|
-
expect(pauseFn?.content).toContain('scoreboard players set timer_active
|
|
154
|
-
expect(resetFn?.content).toContain('scoreboard players set timer_ticks
|
|
152
|
+
expect(startFn?.content).toContain('scoreboard players set timer_active __timerstate 1');
|
|
153
|
+
expect(pauseFn?.content).toContain('scoreboard players set timer_active __timerstate 0');
|
|
154
|
+
expect(resetFn?.content).toContain('scoreboard players set timer_ticks __timerstate 0');
|
|
155
155
|
});
|
|
156
156
|
it('Timer.done returns bool', () => {
|
|
157
157
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-timer-done-'));
|
|
@@ -174,9 +174,9 @@ describe('CLI API', () => {
|
|
|
174
174
|
expect(result.typeErrors).toEqual([]);
|
|
175
175
|
const doneFn = result.files.find(file => file.path.endsWith('/Timer_done.mcfunction'));
|
|
176
176
|
const mainFn = result.files.find(file => file.path.endsWith('/main.mcfunction'));
|
|
177
|
-
expect(doneFn?.content).toContain('scoreboard players get timer_ticks
|
|
177
|
+
expect(doneFn?.content).toContain('scoreboard players get timer_ticks __timerdone');
|
|
178
178
|
expect(doneFn?.content).toContain('return run scoreboard players get');
|
|
179
|
-
expect(mainFn?.content).toContain('execute if score $main_finished
|
|
179
|
+
expect(mainFn?.content).toContain('execute if score $main_finished __timerdone matches 1..');
|
|
180
180
|
});
|
|
181
181
|
it('Timer.tick increments', () => {
|
|
182
182
|
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'redscript-timer-tick-'));
|
|
@@ -199,10 +199,10 @@ describe('CLI API', () => {
|
|
|
199
199
|
.filter(file => file.path.includes('/Timer_tick'))
|
|
200
200
|
.map(file => file.content)
|
|
201
201
|
.join('\n');
|
|
202
|
-
expect(tickOutput).toContain('scoreboard players get timer_active
|
|
203
|
-
expect(tickOutput).toContain('scoreboard players get timer_ticks
|
|
204
|
-
expect(tickOutput).toContain(' += $const_1
|
|
205
|
-
expect(tickOutput).toContain('execute store result score timer_ticks
|
|
202
|
+
expect(tickOutput).toContain('scoreboard players get timer_active __timertick');
|
|
203
|
+
expect(tickOutput).toContain('scoreboard players get timer_ticks __timertick');
|
|
204
|
+
expect(tickOutput).toContain(' += $const_1 __timertick');
|
|
205
|
+
expect(tickOutput).toContain('execute store result score timer_ticks __timertick run scoreboard players get $_');
|
|
206
206
|
});
|
|
207
207
|
});
|
|
208
208
|
describe('compile()', () => {
|
|
@@ -26,7 +26,7 @@ fn turret_tick() {
|
|
|
26
26
|
const result = (0, index_1.compile)(source, { namespace: 'test' });
|
|
27
27
|
const parent = getFileContent(result.files, 'data/test/function/turret_tick.mcfunction');
|
|
28
28
|
const loopBody = getFileContent(result.files, 'data/test/function/turret_tick/foreach_0.mcfunction');
|
|
29
|
-
const hoistedRead = 'execute store result score $_0
|
|
29
|
+
const hoistedRead = 'execute store result score $_0 __test run scoreboard players get config test.turret_range';
|
|
30
30
|
const executeCall = 'execute as @e[tag=turret] run function test:turret_tick/foreach_0';
|
|
31
31
|
expect(parent).toContain(hoistedRead);
|
|
32
32
|
expect(parent.indexOf(hoistedRead)).toBeLessThan(parent.indexOf(executeCall));
|
|
@@ -48,7 +48,7 @@ fn read_twice() {
|
|
|
48
48
|
const fn = getFileContent(result.files, 'data/test/function/read_twice.mcfunction');
|
|
49
49
|
const readMatches = fn.match(/scoreboard players get @s test\.coins/g) ?? [];
|
|
50
50
|
expect(readMatches).toHaveLength(1);
|
|
51
|
-
expect(fn).toContain('scoreboard players operation $_1
|
|
51
|
+
expect(fn).toContain('scoreboard players operation $_1 __test = $_0 __test');
|
|
52
52
|
});
|
|
53
53
|
test('reuses duplicate arithmetic sequences', () => {
|
|
54
54
|
const source = `
|
|
@@ -63,9 +63,9 @@ fn math() {
|
|
|
63
63
|
`;
|
|
64
64
|
const result = (0, index_1.compile)(source, { namespace: 'test' });
|
|
65
65
|
const fn = getFileContent(result.files, 'data/test/function/math.mcfunction');
|
|
66
|
-
const addMatches = fn.match(/\+= \$const_2
|
|
66
|
+
const addMatches = fn.match(/\+= \$const_2 __test/g) ?? [];
|
|
67
67
|
expect(addMatches).toHaveLength(1);
|
|
68
|
-
expect(fn).toContain('scoreboard players operation $_1
|
|
68
|
+
expect(fn).toContain('scoreboard players operation $_1 __test = $_0 __test');
|
|
69
69
|
});
|
|
70
70
|
});
|
|
71
71
|
describe('setblock batching', () => {
|
package/dist/compile.d.ts
CHANGED
|
@@ -14,8 +14,9 @@ export interface CompileOptions {
|
|
|
14
14
|
dce?: boolean;
|
|
15
15
|
mangle?: boolean;
|
|
16
16
|
/** Scoreboard objective used for all variable slots.
|
|
17
|
-
* Defaults to '
|
|
18
|
-
*
|
|
17
|
+
* Defaults to '__<namespace>' (e.g. '__mathshow') — the double-underscore
|
|
18
|
+
* prefix signals compiler-internal and avoids occupying the user's namespace.
|
|
19
|
+
* Each datapack gets a unique objective automatically; no manual setup needed. */
|
|
19
20
|
scoreboardObjective?: string;
|
|
20
21
|
/** Additional source files that should be treated as *library* code.
|
|
21
22
|
* Functions in these files are DCE-eligible: they are only compiled into
|
package/dist/compile.js
CHANGED
|
@@ -212,7 +212,7 @@ function compile(source, options = {}) {
|
|
|
212
212
|
// Configure scoreboard objective for this compilation.
|
|
213
213
|
// Default: use the datapack namespace so each datapack gets its own objective
|
|
214
214
|
// automatically, preventing variable collisions when multiple datapacks coexist.
|
|
215
|
-
const scoreboardObj = options.scoreboardObjective ?? namespace
|
|
215
|
+
const scoreboardObj = options.scoreboardObjective ?? `__${namespace}`;
|
|
216
216
|
(0, lowering_1.setScoreboardObjective)(scoreboardObj);
|
|
217
217
|
// Lowering
|
|
218
218
|
const ir = new lowering_1.Lowering(namespace, preprocessed.ranges).lower(ast);
|
package/dist/index.d.ts
CHANGED
|
@@ -17,9 +17,10 @@ export interface CompileOptions {
|
|
|
17
17
|
filePath?: string;
|
|
18
18
|
dce?: boolean;
|
|
19
19
|
mangle?: boolean;
|
|
20
|
-
/** Scoreboard objective used for all variable slots
|
|
21
|
-
*
|
|
22
|
-
* RedScript datapacks are loaded simultaneously
|
|
20
|
+
/** Scoreboard objective used for all variable slots.
|
|
21
|
+
* Defaults to '__<namespace>' (e.g. '__mathshow') to avoid collisions when
|
|
22
|
+
* multiple RedScript datapacks are loaded simultaneously, without occupying
|
|
23
|
+
* the user's own namespace. Override only if you need a specific name. */
|
|
23
24
|
scoreboardObjective?: string;
|
|
24
25
|
}
|
|
25
26
|
export interface CompileResult {
|
package/dist/index.js
CHANGED
|
@@ -69,7 +69,7 @@ function compile(source, options = {}) {
|
|
|
69
69
|
// Configure scoreboard objective for this compilation.
|
|
70
70
|
// Default: use the datapack namespace so each datapack gets its own objective
|
|
71
71
|
// automatically, preventing variable collisions when multiple datapacks coexist.
|
|
72
|
-
const scoreboardObj = options.scoreboardObjective ?? namespace
|
|
72
|
+
const scoreboardObj = options.scoreboardObjective ?? `__${namespace}`;
|
|
73
73
|
(0, lowering_1.setScoreboardObjective)(scoreboardObj);
|
|
74
74
|
// Lowering to IR
|
|
75
75
|
const lowering = new lowering_1.Lowering(namespace, preprocessed.ranges);
|
package/dist/lexer/index.js
CHANGED
|
@@ -236,9 +236,17 @@ class Lexer {
|
|
|
236
236
|
this.addToken('rel_coord', value, startLine, startCol);
|
|
237
237
|
return;
|
|
238
238
|
}
|
|
239
|
-
// Local coordinate: ^ or ^5 or ^-3 or ^0.5
|
|
239
|
+
// Local coordinate: ^ or ^5 or ^-3 or ^0.5 or ^varname (macro variable)
|
|
240
240
|
if (char === '^') {
|
|
241
241
|
let value = '^';
|
|
242
|
+
// Check for identifier (variable name for macro substitution, e.g. ^px, ^height)
|
|
243
|
+
if (/[a-zA-Z_]/.test(this.peek())) {
|
|
244
|
+
while (/[a-zA-Z0-9_]/.test(this.peek())) {
|
|
245
|
+
value += this.advance();
|
|
246
|
+
}
|
|
247
|
+
this.addToken('local_coord', value, startLine, startCol);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
242
250
|
// Check for optional sign
|
|
243
251
|
if (this.peek() === '-' || this.peek() === '+') {
|
|
244
252
|
value += this.advance();
|
package/dist/lowering/index.js
CHANGED
|
@@ -495,16 +495,31 @@ class Lowering {
|
|
|
495
495
|
}
|
|
496
496
|
}
|
|
497
497
|
// Set up NBT storage for each macro param
|
|
498
|
+
// float-typed params are stored as `double 0.01` so that an integer value N
|
|
499
|
+
// becomes N/100.0 in the command (e.g. scoreboard value 975 → NBT 9.75d → ^9.75)
|
|
498
500
|
for (const macroParam of macroParamNames) {
|
|
499
501
|
const paramIdx = params.findIndex(p => p.name === macroParam);
|
|
500
502
|
if (paramIdx < 0 || paramIdx >= loweredArgs.length)
|
|
501
503
|
continue;
|
|
502
504
|
const operand = loweredArgs[paramIdx];
|
|
505
|
+
const paramType = params[paramIdx]?.type;
|
|
506
|
+
const isFloat = paramType?.kind === 'named' && paramType.name === 'float';
|
|
503
507
|
if (operand.kind === 'const') {
|
|
504
|
-
|
|
508
|
+
if (isFloat) {
|
|
509
|
+
const floatVal = (operand.value / 100).toFixed(6);
|
|
510
|
+
this.builder.emitRaw(`data modify storage rs:macro_args ${macroParam} set value ${floatVal}d`);
|
|
511
|
+
}
|
|
512
|
+
else {
|
|
513
|
+
this.builder.emitRaw(`data modify storage rs:macro_args ${macroParam} set value ${operand.value}`);
|
|
514
|
+
}
|
|
505
515
|
}
|
|
506
516
|
else if (operand.kind === 'var') {
|
|
507
|
-
|
|
517
|
+
if (isFloat) {
|
|
518
|
+
this.builder.emitRaw(`execute store result storage rs:macro_args ${macroParam} double 0.01 run scoreboard players get ${operand.name} ${exports.LOWERING_OBJ}`);
|
|
519
|
+
}
|
|
520
|
+
else {
|
|
521
|
+
this.builder.emitRaw(`execute store result storage rs:macro_args ${macroParam} int 1 run scoreboard players get ${operand.name} ${exports.LOWERING_OBJ}`);
|
|
522
|
+
}
|
|
508
523
|
}
|
|
509
524
|
}
|
|
510
525
|
// Call with macro storage
|