redscript-mc 1.2.27 → 1.2.28

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.
@@ -39,7 +39,8 @@ var __importStar = (this && this.__importStar) || (function () {
39
39
  };
40
40
  })();
41
41
  Object.defineProperty(exports, "__esModule", { value: true });
42
- exports.Lowering = void 0;
42
+ exports.Lowering = exports.LOWERING_OBJ = void 0;
43
+ exports.setScoreboardObjective = setScoreboardObjective;
43
44
  const builder_1 = require("../ir/builder");
44
45
  const diagnostics_1 = require("../diagnostics");
45
46
  const path = __importStar(require("path"));
@@ -54,6 +55,13 @@ const entity_hierarchy_1 = require("../types/entity-hierarchy");
54
55
  // All builtins support macro parameters - any arg that's a function param
55
56
  // will automatically use MC 1.20.2+ macro syntax when needed
56
57
  // ---------------------------------------------------------------------------
58
+ // Scoreboard Objective
59
+ // Set per-compilation via setScoreboardObjective() — defaults to 'rs'.
60
+ // ---------------------------------------------------------------------------
61
+ /** Current scoreboard objective. Set once per compile() call. */
62
+ exports.LOWERING_OBJ = 'rs';
63
+ function setScoreboardObjective(obj) { exports.LOWERING_OBJ = obj; }
64
+ // ---------------------------------------------------------------------------
57
65
  // Builtin Functions
58
66
  // ---------------------------------------------------------------------------
