overpy 9.6.10 → 9.7.3
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 +119 -97
- package/overpy.js +54844 -54818
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -33,56 +33,7 @@ You first need to install the [pnpm package manager](https://pnpm.io/installatio
|
|
|
33
33
|
- Build `out/overpy_standalone.js`: `pnpm run package`
|
|
34
34
|
- Build and publish to prod: `pnpm run publish`
|
|
35
35
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
 
|
|
39
|
-
|
|
40
|
-
Install:
|
|
41
|
-
|
|
42
|
-
- As a dependency: `pnpm i overpy`
|
|
43
|
-
- Global CLI (optional): `pnpm i -g overpy`
|
|
44
|
-
- One-off CLI without install: `npx overpy --help`
|
|
45
|
-
|
|
46
|
-
JS/TS API usage:
|
|
47
|
-
|
|
48
|
-
```js
|
|
49
|
-
// JavaScript (CommonJS)
|
|
50
|
-
const overpy = require("overpy");
|
|
51
|
-
|
|
52
|
-
async function main() {
|
|
53
|
-
await overpy.readyPromise;
|
|
54
|
-
const compileResult = await overpy.compile(
|
|
55
|
-
'rule "hello":\n @Event global\n wait(1)\n',
|
|
56
|
-
"en-US",
|
|
57
|
-
process.cwd(),
|
|
58
|
-
"inline.opy"
|
|
59
|
-
);
|
|
60
|
-
console.log(compileResult.result);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
main().catch(console.error);
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
```ts
|
|
67
|
-
// TypeScript
|
|
68
|
-
import * as overpy from "overpy";
|
|
69
|
-
|
|
70
|
-
async function main() {
|
|
71
|
-
await overpy.readyPromise;
|
|
72
|
-
const workshopText = "rule(\"hello\") { event { Ongoing - Global; } actions { Wait(1, Ignore Condition); } }";
|
|
73
|
-
const decompiled = overpy.decompileAllRules(workshopText, "en-US");
|
|
74
|
-
console.log(decompiled);
|
|
75
|
-
}
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
CLI usage:
|
|
79
|
-
|
|
80
|
-
- Compile a file: `overpy compile -i script.opy -o script.txt`
|
|
81
|
-
- Compile from stdin to stdout: `cat script.opy | overpy compile > script.txt`
|
|
82
|
-
- Decompile a file: `overpy decompile -i workshop.txt -o script.opy`
|
|
83
|
-
- Decompile from stdin to stdout: `cat workshop.txt | overpy decompile --ignore-variable-index > script.opy`
|
|
84
|
-
|
|
85
|
-
Run `overpy --help` to see all options (`-l/--language`, `--root`, `--main-file`, `--ignore-variable-index`, `--ignore-subroutine-index`).
|
|
36
|
+
See at the bottom for NPM usage and LSP building.
|
|
86
37
|
|
|
87
38
|
# Installation
|
|
88
39
|
|
|
@@ -132,7 +83,7 @@ You may get warnings when compiling; do not ignore them, as they can lead to bug
|
|
|
132
83
|
|
|
133
84
|
It is recommended to also decompile one of your existing gamemodes to get a better feel of the OverPy syntax.
|
|
134
85
|
|
|
135
|
-
```
|
|
86
|
+
```opy
|
|
136
87
|
|
|
137
88
|
# Line comments are made with "#".
|
|
138
89
|
# Multiline comments are made with /* */.
|
|
@@ -296,7 +247,6 @@ If a function is not in that list, then the name is the English name in camelCas
|
|
|
296
247
|
<code>Loop If(A == 2)</code> | <code>if A == 2:</code><br><code> loop()</code>
|
|
297
248
|
<code>Loop If Condition Is False</code> | <code>if not ruleCondition:</code><br><code> loop()</code>
|
|
298
249
|
<code>Loop If Condition Is True</code> | <code>if ruleCondition:</code><br><code> loop()</code>
|
|
299
|
-
<code>Magnitude Of</code> | <code>magnitude()</code>
|
|
300
250
|
<code>Map(Workshop Island)</code> | <code>Map.WORKSHOP_ISLAND</code>
|
|
301
251
|
<code>Mapped Array(<i>array</i>, Current Array Element + 2)</code><br><code>Mapped Array(<i>array</i>, Current Array Element * Current Array Index)</code> | <code><i>array</i>.map(lambda <i>elem</i>: <i>elem</i>+2)</code><br><code><i>array</i>.map(lambda <i>elem</i>, <i>idx</i>: <i>elem</i> * <i>idx</i>)</code><br>Python-style comprehension syntax also works but is not recommended: <code>[<i>elem</i>+2 for <i>elem</i> in <i>array</i>]</code>
|
|
302
252
|
<code>Modify Global Variable(A, Add, 2)</code> | <code>A += 2</code>
|
|
@@ -321,7 +271,6 @@ If a function is not in that list, then the name is the English name in camelCas
|
|
|
321
271
|
<code>Not(<i>a</i>)</code> | <code>not <i>a</i></code>
|
|
322
272
|
<code>Number(1234)</code> | <code>1234</code>
|
|
323
273
|
<code>Objective Index</code> | <code>getCurrentObjective()</code>
|
|
324
|
-
<code>Objective Position</code> | <code>getObjectivePosition()</code>
|
|
325
274
|
<code>Opposite Team Of(Team Of(Event Player))</code> | <code>getOppositeTeam(eventPlayer.getTeam())</code><br>Or for a player: `eventPlayer.getOppositeTeam()`
|
|
326
275
|
<code>Or(A == 2, B == 4)</code> | <code>A == 2 or B == 4</code>
|
|
327
276
|
<code>Player Carrying Flag</code> | <code>getFlagCarrier()</code>
|
|
@@ -332,9 +281,6 @@ If a function is not in that list, then the name is the English name in camelCas
|
|
|
332
281
|
<code>Random Real</code> | <code>random.uniform()</code>
|
|
333
282
|
<code>Random Value In Array</code> | <code>random.choice()</code>
|
|
334
283
|
<code>Randomized Array</code> | <code>random.shuffle()</code>
|
|
335
|
-
<code>Raycast Hit Normal(<i>start</i>, <i>end</i>, <i>include</i>, <i>exclude</i>, <i>includePlayerObjects</i>)</code> | <code>raycast(<i>start</i>, <i>end</i>, <i>include</i>, <i>exclude</i>, <i>includePlayersObjects</i>).getNormal()</code>
|
|
336
|
-
<code>Raycast Hit Player(<i>start</i>, <i>end</i>, <i>include</i>, <i>exclude</i>, <i>includePlayerObjects</i>)</code> | <code>raycast(<i>start</i>, <i>end</i>, <i>include</i>, <i>exclude</i>, <i>includePlayersObjects</i>).getPlayerHit()</code>
|
|
337
|
-
<code>Raycast Hit Position(<i>start</i>, <i>end</i>, <i>include</i>, <i>exclude</i>, <i>includePlayerObjects</i>)</code> | <code>raycast(<i>start</i>, <i>end</i>, <i>include</i>, <i>exclude</i>, <i>includePlayersObjects</i>).getHitPosition()</code>
|
|
338
284
|
<code>Remove From Array(<i>array</i>, 2)</code> | <code><i>array</i>.exclude(2)</code>
|
|
339
285
|
<code>Remove Player</code> | <code><i>player</i>.removeFromGame()</code>
|
|
340
286
|
<code>Right</code> | <code>Vector.RIGHT</code>
|
|
@@ -358,7 +304,6 @@ If a function is not in that list, then the name is the English name in camelCas
|
|
|
358
304
|
<code>Start Forcing Dummy Bot Name</code> | <code><i>player</i>.startForcingName()</code>
|
|
359
305
|
<code>Start Holding Button</code> | <code><i>player</i>.startForcingButton()</code>
|
|
360
306
|
<code>Start Modifying Hero Voice Lines</code> | <code><i>player</i>.startModifyingVoicelinePitch()</code>
|
|
361
|
-
<code>Start Rule(<i>subroutine</i>, <i>behavior</i>)</code> | <code>async(<i>subroutine</i>, <i>behavior</i>)</code>
|
|
362
307
|
<code>Start Scaling Player</code> | <code><i>player</i>.startScalingSize()</code>
|
|
363
308
|
<code>Stop Holding Button</code> | <code><i>player</i>.stopForcingButton()</code>
|
|
364
309
|
<code>Stop Modifying Hero Voice Lines</code> | <code><i>player</i>.stopModifyingVoicelinePitch()</code>
|
|
@@ -388,7 +333,7 @@ If a function is not in that list, then the name is the English name in camelCas
|
|
|
388
333
|
|
|
389
334
|
OverPy supports including custom game settings, using the `settings` keyword. The settings are parsed with OverPy's parser, meaning you can do things such as:
|
|
390
335
|
|
|
391
|
-
```
|
|
336
|
+
```opy
|
|
392
337
|
macro VERSION = "1.4.3"
|
|
393
338
|
macro DEBUG = false
|
|
394
339
|
macro CLIP_SIZE_MULTIPLIER = 2
|
|
@@ -419,7 +364,7 @@ settings {
|
|
|
419
364
|
|
|
420
365
|
Note that every value has to eventually resolve to a dict/array/string/number/boolean through the optimizer (you can't do `200 * A` where `A` is a variable).
|
|
421
366
|
|
|
422
|
-
|
|
367
|
+
Because I made the unfortunate mistake of trying to rename pretty much all settings (and because Overwatch periodically renames a setting or two), unknown settings are accepted by the compiler, so you can just put what Overwatch accepts (but they won't be translated if you are compiling for another language).
|
|
423
368
|
|
|
424
369
|
You can also put the settings in a .json file and then import it with `settings "gamesettings.opy.json"`. This has the advantage of adding autocompletion (if ending with .opy.json), although it will display syntax errors if it doesn't perfectly conform to the JSON syntax (trailing comma, comment, etc).
|
|
425
370
|
|
|
@@ -431,7 +376,7 @@ Extensions are activated using the `#!extensions` compiler directive.
|
|
|
431
376
|
|
|
432
377
|
An if/elif/else statement is simply represented by the following structure:
|
|
433
378
|
|
|
434
|
-
```
|
|
379
|
+
```opy
|
|
435
380
|
if A == 1:
|
|
436
381
|
B = 2
|
|
437
382
|
elif A == 2:
|
|
@@ -446,7 +391,7 @@ else:
|
|
|
446
391
|
|
|
447
392
|
A while loop is represented by the following structure:
|
|
448
393
|
|
|
449
|
-
```
|
|
394
|
+
```opy
|
|
450
395
|
while A == 1:
|
|
451
396
|
B = 2
|
|
452
397
|
wait()
|
|
@@ -457,7 +402,7 @@ It compiles to the workshop's `While` instruction.
|
|
|
457
402
|
## For loop
|
|
458
403
|
|
|
459
404
|
A for loop is represented by the following structure:
|
|
460
|
-
```
|
|
405
|
+
```opy
|
|
461
406
|
globalvar i
|
|
462
407
|
rule "for loop":
|
|
463
408
|
for i in range(1, 5, 2):
|
|
@@ -467,7 +412,7 @@ rule "for loop":
|
|
|
467
412
|
|
|
468
413
|
Note that the `range(start, stop, step)` function, that can only be used here, has other forms:
|
|
469
414
|
|
|
470
|
-
```
|
|
415
|
+
```opy
|
|
471
416
|
for i in range(1,5) -> for i in range(1,5,1)
|
|
472
417
|
for i in range(5) -> for i in range(0,5,1)
|
|
473
418
|
```
|
|
@@ -480,7 +425,7 @@ Although not recommended to use, gotos can be used in conjunction with a label.
|
|
|
480
425
|
|
|
481
426
|
For example:
|
|
482
427
|
|
|
483
|
-
```
|
|
428
|
+
```opy
|
|
484
429
|
if A == 4:
|
|
485
430
|
goto lbl_0
|
|
486
431
|
B = 5
|
|
@@ -493,7 +438,7 @@ Labels are declared on their own line, and must include a colon at the end (but
|
|
|
493
438
|
Due to the limitations of the workshop, labels must be in the same rule as the `goto` instruction, and cannot be before it.
|
|
494
439
|
|
|
495
440
|
Additionally, dynamic gotos can be specified using the special keyword `loc`:
|
|
496
|
-
```
|
|
441
|
+
```opy
|
|
497
442
|
goto loc+A
|
|
498
443
|
```
|
|
499
444
|
|
|
@@ -566,7 +511,7 @@ Compiler options begin with the `#!` operator, not indented.
|
|
|
566
511
|
|
|
567
512
|
Inserts the text of the specified file. The file path can be relative; if so, it is relative to the file with the `#!include` directive. For example:
|
|
568
513
|
|
|
569
|
-
```
|
|
514
|
+
```opy
|
|
570
515
|
#!include "heroes/zenyatta.opy"
|
|
571
516
|
|
|
572
517
|
/* includes a file in the parent directory (".." is the parent directory) */
|
|
@@ -580,7 +525,7 @@ Inserts the text of the specified file. The file path can be relative; if so, it
|
|
|
580
525
|
|
|
581
526
|
Specifies an .opy file as the main file (implying the current file is a module). This directive MUST be placed at the very beginning of the file. For example:
|
|
582
527
|
|
|
583
|
-
```
|
|
528
|
+
```opy
|
|
584
529
|
#!mainFile "../main.opy"
|
|
585
530
|
```
|
|
586
531
|
|
|
@@ -590,7 +535,7 @@ This is so that you can compile your gamemode from any file and OverPy knows the
|
|
|
590
535
|
|
|
591
536
|
Suppresses the specified warnings globally across the program. Warnings must be separated by a space. Example:
|
|
592
537
|
|
|
593
|
-
```
|
|
538
|
+
```opy
|
|
594
539
|
#!suppressWarnings w_type_check w_unsuitable_event
|
|
595
540
|
```
|
|
596
541
|
|
|
@@ -634,7 +579,7 @@ This directive is added by default upon decompilation. Only remove it if you are
|
|
|
634
579
|
|
|
635
580
|
All 3 of these directives are only effective in the current block scope (indentation level) once they are declared, and can be cancelled by `#!enableOptimizations`, `#!disableOptimizeForSize` and `#!disableOptimizeStrict` respectively. For example:
|
|
636
581
|
|
|
637
|
-
```
|
|
582
|
+
```opy
|
|
638
583
|
rule "default: optimizations, no optimize for size, no optimize strict"
|
|
639
584
|
A = B+0 #will be optimized
|
|
640
585
|
if A:
|
|
@@ -654,7 +599,7 @@ rule "optimize strict, no optimize for size":
|
|
|
654
599
|
|
|
655
600
|
Several compiler options are available to automatically replace some constants, in order to save elements:
|
|
656
601
|
|
|
657
|
-
```
|
|
602
|
+
```opy
|
|
658
603
|
#!replaceTeam1ByControlScoringTeam
|
|
659
604
|
#!replace0ByCapturePercentage
|
|
660
605
|
#!replace0ByPayloadProgressPercentage
|
|
@@ -674,7 +619,7 @@ Preprocessing is an important part of OverPy and allows extending its power way
|
|
|
674
619
|
|
|
675
620
|
Use the `macro` keyword to declare a macro, which is an inline function or constant. For example:
|
|
676
621
|
|
|
677
|
-
```
|
|
622
|
+
```opy
|
|
678
623
|
macro BOSS_HP = 1000 + getNumberOfPlayers() * 300
|
|
679
624
|
|
|
680
625
|
macro add(a, b):
|
|
@@ -689,7 +634,7 @@ Note that the replacement is done in the AST, meaning the order of operations wi
|
|
|
689
634
|
|
|
690
635
|
You can also declare member macros, where the member is referenced with `self`. For example:
|
|
691
636
|
|
|
692
|
-
```
|
|
637
|
+
```opy
|
|
693
638
|
macro Vector.sum = self.x + self.y
|
|
694
639
|
|
|
695
640
|
macro Player.setPowerLevel(powerLevel):
|
|
@@ -709,7 +654,7 @@ rule "power level":
|
|
|
709
654
|
|
|
710
655
|
Default parameters can also be specified, and just like normal functions, you can use keyword arguments:
|
|
711
656
|
|
|
712
|
-
```
|
|
657
|
+
```opy
|
|
713
658
|
macro Player.setPowerLevel(powerLevel=1, damageDealt=null):
|
|
714
659
|
self.setMaxHealth(powerLevel*200)
|
|
715
660
|
self.setDamageDealt(damageDealt or powerLevel*2)
|
|
@@ -724,7 +669,7 @@ The `#!define` directive declares a text-based macro, meaning the replacement is
|
|
|
724
669
|
|
|
725
670
|
For example, given this function:
|
|
726
671
|
|
|
727
|
-
```
|
|
672
|
+
```opy
|
|
728
673
|
#!define sum(a,b) a+b
|
|
729
674
|
```
|
|
730
675
|
|
|
@@ -738,7 +683,7 @@ This problem does not occur with `macro`, which is why you should always use the
|
|
|
738
683
|
|
|
739
684
|
You can do script macros with `#!define` and the special `__script__` function. For example:
|
|
740
685
|
|
|
741
|
-
```
|
|
686
|
+
```opy
|
|
742
687
|
#!define addFive(x) __script__("addfive.js")
|
|
743
688
|
```
|
|
744
689
|
|
|
@@ -755,7 +700,7 @@ For the technical details:
|
|
|
755
700
|
|
|
756
701
|
Enums can be declared to avoid manually declaring several macros:
|
|
757
702
|
|
|
758
|
-
```
|
|
703
|
+
```opy
|
|
759
704
|
enum GameStatus:
|
|
760
705
|
GAME_NOT_STARTED = 1
|
|
761
706
|
GAME_IN_PROGRESS
|
|
@@ -780,7 +725,7 @@ Note that enum members are inlined, so if you use a value such as `getAllPlayers
|
|
|
780
725
|
|
|
781
726
|
Runs a JavaScript post-processing script after OverPy finishes compilation. This can effectively resolve certain compilation errors caused by language translation.
|
|
782
727
|
|
|
783
|
-
```
|
|
728
|
+
```opy
|
|
784
729
|
#!postCompileHook "hooks/postCompileHook.js"
|
|
785
730
|
```
|
|
786
731
|
|
|
@@ -793,7 +738,7 @@ Runs a JavaScript post-processing script after OverPy finishes compilation. This
|
|
|
793
738
|
|
|
794
739
|
Example `hooks/postCompileHook.js`:
|
|
795
740
|
|
|
796
|
-
```
|
|
741
|
+
```opy
|
|
797
742
|
content = content.replace(/abc/g, "def");
|
|
798
743
|
|
|
799
744
|
// If the last operation returns an interpreter object,
|
|
@@ -809,7 +754,7 @@ Sets a prefix for all subsequent rules. The prefix is applied to the rule name u
|
|
|
809
754
|
|
|
810
755
|
If a `#!rulePrefix` directive is in an included file, it only takes effect for rules within that file (and its child includes, if they don't have their own `#!rulePrefix`), after the directive. When the included file ends, the prefix is restored to what it was before the include.
|
|
811
756
|
|
|
812
|
-
```
|
|
757
|
+
```opy
|
|
813
758
|
#!rulePrefix "Effects"
|
|
814
759
|
|
|
815
760
|
rule "Spawn particles":
|
|
@@ -846,7 +791,7 @@ The expression has to evaluate to a string without arguments.
|
|
|
846
791
|
|
|
847
792
|
Switches are a good way to transform an if/elif/else chain into something more optimized:
|
|
848
793
|
|
|
849
|
-
```
|
|
794
|
+
```opy
|
|
850
795
|
switch A:
|
|
851
796
|
case Hero.ANA:
|
|
852
797
|
B = 2
|
|
@@ -859,7 +804,7 @@ switch A:
|
|
|
859
804
|
```
|
|
860
805
|
|
|
861
806
|
This is equivalent to:
|
|
862
|
-
```
|
|
807
|
+
```opy
|
|
863
808
|
if A == Hero.ANA:
|
|
864
809
|
B = 2
|
|
865
810
|
elif A == Hero.ASHE:
|
|
@@ -876,7 +821,7 @@ Keep in mind that fallthrough is enabled, so if you don't have a `break` instruc
|
|
|
876
821
|
|
|
877
822
|
In the above case, we always set the same variable. Therefore, a dictionary can be used:
|
|
878
823
|
|
|
879
|
-
```
|
|
824
|
+
```opy
|
|
880
825
|
B = {
|
|
881
826
|
0: 4,
|
|
882
827
|
Hero.ANA: 2,
|
|
@@ -887,7 +832,7 @@ B = {
|
|
|
887
832
|
If the key is not found in the dictionary, `null` will be returned. However, you can specify a `default` key for a default value.
|
|
888
833
|
|
|
889
834
|
This dictionary is internally converted to:
|
|
890
|
-
```
|
|
835
|
+
```opy
|
|
891
836
|
B = [4, 2, 3][[0, Hero.ANA, Hero.ASHE].index(A)]
|
|
892
837
|
```
|
|
893
838
|
|
|
@@ -913,7 +858,7 @@ The `spacesForLength` and `strVisualLength` macros can also be used. `spacesForS
|
|
|
913
858
|
|
|
914
859
|
This is useful to do alignment tricks. For example, the following code displays a key:value attribute list:
|
|
915
860
|
|
|
916
|
-
```
|
|
861
|
+
```opy
|
|
917
862
|
#We use strVisualLength("M")*20 to specify a string that is longer than the longest key/value.
|
|
918
863
|
#!define dictLine(key, value) "{}{}{}{}".format(spacesForLength(strVisualLength("M")*20 - strVisualLength(key)), (key), (value), spacesForLength(strVisualLength("M")*20 - strVisualLength(value)))
|
|
919
864
|
rule "iwt":
|
|
@@ -933,7 +878,7 @@ The `ruleCondition` value compiles to all the conditions of the rule, joined wit
|
|
|
933
878
|
|
|
934
879
|
This is mostly useful in `waitUntil`, so you can do the following:
|
|
935
880
|
|
|
936
|
-
```
|
|
881
|
+
```opy
|
|
937
882
|
rule "":
|
|
938
883
|
@Event eachPlayer
|
|
939
884
|
@Condition ...
|
|
@@ -952,7 +897,7 @@ You can use the `compressed()` function to store a large array of numbers or vec
|
|
|
952
897
|
|
|
953
898
|
For example:
|
|
954
899
|
|
|
955
|
-
```
|
|
900
|
+
```opy
|
|
956
901
|
mapData = compressed([vect(-65.048, -18.007, -80.036), vect(0.92, 12.58, -18.32), vect(194.041, 6.128, -74.097), ...])
|
|
957
902
|
```
|
|
958
903
|
|
|
@@ -966,7 +911,7 @@ You can also use the `#!useVariableForCompressionAlphabet` compiler option to us
|
|
|
966
911
|
|
|
967
912
|
`splitDictArray` maps an array of dictionaries to variables. For example:
|
|
968
913
|
|
|
969
|
-
```
|
|
914
|
+
```opy
|
|
970
915
|
splitDictArray({
|
|
971
916
|
hero: waveHeroes,
|
|
972
917
|
length: waveLengths
|
|
@@ -979,14 +924,14 @@ splitDictArray({
|
|
|
979
924
|
|
|
980
925
|
Will yield the following:
|
|
981
926
|
|
|
982
|
-
```
|
|
927
|
+
```opy
|
|
983
928
|
waveHeroes = [Hero.ANA, Hero.SOLDIER, Hero.HAMMOND]
|
|
984
929
|
waveLengths = [3, 8, null]
|
|
985
930
|
```
|
|
986
931
|
|
|
987
932
|
For a terser syntax, `tabular` can be used, where the second argument is a raw array (not an array of arrays!)
|
|
988
933
|
|
|
989
|
-
```
|
|
934
|
+
```opy
|
|
990
935
|
tabular([waveHeroes, waveLengths], [
|
|
991
936
|
Hero.ANA, 3,
|
|
992
937
|
Hero.SOLDIER, 8,
|
|
@@ -1075,13 +1020,13 @@ The `___` function is the same as the `_` function, but will never resolve the t
|
|
|
1075
1020
|
|
|
1076
1021
|
This is useful when several strings are used in a single display action. For example:
|
|
1077
1022
|
|
|
1078
|
-
```
|
|
1023
|
+
```opy
|
|
1079
1024
|
bigMessage(text=[t"Choice 1", t"Choice 2"][eventPlayer.choice])
|
|
1080
1025
|
```
|
|
1081
1026
|
|
|
1082
1027
|
This will add the code to resolve the translation twice, but it can be optimized to:
|
|
1083
1028
|
|
|
1084
|
-
```
|
|
1029
|
+
```opy
|
|
1085
1030
|
bigMessage(text=_([___("Choice 1"), ___("Choice 2")][eventPlayer.choice]))
|
|
1086
1031
|
```
|
|
1087
1032
|
|
|
@@ -1095,7 +1040,7 @@ Wrapping a string with `___` has the same caveats as putting a translated string
|
|
|
1095
1040
|
|
|
1096
1041
|
**Example**:
|
|
1097
1042
|
|
|
1098
|
-
```
|
|
1043
|
+
```opy
|
|
1099
1044
|
#!translations en fr zh
|
|
1100
1045
|
|
|
1101
1046
|
rule "Player got kill":
|
|
@@ -1136,7 +1081,7 @@ The way translations work is by casting a value to string (usually `Color.WHITE`
|
|
|
1136
1081
|
|
|
1137
1082
|
However, this cast to string **must** be done client-side. You cannot do the following:
|
|
1138
1083
|
|
|
1139
|
-
```
|
|
1084
|
+
```opy
|
|
1140
1085
|
# Will not work properly, do not use!
|
|
1141
1086
|
eventPlayer.language = ["White", "Blanc"].index("{}".format(Color.WHITE))
|
|
1142
1087
|
```
|
|
@@ -1145,7 +1090,7 @@ This will appear to work, but this is evaluated server-side, and what it actuall
|
|
|
1145
1090
|
|
|
1146
1091
|
When in a reevaluated HUD text, `t"Some string"` resolves to:
|
|
1147
1092
|
|
|
1148
|
-
```
|
|
1093
|
+
```opy
|
|
1149
1094
|
["Some string", "Une chaîne"][["White", "Blanc"].index("{}".format(Color.WHITE))]
|
|
1150
1095
|
```
|
|
1151
1096
|
|
|
@@ -1167,7 +1112,7 @@ Note: I used arrays in the example. OverPy concatenates arrays to strings using
|
|
|
1167
1112
|
|
|
1168
1113
|
This is a bug introduced in Overwatch 2 where a rule condition check does not properly trigger while a variable is chased. For example:
|
|
1169
1114
|
|
|
1170
|
-
```
|
|
1115
|
+
```opy
|
|
1171
1116
|
playervar chasebug = 0
|
|
1172
1117
|
|
|
1173
1118
|
rule "debug":
|
|
@@ -1190,9 +1135,21 @@ You would expect "Test chase" to display after 1 second, but the variable goes w
|
|
|
1190
1135
|
|
|
1191
1136
|
To solve this bug, refactor your code to stop chasing the variable when you need to check it in a rule condition. Eg here, we could put the stop at 1 instead of 10. Then put `@SuppressWarnings w_ow2_rule_condition_chase` on the rule with the rule condition you checked is working. (It is not recommended to disable it for the whole project.)
|
|
1192
1137
|
|
|
1138
|
+
## w_start_rule_crash
|
|
1139
|
+
|
|
1140
|
+
Found by Psyrius:
|
|
1141
|
+
|
|
1142
|
+
It seems like repeatedly calling a `Start Rule` with its option `If Already Executing` set to `Restart Rule` and the subroutine being called has a `Wait` action inside (doesn't matter if there is more code before or after the wait inside the subroutine), the server will eventually crash - even if the server load is low. It will crash more frequently if the rule is called more often. In this workshop code/video, the calling frequency goes from every 1 to every 0.1s
|
|
1143
|
+
|
|
1144
|
+
Edit 1: Crashes at ~465 accumulated restarts, confirmed stack overflow behavior.
|
|
1145
|
+
Edit 2: ~465 = shared pool, not per subroutine.
|
|
1146
|
+
Edit 3: It only accumulates toward the crash if the restarted subroutine has any remaining wait duration inside of it (doesn't matter how much duration is remaining).
|
|
1147
|
+
|
|
1148
|
+
See https://discord.com/channels/570672959799164958/1485108807855247540/1485108807855247540 for more info.
|
|
1149
|
+
|
|
1193
1150
|
## w_wait_until
|
|
1194
1151
|
|
|
1195
|
-
```
|
|
1152
|
+
```opy
|
|
1196
1153
|
globalvar waitUntilBug = 0
|
|
1197
1154
|
|
|
1198
1155
|
rule "debug":
|
|
@@ -1216,7 +1173,72 @@ Since non-zero numbers are truthy, you would expect both `print` statements to r
|
|
|
1216
1173
|
|
|
1217
1174
|
You can safely ignore this warning if you are using a variable that can only be a boolean.
|
|
1218
1175
|
|
|
1219
|
-
|
|
1176
|
+
# Language Server Protocol
|
|
1220
1177
|
|
|
1178
|
+
OverPy can be built as a standalone Language Server Protocol server for editors that support custom LSP commands.
|
|
1179
|
+
|
|
1180
|
+
```sh
|
|
1181
|
+
pnpm install
|
|
1182
|
+
pnpm run compile-lsp
|
|
1183
|
+
node out/languageServer.js --stdio
|
|
1184
|
+
```
|
|
1185
|
+
|
|
1186
|
+
Configure your editor to run `node /path/to/overpy/out/languageServer.js --stdio` for `.opy` files. The server currently provides compiler diagnostics, completions (including type-aware argument values), signature help, hover documentation, semantic tokens, parameter inlay hints, document symbols, folding ranges, workspace go to definition, references and rename for user symbols, and warning suppression code actions by reusing the OverPy compiler metadata. You can also document your own `globalvar`/`playervar`/`def`/`enum` declarations with comments and they show up in hover and completion popups.
|
|
1187
|
+
|
|
1188
|
+
See [`docs/language-server.md`](docs/language-server.md) for the architecture, per-feature internals, and the comment-documentation conventions.
|
|
1189
|
+
|
|
1190
|
+
# NPM usage
|
|
1191
|
+
|
|
1192
|
+
 
|
|
1193
|
+
|
|
1194
|
+
Install:
|
|
1195
|
+
|
|
1196
|
+
- As a dependency: `pnpm i overpy`
|
|
1197
|
+
- Global CLI (optional): `pnpm i -g overpy`
|
|
1198
|
+
- One-off CLI without install: `npx overpy --help`
|
|
1199
|
+
|
|
1200
|
+
JS/TS API usage:
|
|
1201
|
+
|
|
1202
|
+
```js
|
|
1203
|
+
// JavaScript (CommonJS)
|
|
1204
|
+
const overpy = require("overpy");
|
|
1205
|
+
|
|
1206
|
+
async function main() {
|
|
1207
|
+
await overpy.readyPromise;
|
|
1208
|
+
const compileResult = await overpy.compile(
|
|
1209
|
+
'rule "hello":\n @Event global\n wait(1)\n',
|
|
1210
|
+
"en-US",
|
|
1211
|
+
process.cwd(),
|
|
1212
|
+
"inline.opy"
|
|
1213
|
+
);
|
|
1214
|
+
console.log(compileResult.result);
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
main().catch(console.error);
|
|
1218
|
+
```
|
|
1219
|
+
|
|
1220
|
+
```ts
|
|
1221
|
+
// TypeScript
|
|
1222
|
+
import * as overpy from "overpy";
|
|
1223
|
+
|
|
1224
|
+
async function main() {
|
|
1225
|
+
await overpy.readyPromise;
|
|
1226
|
+
const workshopText = "rule(\"hello\") { event { Ongoing - Global; } actions { Wait(1, Ignore Condition); } }";
|
|
1227
|
+
const decompiled = overpy.decompileAllRules(workshopText, "en-US");
|
|
1228
|
+
console.log(decompiled);
|
|
1229
|
+
}
|
|
1230
|
+
```
|
|
1231
|
+
|
|
1232
|
+
CLI usage:
|
|
1233
|
+
|
|
1234
|
+
- Compile a file: `overpy compile -i script.opy -o script.txt`
|
|
1235
|
+
- Compile from stdin to stdout: `cat script.opy | overpy compile > script.txt`
|
|
1236
|
+
- Decompile a file: `overpy decompile -i workshop.txt -o script.opy`
|
|
1237
|
+
- Decompile from stdin to stdout: `cat workshop.txt | overpy decompile --ignore-variable-index > script.opy`
|
|
1238
|
+
|
|
1239
|
+
Run `overpy --help` to see all options (`-l/--language`, `--root`, `--main-file`, `--ignore-variable-index`, `--ignore-subroutine-index`).
|
|
1240
|
+
|
|
1241
|
+
|
|
1242
|
+
----------------------
|
|
1221
1243
|
|
|
1222
1244
|
If you are still confused about something, or want to discuss a feature, please [join the discord](https://workshop.codes/discord) #hll-scripting :)
|