59
67
  const BUILTINS = {
@@ -73,9 +81,13 @@ const BUILTINS = {
73
81
  const pos = [x ?? '~', y ?? '~', z ?? '~'].join(' ');
74
82
  return nbt ? `summon ${type} ${pos} ${nbt}` : `summon ${type} ${pos}`;
75
83
  },
76
- particle: ([name, x, y, z]) => {
84
+ particle: ([name, x, y, z, dx, dy, dz, speed, count]) => {
77
85
  const pos = [x ?? '~', y ?? '~', z ?? '~'].join(' ');
78
- return `particle ${name} ${pos}`;
86
+ // dx/dy/dz/speed/count are optional; omit trailing undefineds
87
+ const extra = [dx, dy, dz, speed, count].filter(v => v !== undefined && v !== null);
88
+ return extra.length > 0
89
+ ? `particle ${name} ${pos} ${extra.join(' ')}`
90
+ : `particle ${name} ${pos}`;
79
91
  },
80
92
  playsound: ([sound, source, sel, x, y, z, volume, pitch, minVolume]) => ['playsound', sound, source, sel, x, y, z, volume, pitch, minVolume].filter(Boolean).join(' '),
81
93
  tp: () => null, // Special handling
@@ -453,6 +465,16 @@ class Lowering {
453
465
  if (expr.kind === 'struct_lit' || expr.kind === 'array_lit') {
454
466
  return { str: this.exprToSnbt(expr) };
455
467
  }
468
+ // Float literals: preserve the float value for MC commands that accept floats
469
+ // (particle spread, playsound volume/pitch, etc.)
470
+ // We do NOT truncate here — that only applies to scoreboard/IR contexts.
471
+ if (expr.kind === 'float_lit') {
472
+ return { str: expr.value.toString() };
473
+ }
474
+ // Unary minus applied to a float literal (e.g. -0.5)
475
+ if (expr.kind === 'unary' && expr.op === '-' && expr.operand.kind === 'float_lit') {
476
+ return { str: (-expr.operand.value).toString() };
477
+ }
456
478
  return { str: this.exprToString(expr) };
457
479
  }
458
480
  /**
@@ -466,10 +488,10 @@ class Lowering {
466
488
  for (let i = 0; i < loweredArgs.length; i++) {
467
489
  const operand = loweredArgs[i];
468
490
  if (operand.kind === 'const') {
469
- this.builder.emitRaw(`scoreboard players set $p${i} rs ${operand.value}`);
491
+ this.builder.emitRaw(`scoreboard players set $p${i} ${exports.LOWERING_OBJ} ${operand.value}`);
470
492
  }
471
493
  else if (operand.kind === 'var') {
472
- this.builder.emitRaw(`scoreboard players operation $p${i} rs = ${operand.name} rs`);
494
+ this.builder.emitRaw(`scoreboard players operation $p${i} ${exports.LOWERING_OBJ} = ${operand.name} ${exports.LOWERING_OBJ}`);
473
495
  }
474
496
  }
475
497
  // Set up NBT storage for each macro param
@@ -482,14 +504,14 @@ class Lowering {
482
504
  this.builder.emitRaw(`data modify storage rs:macro_args ${macroParam} set value ${operand.value}`);
483
505
  }
484
506
  else if (operand.kind === 'var') {
485
- this.builder.emitRaw(`execute store result storage rs:macro_args ${macroParam} int 1 run scoreboard players get ${operand.name} rs`);
507
+ this.builder.emitRaw(`execute store result storage rs:macro_args ${macroParam} int 1 run scoreboard players get ${operand.name} ${exports.LOWERING_OBJ}`);
486
508
  }
487
509
  }
488
510
  // Call with macro storage
489
511
  this.builder.emitRaw(`function ${this.namespace}:${fnName} with storage rs:macro_args`);
490
512
  // Copy return value (callers may use it)
491
513
  const dst = this.builder.freshTemp();
492
- this.builder.emitRaw(`scoreboard players operation ${dst} rs = $ret rs`);
514
+ this.builder.emitRaw(`scoreboard players operation ${dst} ${exports.LOWERING_OBJ} = $ret ${exports.LOWERING_OBJ}`);
493
515
  return { kind: 'var', name: dst };
494
516
  }
495
517
  lower(program) {
@@ -723,7 +745,7 @@ class Lowering {
723
745
  const originalInstrs = [...entry.instrs];
724
746
  const originalTerm = entry.term;
725
747
  entry.instrs = [
726
- { op: 'raw', cmd: `scoreboard players add ${counterVar} rs 1` },
748
+ { op: 'raw', cmd: `scoreboard players add ${counterVar} ${exports.LOWERING_OBJ} 1` },
727
749
  ];
728
750
  // Create conditional jump
729
751
  const bodyLabel = 'tick_body';
@@ -737,13 +759,13 @@ class Lowering {
737
759
  // Add check instruction
738
760
  entry.instrs.push({
739
761
  op: 'raw',
740
- cmd: `execute store success score ${counterVar}_check rs if score ${counterVar} rs matches ${rate}..`,
762
+ cmd: `execute store success score ${counterVar}_check ${exports.LOWERING_OBJ} if score ${counterVar} ${exports.LOWERING_OBJ} matches ${rate}..`,
741
763
  });
742
764
  // Body block (original logic + counter reset)
743
765
  fn.blocks.push({
744
766
  label: bodyLabel,
745
767
  instrs: [
746
- { op: 'raw', cmd: `scoreboard players set ${counterVar} rs 0` },
768
+ { op: 'raw', cmd: `scoreboard players set ${counterVar} ${exports.LOWERING_OBJ} 0` },
747
769
  ...originalInstrs,
748
770
  ],
749
771
  term: originalTerm,
@@ -857,7 +879,7 @@ class Lowering {
857
879
  }
858
880
  else if (fieldValue.kind === 'var') {
859
881
  // Copy from scoreboard to NBT
860
- this.builder.emitRaw(`execute store result storage ${path} int 1 run scoreboard players get ${fieldValue.name} rs`);
882
+ this.builder.emitRaw(`execute store result storage ${path} int 1 run scoreboard players get ${fieldValue.name} ${exports.LOWERING_OBJ}`);
861
883
  }
862
884
  }
863
885
  return;
@@ -890,7 +912,7 @@ class Lowering {
890
912
  }
891
913
  else if (elemValue.kind === 'var') {
892
914
  this.builder.emitRaw(`data modify storage rs:heap ${stmt.name} append value 0`);
893
- this.builder.emitRaw(`execute store result storage rs:heap ${stmt.name}[-1] int 1 run scoreboard players get ${elemValue.name} rs`);
915
+ this.builder.emitRaw(`execute store result storage rs:heap ${stmt.name}[-1] int 1 run scoreboard players get ${elemValue.name} ${exports.LOWERING_OBJ}`);
894
916
  }
895
917
  }
896
918
  return;
@@ -936,7 +958,7 @@ class Lowering {
936
958
  this.builder.emitRaw(`data modify storage ${path} set value ${fieldValue.value}`);
937
959
  }
938
960
  else if (fieldValue.kind === 'var') {
939
- this.builder.emitRaw(`execute store result storage ${path} int 1 run scoreboard players get ${fieldValue.name} rs`);
961
+ this.builder.emitRaw(`execute store result storage ${path} int 1 run scoreboard players get ${fieldValue.name} ${exports.LOWERING_OBJ}`);
940
962
  }
941
963
  }
942
964
  this.builder.emitReturn({ kind: 'const', value: 0 });
@@ -1103,10 +1125,10 @@ class Lowering {
1103
1125
  this.varMap.set(stmt.varName, loopVar);
1104
1126
  const startVal = this.lowerExpr(stmt.start);
1105
1127
  if (startVal.kind === 'const') {
1106
- this.builder.emitRaw(`scoreboard players set ${loopVar} rs ${startVal.value}`);
1128
+ this.builder.emitRaw(`scoreboard players set ${loopVar} ${exports.LOWERING_OBJ} ${startVal.value}`);
1107
1129
  }
1108
1130
  else if (startVal.kind === 'var') {
1109
- this.builder.emitRaw(`scoreboard players operation ${loopVar} rs = ${startVal.name} rs`);
1131
+ this.builder.emitRaw(`scoreboard players operation ${loopVar} ${exports.LOWERING_OBJ} = ${startVal.name} ${exports.LOWERING_OBJ}`);
1110
1132
  }
1111
1133
  // Call loop function
1112
1134
  this.builder.emitRaw(`function ${this.namespace}:${subFnName}`);
@@ -1123,11 +1145,11 @@ class Lowering {
1123
1145
  // Body
1124
1146
  this.lowerBlock(stmt.body);
1125
1147
  // Increment
1126
- this.builder.emitRaw(`scoreboard players add ${loopVar} rs 1`);
1148
+ this.builder.emitRaw(`scoreboard players add ${loopVar} ${exports.LOWERING_OBJ} 1`);
1127
1149
  // Loop condition: execute if score matches ..<end-1> run function
1128
1150
  const endVal = this.lowerExpr(stmt.end);
1129
1151
  const endNum = endVal.kind === 'const' ? endVal.value - 1 : '?';
1130
- this.builder.emitRaw(`execute if score ${loopVar} rs matches ..${endNum} run function ${this.namespace}:${subFnName}`);
1152
+ this.builder.emitRaw(`execute if score ${loopVar} ${exports.LOWERING_OBJ} matches ..${endNum} run function ${this.namespace}:${subFnName}`);
1131
1153
  if (!this.builder.isBlockSealed()) {
1132
1154
  this.builder.emitReturn();
1133
1155
  }
@@ -1217,12 +1239,12 @@ class Lowering {
1217
1239
  matchCondition = String(patternValue.value);
1218
1240
  }
1219
1241
  const subFnName = `${this.currentFn}/match_${this.foreachCounter++}`;
1220
- this.builder.emitRaw(`execute if score ${matchedVar} rs matches ..0 if score ${subject} rs matches ${matchCondition} run function ${this.namespace}:${subFnName}`);
1242
+ this.builder.emitRaw(`execute if score ${matchedVar} ${exports.LOWERING_OBJ} matches ..0 if score ${subject} ${exports.LOWERING_OBJ} matches ${matchCondition} run function ${this.namespace}:${subFnName}`);
1221
1243
  this.emitMatchArmSubFunction(subFnName, matchedVar, arm.body, true);
1222
1244
  }
1223
1245
  if (defaultArm) {
1224
1246
  const subFnName = `${this.currentFn}/match_${this.foreachCounter++}`;
1225
- this.builder.emitRaw(`execute if score ${matchedVar} rs matches ..0 run function ${this.namespace}:${subFnName}`);
1247
+ this.builder.emitRaw(`execute if score ${matchedVar} ${exports.LOWERING_OBJ} matches ..0 run function ${this.namespace}:${subFnName}`);
1226
1248
  this.emitMatchArmSubFunction(subFnName, matchedVar, defaultArm.body, false);
1227
1249
  }
1228
1250
  }
@@ -1237,7 +1259,7 @@ class Lowering {
1237
1259
  this.blockPosVars = new Map(savedBlockPosVars);
1238
1260
  this.builder.startBlock('entry');
1239
1261
  if (setMatched) {
1240
- this.builder.emitRaw(`scoreboard players set ${matchedVar} rs 1`);
1262
+ this.builder.emitRaw(`scoreboard players set ${matchedVar} ${exports.LOWERING_OBJ} 1`);
1241
1263
  }
1242
1264
  this.lowerBlock(body);
1243
1265
  if (!this.builder.isBlockSealed()) {
@@ -1269,7 +1291,7 @@ class Lowering {
1269
1291
  }
1270
1292
  this.builder.emitAssign(indexVar, { kind: 'const', value: 0 });
1271
1293
  this.builder.emitAssign(oneVar, { kind: 'const', value: 1 });
1272
- this.builder.emitRaw(`execute store result score ${lengthVar} rs run data get storage rs:heap ${arrayName}`);
1294
+ this.builder.emitRaw(`execute store result score ${lengthVar} ${exports.LOWERING_OBJ} run data get storage rs:heap ${arrayName}`);
1273
1295
  const checkLabel = this.builder.freshLabel('foreach_array_check');
1274
1296
  const bodyLabel = this.builder.freshLabel('foreach_array_body');
1275
1297
  const exitLabel = this.builder.freshLabel('foreach_array_exit');
@@ -1282,7 +1304,7 @@ class Lowering {
1282
1304
  this.builder.emitAssign(bindingVar, element);
1283
1305
  this.lowerBlock(stmt.body);
1284
1306
  if (!this.builder.isBlockSealed()) {
1285
- this.builder.emitRaw(`scoreboard players operation ${indexVar} rs += ${oneVar} rs`);
1307
+ this.builder.emitRaw(`scoreboard players operation ${indexVar} ${exports.LOWERING_OBJ} += ${oneVar} ${exports.LOWERING_OBJ}`);
1286
1308
  this.builder.emitJump(checkLabel);
1287
1309
  }
1288
1310
  this.builder.startBlock(exitLabel);
@@ -1596,7 +1618,7 @@ class Lowering {
1596
1618
  if (mapped && mapped.startsWith('@e[tag=__rs_obj_')) {
1597
1619
  // World object field access → scoreboard get
1598
1620
  const dst = this.builder.freshTemp();
1599
- this.builder.emitRaw(`scoreboard players operation ${dst} rs = ${mapped} rs`);
1621
+ this.builder.emitRaw(`scoreboard players operation ${dst} ${exports.LOWERING_OBJ} = ${mapped} ${exports.LOWERING_OBJ}`);
1600
1622
  return { kind: 'var', name: dst };
1601
1623
  }
1602
1624
  if (varType?.kind === 'struct') {
@@ -1604,13 +1626,13 @@ class Lowering {
1604
1626
  const path = `rs:heap ${structName}_${expr.obj.name}.${expr.field}`;
1605
1627
  const dst = this.builder.freshTemp();
1606
1628
  // Read from NBT storage into scoreboard
1607
- this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${path}`);
1629
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} run data get storage ${path}`);
1608
1630
  return { kind: 'var', name: dst };
1609
1631
  }
1610
1632
  // Array length property
1611
1633
  if (varType?.kind === 'array' && expr.field === 'len') {
1612
1634
  const dst = this.builder.freshTemp();
1613
- this.builder.emitRaw(`execute store result score ${dst} rs run data get storage rs:heap ${expr.obj.name}`);
1635
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} run data get storage rs:heap ${expr.obj.name}`);
1614
1636
  return { kind: 'var', name: dst };
1615
1637
  }
1616
1638
  }
@@ -1626,10 +1648,10 @@ class Lowering {
1626
1648
  const value = this.lowerExpr(expr.value);
1627
1649
  if (expr.op === '=') {
1628
1650
  if (value.kind === 'const') {
1629
- this.builder.emitRaw(`scoreboard players set ${mapped} rs ${value.value}`);
1651
+ this.builder.emitRaw(`scoreboard players set ${mapped} ${exports.LOWERING_OBJ} ${value.value}`);
1630
1652
  }
1631
1653
  else if (value.kind === 'var') {
1632
- this.builder.emitRaw(`scoreboard players operation ${mapped} rs = ${value.name} rs`);
1654
+ this.builder.emitRaw(`scoreboard players operation ${mapped} ${exports.LOWERING_OBJ} = ${value.name} ${exports.LOWERING_OBJ}`);
1633
1655
  }
1634
1656
  }
1635
1657
  else {
@@ -1639,10 +1661,10 @@ class Lowering {
1639
1661
  if (value.kind === 'const') {
1640
1662
  const constTemp = this.builder.freshTemp();
1641
1663
  this.builder.emitAssign(constTemp, value);
1642
- this.builder.emitRaw(`scoreboard players operation ${mapped} rs ${opMap[binOp]} ${constTemp} rs`);
1664
+ this.builder.emitRaw(`scoreboard players operation ${mapped} ${exports.LOWERING_OBJ} ${opMap[binOp]} ${constTemp} ${exports.LOWERING_OBJ}`);
1643
1665
  }
1644
1666
  else if (value.kind === 'var') {
1645
- this.builder.emitRaw(`scoreboard players operation ${mapped} rs ${opMap[binOp]} ${value.name} rs`);
1667
+ this.builder.emitRaw(`scoreboard players operation ${mapped} ${exports.LOWERING_OBJ} ${opMap[binOp]} ${value.name} ${exports.LOWERING_OBJ}`);
1646
1668
  }
1647
1669
  }
1648
1670
  return { kind: 'const', value: 0 };
@@ -1656,16 +1678,16 @@ class Lowering {
1656
1678
  this.builder.emitRaw(`data modify storage ${path} set value ${value.value}`);
1657
1679
  }
1658
1680
  else if (value.kind === 'var') {
1659
- this.builder.emitRaw(`execute store result storage ${path} int 1 run scoreboard players get ${value.name} rs`);
1681
+ this.builder.emitRaw(`execute store result storage ${path} int 1 run scoreboard players get ${value.name} ${exports.LOWERING_OBJ}`);
1660
1682
  }
1661
1683
  }
1662
1684
  else {
1663
1685
  // Compound assignment: read, modify, write back
1664
1686
  const dst = this.builder.freshTemp();
1665
- this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${path}`);
1687
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} run data get storage ${path}`);
1666
1688
  const binOp = expr.op.slice(0, -1);
1667
1689
  this.builder.emitBinop(dst, { kind: 'var', name: dst }, binOp, value);
1668
- this.builder.emitRaw(`execute store result storage ${path} int 1 run scoreboard players get ${dst} rs`);
1690
+ this.builder.emitRaw(`execute store result storage ${path} int 1 run scoreboard players get ${dst} ${exports.LOWERING_OBJ}`);
1669
1691
  }
1670
1692
  return { kind: 'const', value: 0 };
1671
1693
  }
@@ -1694,14 +1716,14 @@ class Lowering {
1694
1716
  this.builder.emitAssign(dst, left);
1695
1717
  const rightVar = this.operandToVar(right);
1696
1718
  // dst = dst && right → if dst != 0 then dst = right
1697
- this.builder.emitRaw(`execute if score ${dst} rs matches 1.. run scoreboard players operation ${dst} rs = ${rightVar} rs`);
1719
+ this.builder.emitRaw(`execute if score ${dst} ${exports.LOWERING_OBJ} matches 1.. run scoreboard players operation ${dst} ${exports.LOWERING_OBJ} = ${rightVar} ${exports.LOWERING_OBJ}`);
1698
1720
  }
1699
1721
  else {
1700
1722
  // Short-circuit OR
1701
1723
  this.builder.emitAssign(dst, left);
1702
1724
  const rightVar = this.operandToVar(right);
1703
1725
  // dst = dst || right → if dst == 0 then dst = right
1704
- this.builder.emitRaw(`execute if score ${dst} rs matches ..0 run scoreboard players operation ${dst} rs = ${rightVar} rs`);
1726
+ this.builder.emitRaw(`execute if score ${dst} ${exports.LOWERING_OBJ} matches ..0 run scoreboard players operation ${dst} ${exports.LOWERING_OBJ} = ${rightVar} ${exports.LOWERING_OBJ}`);
1705
1727
  }
1706
1728
  return { kind: 'var', name: dst };
1707
1729
  }
@@ -1719,16 +1741,16 @@ class Lowering {
1719
1741
  // Divide by 1000 to correct for double scaling
1720
1742
  const constDiv = this.builder.freshTemp();
1721
1743
  this.builder.emitAssign(constDiv, { kind: 'const', value: 1000 });
1722
- this.builder.emitRaw(`scoreboard players operation ${dst} rs /= ${constDiv} rs`);
1744
+ this.builder.emitRaw(`scoreboard players operation ${dst} ${exports.LOWERING_OBJ} /= ${constDiv} ${exports.LOWERING_OBJ}`);
1723
1745
  }
1724
1746
  else {
1725
1747
  // Division: a * 1000 / b
1726
1748
  const constMul = this.builder.freshTemp();
1727
1749
  this.builder.emitAssign(constMul, { kind: 'const', value: 1000 });
1728
1750
  this.builder.emitAssign(dst, left);
1729
- this.builder.emitRaw(`scoreboard players operation ${dst} rs *= ${constMul} rs`);
1751
+ this.builder.emitRaw(`scoreboard players operation ${dst} ${exports.LOWERING_OBJ} *= ${constMul} ${exports.LOWERING_OBJ}`);
1730
1752
  const rightVar = this.operandToVar(right);
1731
- this.builder.emitRaw(`scoreboard players operation ${dst} rs /= ${rightVar} rs`);
1753
+ this.builder.emitRaw(`scoreboard players operation ${dst} ${exports.LOWERING_OBJ} /= ${rightVar} ${exports.LOWERING_OBJ}`);
1732
1754
  }
1733
1755
  return { kind: 'var', name: dst };
1734
1756
  }
@@ -1798,7 +1820,7 @@ class Lowering {
1798
1820
  const storagePath = this.getStringStoragePath(expr.args[0]);
1799
1821
  if (storagePath) {
1800
1822
  const dst = this.builder.freshTemp();
1801
- this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${storagePath}`);
1823
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} run data get storage ${storagePath}`);
1802
1824
  return { kind: 'var', name: dst };
1803
1825
  }
1804
1826
  const staticString = this.resolveStaticString(expr.args[0]);
@@ -1832,7 +1854,7 @@ class Lowering {
1832
1854
  const entity = this.exprToString(expr.args[0]);
1833
1855
  const tagName = this.exprToString(expr.args[1]);
1834
1856
  const dst = this.builder.freshTemp();
1835
- this.builder.emitRaw(`execute store result score ${dst} rs if entity ${entity}[tag=${tagName}]`);
1857
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} if entity ${entity}[tag=${tagName}]`);
1836
1858
  return { kind: 'var', name: dst };
1837
1859
  }
1838
1860
  // Handle array push
@@ -1847,7 +1869,7 @@ class Lowering {
1847
1869
  }
1848
1870
  else if (value.kind === 'var') {
1849
1871
  this.builder.emitRaw(`data modify storage rs:heap ${arrName} append value 0`);
1850
- this.builder.emitRaw(`execute store result storage rs:heap ${arrName}[-1] int 1 run scoreboard players get ${value.name} rs`);
1872
+ this.builder.emitRaw(`execute store result storage rs:heap ${arrName}[-1] int 1 run scoreboard players get ${value.name} ${exports.LOWERING_OBJ}`);
1851
1873
  }
1852
1874
  }
1853
1875
  return { kind: 'const', value: 0 };
@@ -1856,7 +1878,7 @@ class Lowering {
1856
1878
  const arrName = this.getArrayStorageName(expr.args[0]);
1857
1879
  const dst = this.builder.freshTemp();
1858
1880
  if (arrName) {
1859
- this.builder.emitRaw(`execute store result score ${dst} rs run data get storage rs:heap ${arrName}[-1]`);
1881
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} run data get storage rs:heap ${arrName}[-1]`);
1860
1882
  this.builder.emitRaw(`data remove storage rs:heap ${arrName}[-1]`);
1861
1883
  }
1862
1884
  else {
@@ -2120,7 +2142,7 @@ class Lowering {
2120
2142
  const dst = this.builder.freshTemp();
2121
2143
  const min = args[0] ? this.exprToLiteral(args[0]) : '0';
2122
2144
  const max = args[1] ? this.exprToLiteral(args[1]) : '100';
2123
- this.builder.emitRaw(`scoreboard players random ${dst} rs ${min} ${max}`);
2145
+ this.builder.emitRaw(`scoreboard players random ${dst} ${exports.LOWERING_OBJ} ${min} ${max}`);
2124
2146
  return { kind: 'var', name: dst };
2125
2147
  }
2126
2148
  // Special case: random_native - /random value (MC 1.20.3+)
@@ -2128,7 +2150,7 @@ class Lowering {
2128
2150
  const dst = this.builder.freshTemp();
2129
2151
  const min = args[0] ? this.exprToLiteral(args[0]) : '0';
2130
2152
  const max = args[1] ? this.exprToLiteral(args[1]) : '100';
2131
- this.builder.emitRaw(`execute store result score ${dst} rs run random value ${min} ${max}`);
2153
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} run random value ${min} ${max}`);
2132
2154
  return { kind: 'var', name: dst };
2133
2155
  }
2134
2156
  // Special case: random_sequence - /random reset (MC 1.20.3+)
@@ -2143,7 +2165,7 @@ class Lowering {
2143
2165
  const dst = this.builder.freshTemp();
2144
2166
  const player = this.exprToTargetString(args[0]);
2145
2167
  const objective = this.resolveScoreboardObjective(args[0], args[1], callSpan);
2146
- this.builder.emitRaw(`execute store result score ${dst} rs run scoreboard players get ${player} ${objective}`);
2168
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} run scoreboard players get ${player} ${objective}`);
2147
2169
  return { kind: 'var', name: dst };
2148
2170
  }
2149
2171
  // Special case: scoreboard_set — write to vanilla MC scoreboard
@@ -2157,7 +2179,7 @@ class Lowering {
2157
2179
  else if (value.kind === 'var') {
2158
2180
  // Read directly from the computed scoreboard temp. Routing through a fresh
2159
2181
  // temp here breaks once optimization removes the apparently-dead assign.
2160
- this.builder.emitRaw(`execute store result score ${player} ${objective} run scoreboard players get ${value.name} rs`);
2182
+ this.builder.emitRaw(`execute store result score ${player} ${objective} run scoreboard players get ${value.name} ${exports.LOWERING_OBJ}`);
2161
2183
  }
2162
2184
  return { kind: 'const', value: 0 };
2163
2185
  }
@@ -2220,7 +2242,7 @@ class Lowering {
2220
2242
  }
2221
2243
  if (name === 'bossbar_get_value') {
2222
2244
  const dst = this.builder.freshTemp();
2223
- this.builder.emitRaw(`execute store result score ${dst} rs run bossbar get ${this.exprToString(args[0])} value`);
2245
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} run bossbar get ${this.exprToString(args[0])} value`);
2224
2246
  return { kind: 'var', name: dst };
2225
2247
  }
2226
2248
  if (name === 'team_add') {
@@ -2261,7 +2283,7 @@ class Lowering {
2261
2283
  : this.exprToString(args[1]);
2262
2284
  const path = this.exprToString(args[2]);
2263
2285
  const scale = args[3] ? this.exprToString(args[3]) : '1';
2264
- this.builder.emitRaw(`execute store result score ${dst} rs run data get ${targetType} ${target} ${path} ${scale}`);
2286
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} run data get ${targetType} ${target} ${path} ${scale}`);
2265
2287
  return { kind: 'var', name: dst };
2266
2288
  }
2267
2289
  // storage_get_int(storage_ns, array_key, index) -> int
@@ -2270,7 +2292,7 @@ class Lowering {
2270
2292
  // array_key : e.g. "sin"
2271
2293
  // index : integer index (const or runtime)
2272
2294
  //
2273
- // Const index: execute store result score $dst rs run data get storage math:tables sin[N] 1
2295
+ // Const index: execute store result score $dst ${LOWERING_OBJ} run data get storage math:tables sin[N] 1
2274
2296
  // Runtime index: macro sub-function via rs:heap, mirrors readArrayElement.
2275
2297
  if (name === 'storage_get_int') {
2276
2298
  const storageNs = this.exprToString(args[0]); // "math:tables"
@@ -2278,7 +2300,7 @@ class Lowering {
2278
2300
  const indexOperand = this.lowerExpr(args[2]);
2279
2301
  const dst = this.builder.freshTemp();
2280
2302
  if (indexOperand.kind === 'const') {
2281
- this.builder.emitRaw(`execute store result score ${dst} rs run data get storage ${storageNs} ${arrayKey}[${indexOperand.value}] 1`);
2303
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} run data get storage ${storageNs} ${arrayKey}[${indexOperand.value}] 1`);
2282
2304
  }
2283
2305
  else {
2284
2306
  // Runtime index: store the index into rs:heap under a unique key,
@@ -2288,13 +2310,13 @@ class Lowering {
2288
2310
  const indexVar = indexOperand.kind === 'var'
2289
2311
  ? indexOperand.name
2290
2312
  : this.operandToVar(indexOperand);
2291
- this.builder.emitRaw(`execute store result storage rs:heap ${macroKey} int 1 run scoreboard players get ${indexVar} rs`);
2313
+ this.builder.emitRaw(`execute store result storage rs:heap ${macroKey} int 1 run scoreboard players get ${indexVar} ${exports.LOWERING_OBJ}`);
2292
2314
  this.builder.emitRaw(`function ${this.namespace}:${subFnName} with storage rs:heap`);
2293
2315
  // Prefix \x01 is a sentinel for the MC macro '$' line-start marker.
2294
2316
  // We avoid using literal '$execute' here so the pre-alloc pass
2295
2317
  // doesn't mistakenly register 'execute' as a scoreboard variable.
2296
2318
  // Codegen replaces \x01 → '$' when emitting the mc function file.
2297
- this.emitRawSubFunction(subFnName, `\x01execute store result score ${dst} rs run data get storage ${storageNs} ${arrayKey}[$(${macroKey})] 1`);
2319
+ this.emitRawSubFunction(subFnName, `\x01execute store result score ${dst} ${exports.LOWERING_OBJ} run data get storage ${storageNs} ${arrayKey}[$(${macroKey})] 1`);
2298
2320
  }
2299
2321
  return { kind: 'var', name: dst };
2300
2322
  }
@@ -2316,7 +2338,7 @@ class Lowering {
2316
2338
  // value : integer value to write (const or runtime)
2317
2339
  //
2318
2340
  // Const index + const value:
2319
- // execute store result storage <ns> <key>[N] int 1 run scoreboard players set $const_V rs V
2341
+ // execute store result storage <ns> <key>[N] int 1 run scoreboard players set $const_V ${LOWERING_OBJ} V
2320
2342
  // Runtime index or value: macro sub-function via rs:heap
2321
2343
  if (name === 'storage_set_int') {
2322
2344
  const storageNs = this.exprToString(args[0]);
@@ -2328,7 +2350,7 @@ class Lowering {
2328
2350
  const valVar = valueOperand.kind === 'var'
2329
2351
  ? valueOperand.name
2330
2352
  : this.operandToVar(valueOperand);
2331
- this.builder.emitRaw(`execute store result storage ${storageNs} ${arrayKey}[${indexOperand.value}] int 1 run scoreboard players get ${valVar} rs`);
2353
+ this.builder.emitRaw(`execute store result storage ${storageNs} ${arrayKey}[${indexOperand.value}] int 1 run scoreboard players get ${valVar} ${exports.LOWERING_OBJ}`);
2332
2354
  }
2333
2355
  else {
2334
2356
  // Runtime index: we need a macro sub-function.
@@ -2343,16 +2365,16 @@ class Lowering {
2343
2365
  const valVar = valueOperand.kind === 'var'
2344
2366
  ? valueOperand.name
2345
2367
  : this.operandToVar(valueOperand);
2346
- this.builder.emitRaw(`execute store result storage rs:heap ${macroIdxKey} int 1 run scoreboard players get ${indexVar} rs`);
2368
+ this.builder.emitRaw(`execute store result storage rs:heap ${macroIdxKey} int 1 run scoreboard players get ${indexVar} ${exports.LOWERING_OBJ}`);
2347
2369
  // Pin valVar in the optimizer's read-set so the assignment is not dead-code-eliminated.
2348
2370
  // The value is stored to rs:heap but NOT used by the macro (the macro reads the scoreboard
2349
2371
  // slot directly to avoid the MC 'data modify set value $(n)' macro substitution bug).
2350
- this.builder.emitRaw(`execute store result storage rs:heap ${macroValKey} int 1 run scoreboard players get ${valVar} rs`);
2372
+ this.builder.emitRaw(`execute store result storage rs:heap ${macroValKey} int 1 run scoreboard players get ${valVar} ${exports.LOWERING_OBJ}`);
2351
2373
  this.builder.emitRaw(`function ${this.namespace}:${subFnName} with storage rs:heap`);
2352
2374
  // Use execute store result (not 'data modify set value $(val)') to avoid MC macro
2353
2375
  // substitution bugs with numeric values. The scoreboard slot ${valVar} is hardcoded
2354
2376
  // into the macro sub-function at compile time — only the array index is macro-substituted.
2355
- this.emitRawSubFunction(subFnName, `\x01execute store result storage ${storageNs} ${arrayKey}[$(${macroIdxKey})] int 1 run scoreboard players get ${valVar} rs`);
2377
+ this.emitRawSubFunction(subFnName, `\x01execute store result storage ${storageNs} ${arrayKey}[$(${macroIdxKey})] int 1 run scoreboard players get ${valVar} ${exports.LOWERING_OBJ}`);
2356
2378
  }
2357
2379
  return { kind: 'const', value: 0 };
2358
2380
  }
@@ -2398,7 +2420,7 @@ class Lowering {
2398
2420
  const dst = this.builder.freshTemp();
2399
2421
  const setId = this.exprToString(args[0]);
2400
2422
  const value = this.exprToString(args[1]);
2401
- this.builder.emitRaw(`execute store result score ${dst} rs if data storage rs:sets ${setId}[{value:${value}}]`);
2423
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} if data storage rs:sets ${setId}[{value:${value}}]`);
2402
2424
  return { kind: 'var', name: dst };
2403
2425
  }
2404
2426
  if (name === 'set_remove') {
@@ -2663,7 +2685,7 @@ class Lowering {
2663
2685
  components.push({ text: operand.value.toString() });
2664
2686
  return;
2665
2687
  }
2666
- components.push({ score: { name: this.operandToVar(operand), objective: 'rs' } });
2688
+ components.push({ score: { name: this.operandToVar(operand), objective: exports.LOWERING_OBJ } });
2667
2689
  }
2668
2690
  exprToString(expr) {
2669
2691
  switch (expr.kind) {
@@ -2816,11 +2838,19 @@ class Lowering {
2816
2838
  }
2817
2839
  exprToScoreboardObjective(expr, span) {
2818
2840
  if (expr.kind === 'mc_name') {
2819
- return expr.value;
2841
+ // 'rs' is the canonical token for the current RS scoreboard objective.
2842
+ // Resolve to LOWERING_OBJ so it respects --scoreboard / namespace default.
2843
+ return expr.value === 'rs' ? exports.LOWERING_OBJ : expr.value;
2820
2844
  }
2821
2845
  const objective = this.exprToString(expr);
2822
2846
  if (objective.startsWith('#') || objective.includes('.')) {
2823
- return objective.startsWith('#') ? objective.slice(1) : objective;
2847
+ if (objective.startsWith('#')) {
2848
+ const name = objective.slice(1);
2849
+ // '#rs' is the canonical way to reference the current RS scoreboard objective.
2850
+ // Resolve to LOWERING_OBJ so it tracks the --scoreboard option.
2851
+ return name === 'rs' ? exports.LOWERING_OBJ : name;
2852
+ }
2853
+ return objective;
2824
2854
  }
2825
2855
  return `${this.getObjectiveNamespace(span)}.${objective}`;
2826
2856
  }
@@ -2836,7 +2866,7 @@ class Lowering {
2836
2866
  if (!filePath) {
2837
2867
  return this.namespace;
2838
2868
  }
2839
- return this.isStdlibFile(filePath) ? 'rs' : this.namespace;
2869
+ return this.isStdlibFile(filePath) ? exports.LOWERING_OBJ : this.namespace;
2840
2870
  }
2841
2871
  tryGetStdlibInternalObjective(playerExpr, objectiveExpr, span) {
2842
2872
  if (!span || !this.currentStdlibCallSite || objectiveExpr.kind !== 'mc_name' || objectiveExpr.value !== 'rs') {
@@ -2851,7 +2881,7 @@ class Lowering {
2851
2881
  return null;
2852
2882
  }
2853
2883
  const hash = this.shortHash(this.serializeCallSite(this.currentStdlibCallSite));
2854
- return `rs._${resourceBase}_${hash}`;
2884
+ return `${exports.LOWERING_OBJ}._${resourceBase}_${hash}`;
2855
2885
  }
2856
2886
  getStdlibInternalResourceBase(playerExpr) {
2857
2887
  if (!playerExpr || playerExpr.kind !== 'str_lit') {
@@ -3138,15 +3168,15 @@ class Lowering {
3138
3168
  readArrayElement(arrayName, index) {
3139
3169
  const dst = this.builder.freshTemp();
3140
3170
  if (index.kind === 'const') {
3141
- this.builder.emitRaw(`execute store result score ${dst} rs run data get storage rs:heap ${arrayName}[${index.value}]`);
3171
+ this.builder.emitRaw(`execute store result score ${dst} ${exports.LOWERING_OBJ} run data get storage rs:heap ${arrayName}[${index.value}]`);
3142
3172
  return { kind: 'var', name: dst };
3143
3173
  }
3144
3174
  const macroKey = `__rs_index_${this.foreachCounter++}`;
3145
3175
  const subFnName = `${this.currentFn}/array_get_${this.foreachCounter++}`;
3146
3176
  const indexVar = index.kind === 'var' ? index.name : this.operandToVar(index);
3147
- this.builder.emitRaw(`execute store result storage rs:heap ${macroKey} int 1 run scoreboard players get ${indexVar} rs`);
3177
+ this.builder.emitRaw(`execute store result storage rs:heap ${macroKey} int 1 run scoreboard players get ${indexVar} ${exports.LOWERING_OBJ}`);
3148
3178
  this.builder.emitRaw(`function ${this.namespace}:${subFnName} with storage rs:heap`);
3149
- this.emitRawSubFunction(subFnName, `\x01execute store result score ${dst} rs run data get storage rs:heap ${arrayName}[$(${macroKey})]`);
3179
+ this.emitRawSubFunction(subFnName, `\x01execute store result score ${dst} ${exports.LOWERING_OBJ} run data get storage rs:heap ${arrayName}[$(${macroKey})]`);
3150
3180
  return { kind: 'var', name: dst };
3151
3181
  }
3152
3182
  emitRawSubFunction(name, ...commands) {
@@ -17,6 +17,7 @@ export interface CommandFunction {
17
17
  name: string;
18
18
  commands: IRCommand[];
19
19
  }
20
+ export declare function setOptimizerObjective(obj: string): void;
20
21
  export declare function createEmptyOptimizationStats(): OptimizationStats;
21
22
  export declare function mergeOptimizationStats(base: OptimizationStats, delta: Partial<OptimizationStats>): void;
22
23
  export declare function applyLICM(functions: CommandFunction[]): {