redscript-mc 2.1.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -0
- package/dist/src/__tests__/lsp.test.js +76 -0
- package/dist/src/__tests__/mc-syntax.test.js +1 -6
- package/dist/src/__tests__/stdlib-include.test.d.ts +1 -0
- package/dist/src/__tests__/stdlib-include.test.js +86 -0
- package/dist/src/cli.js +10 -3
- package/dist/src/compile.d.ts +1 -0
- package/dist/src/compile.js +33 -10
- package/dist/src/emit/compile.d.ts +2 -0
- package/dist/src/emit/compile.js +2 -2
- package/dist/src/lsp/server.js +51 -0
- package/editors/vscode/package-lock.json +3 -3
- package/editors/vscode/package.json +1 -1
- package/editors/vscode/syntaxes/redscript.tmLanguage.json +34 -0
- package/examples/coroutine-demo.mcrs +50 -0
- package/examples/enum-demo.mcrs +95 -0
- package/examples/scheduler-demo.mcrs +59 -0
- package/package.json +1 -1
- package/src/__tests__/lsp.test.ts +89 -0
- package/src/__tests__/mc-syntax.test.ts +1 -7
- package/src/__tests__/stdlib-include.test.ts +61 -0
- package/src/cli.ts +9 -1
- package/src/compile.ts +44 -15
- package/src/emit/compile.ts +4 -2
- package/src/lsp/server.ts +55 -0
- package/examples/spiral.mcrs +0 -43
- package/src/examples/arena.mcrs +0 -44
- package/src/examples/counter.mcrs +0 -12
- package/src/examples/new_features_demo.mcrs +0 -193
- package/src/examples/rpg.mcrs +0 -13
- package/src/examples/stdlib_demo.mcrs +0 -181
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
// Tick counter that announces every 100 ticks.
|
|
2
|
-
|
|
3
|
-
@tick
|
|
4
|
-
fn counter_tick() {
|
|
5
|
-
let ticks = scoreboard_get("counter", #ticks);
|
|
6
|
-
ticks = ticks + 1;
|
|
7
|
-
scoreboard_set("counter", #ticks, ticks);
|
|
8
|
-
|
|
9
|
-
if (ticks % 100 == 0) {
|
|
10
|
-
say("Counter reached another 100 ticks");
|
|
11
|
-
}
|
|
12
|
-
}
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* RedScript New Features Demo
|
|
3
|
-
* Showcasing language features added on 2026-03-12
|
|
4
|
-
*/
|
|
5
|
-
|
|
6
|
-
// ============================================
|
|
7
|
-
// 1. Type Inference
|
|
8
|
-
// ============================================
|
|
9
|
-
fn type_inference_demo() {
|
|
10
|
-
// No need to write `: int`, compiler infers automatically
|
|
11
|
-
let health = 100;
|
|
12
|
-
let name = "Steve";
|
|
13
|
-
let alive = true;
|
|
14
|
-
let speed = 1.5;
|
|
15
|
-
|
|
16
|
-
// NBT suffixes can also be inferred
|
|
17
|
-
let damage = 20b; // byte
|
|
18
|
-
let distance = 1000s; // short
|
|
19
|
-
let bignum = 999999L; // long
|
|
20
|
-
let precise = 3.14d; // double
|
|
21
|
-
|
|
22
|
-
say("Health: ${health}, Name: ${name}");
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// ============================================
|
|
26
|
-
// 2. For-Range Loops
|
|
27
|
-
// ============================================
|
|
28
|
-
fn for_range_demo() {
|
|
29
|
-
// Loop from 0 to 9
|
|
30
|
-
for i in 0..10 {
|
|
31
|
-
say("Count: ${i}");
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Can be used for countdown
|
|
35
|
-
for sec in 0..5 {
|
|
36
|
-
title(@a, "Starting in ${sec}...");
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// ============================================
|
|
41
|
-
// 3. NBT Structured Params
|
|
42
|
-
// ============================================
|
|
43
|
-
fn nbt_params_demo() {
|
|
44
|
-
// Give item with NBT
|
|
45
|
-
give(@s, "minecraft:diamond_sword", 1, {
|
|
46
|
-
display: { Name: "Excalibur" },
|
|
47
|
-
Enchantments: [
|
|
48
|
-
{ id: "minecraft:sharpness", lvl: 5 },
|
|
49
|
-
{ id: "minecraft:unbreaking", lvl: 3 }
|
|
50
|
-
]
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// Summon entity with attributes
|
|
54
|
-
summon("minecraft:zombie", @s, {
|
|
55
|
-
CustomName: "Boss Zombie",
|
|
56
|
-
Health: 100.0,
|
|
57
|
-
Attributes: [
|
|
58
|
-
{ Name: "generic.max_health", Base: 100.0 }
|
|
59
|
-
]
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
// ============================================
|
|
64
|
-
// 4. Set Data Structure (Runtime Set)
|
|
65
|
-
// ============================================
|
|
66
|
-
fn set_demo() {
|
|
67
|
-
// Create set
|
|
68
|
-
let visited = set_new();
|
|
69
|
-
|
|
70
|
-
// Add elements using method syntax
|
|
71
|
-
visited.add("spawn");
|
|
72
|
-
visited.add("castle");
|
|
73
|
-
visited.add("dungeon");
|
|
74
|
-
|
|
75
|
-
// Check if exists
|
|
76
|
-
if (visited.contains("castle")) {
|
|
77
|
-
say("You've been to the castle!");
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
// Remove element
|
|
81
|
-
visited.remove("spawn");
|
|
82
|
-
|
|
83
|
-
// Clear set
|
|
84
|
-
visited.clear();
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
// ============================================
|
|
88
|
-
// 5. Method Syntax Sugar
|
|
89
|
-
// ============================================
|
|
90
|
-
fn method_syntax_demo() {
|
|
91
|
-
let items: string[] = [];
|
|
92
|
-
|
|
93
|
-
// obj.method(args) → method(obj, args)
|
|
94
|
-
items.push("sword");
|
|
95
|
-
items.push("shield");
|
|
96
|
-
items.push("potion");
|
|
97
|
-
|
|
98
|
-
let count = items.len();
|
|
99
|
-
say("You have ${count} items");
|
|
100
|
-
|
|
101
|
-
// Sets can also use method syntax
|
|
102
|
-
let tags = set_new();
|
|
103
|
-
tags.add("vip");
|
|
104
|
-
tags.add("admin");
|
|
105
|
-
|
|
106
|
-
if (tags.contains("admin")) {
|
|
107
|
-
say("Welcome, admin!");
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
// ============================================
|
|
112
|
-
// 6. #mc_name Syntax (MC Identifier Syntax)
|
|
113
|
-
// ============================================
|
|
114
|
-
fn mc_name_demo() {
|
|
115
|
-
// #name compiles to bare MC name (without quotes)
|
|
116
|
-
scoreboard_set(@s, #kills, 0);
|
|
117
|
-
scoreboard_add(@s, #deaths, 1);
|
|
118
|
-
|
|
119
|
-
let score = scoreboard_get(@s, #points);
|
|
120
|
-
|
|
121
|
-
// For tag
|
|
122
|
-
tag_add(@s, #vip);
|
|
123
|
-
|
|
124
|
-
// For team
|
|
125
|
-
team_join(@s, #red);
|
|
126
|
-
|
|
127
|
-
// Comparison: strings still need quotes
|
|
128
|
-
give(@s, "minecraft:diamond", 1);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
// ============================================
|
|
132
|
-
// 7. Block Comments
|
|
133
|
-
// ============================================
|
|
134
|
-
|
|
135
|
-
/*
|
|
136
|
-
* This is a block comment
|
|
137
|
-
* Can span multiple lines
|
|
138
|
-
*/
|
|
139
|
-
|
|
140
|
-
/**
|
|
141
|
-
* This is a doc comment
|
|
142
|
-
* @param player Target player
|
|
143
|
-
*/
|
|
144
|
-
fn documented_function() {
|
|
145
|
-
say("Hello!");
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// ============================================
|
|
149
|
-
// Combined Example: Simple Game
|
|
150
|
-
// ============================================
|
|
151
|
-
|
|
152
|
-
struct Player {
|
|
153
|
-
score: int,
|
|
154
|
-
level: int,
|
|
155
|
-
visited: string // set ID
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
fn init_player() {
|
|
159
|
-
let visited_set = set_new();
|
|
160
|
-
let p: Player = {
|
|
161
|
-
score: 0,
|
|
162
|
-
level: 1,
|
|
163
|
-
visited: visited_set
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
// Record spawn point (using set_add since visited is a string ID)
|
|
167
|
-
set_add(p.visited, "spawn");
|
|
168
|
-
|
|
169
|
-
scoreboard_set(@s, #score, p.score);
|
|
170
|
-
scoreboard_set(@s, #level, p.level);
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
@tick(rate=20)
|
|
174
|
-
fn game_tick() {
|
|
175
|
-
// Check once per second
|
|
176
|
-
for i in 0..1 {
|
|
177
|
-
let score = scoreboard_get(@s, #score);
|
|
178
|
-
if (score >= 100) {
|
|
179
|
-
title(@s, "Level Up!");
|
|
180
|
-
scoreboard_set(@s, #level, 2);
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
fn reward_player(amount: int) {
|
|
186
|
-
// Type inference + NBT params
|
|
187
|
-
let bonus = amount * 2;
|
|
188
|
-
scoreboard_add(@s, #score, bonus);
|
|
189
|
-
|
|
190
|
-
give(@s, "minecraft:gold_ingot", amount, {
|
|
191
|
-
display: { Name: "Reward Gold" }
|
|
192
|
-
});
|
|
193
|
-
}
|
package/src/examples/rpg.mcrs
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import "../stdlib/math.mcrs"
|
|
2
|
-
import "../stdlib/combat.mcrs"
|
|
3
|
-
|
|
4
|
-
fn attack(enemy: string, base: int, bonus: int) {
|
|
5
|
-
let raw_damage = weapon_damage(base, bonus);
|
|
6
|
-
let damage = clamp(raw_damage, 1, 20);
|
|
7
|
-
apply_damage(enemy, damage);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
@tick
|
|
11
|
-
fn battle_tick() {
|
|
12
|
-
attack("goblin", 4, 2);
|
|
13
|
-
}
|
|
@@ -1,181 +0,0 @@
|
|
|
1
|
-
// Stdlib pattern demo: a simple survival loop.
|
|
2
|
-
//
|
|
3
|
-
// This file is standalone on purpose. Since RedScript has no import system yet,
|
|
4
|
-
// copy the helpers you need from src/stdlib/ into your project file.
|
|
5
|
-
|
|
6
|
-
fn abs(x: int) -> int {
|
|
7
|
-
if (x < 0) {
|
|
8
|
-
return -x;
|
|
9
|
-
} else {
|
|
10
|
-
return x;
|
|
11
|
-
}
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
fn clamp(x: int, lo: int, hi: int) -> int {
|
|
15
|
-
if (x < lo) {
|
|
16
|
-
return lo;
|
|
17
|
-
} else {
|
|
18
|
-
if (x > hi) {
|
|
19
|
-
return hi;
|
|
20
|
-
} else {
|
|
21
|
-
return x;
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
fn heal(amount: int) {
|
|
27
|
-
let health: int = scoreboard_get(@p, #health);
|
|
28
|
-
let next: int = health + amount;
|
|
29
|
-
scoreboard_set(@p, #health, next);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
fn damage(amount: int) {
|
|
33
|
-
let health: int = scoreboard_get(@p, #health);
|
|
34
|
-
let next: int = health - amount;
|
|
35
|
-
|
|
36
|
-
if (next < 0) {
|
|
37
|
-
scoreboard_set(@p, #health, 0);
|
|
38
|
-
} else {
|
|
39
|
-
scoreboard_set(@p, #health, next);
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
fn is_op() -> int {
|
|
44
|
-
let result: int = 0;
|
|
45
|
-
|
|
46
|
-
execute if entity @p[tag=op] run {
|
|
47
|
-
result = 1;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return result;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
fn timer_start(name: string, duration: int) {
|
|
54
|
-
scoreboard_set("demo_timer_ticks", #rs, duration);
|
|
55
|
-
scoreboard_set("demo_timer_active", #rs, 1);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
fn timer_tick(name: string) -> int {
|
|
59
|
-
let active: int = scoreboard_get("demo_timer_active", #rs);
|
|
60
|
-
let ticks: int = scoreboard_get("demo_timer_ticks", #rs);
|
|
61
|
-
|
|
62
|
-
if (active == 0) {
|
|
63
|
-
return 0;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (ticks > 0) {
|
|
67
|
-
let next: int = ticks - 1;
|
|
68
|
-
scoreboard_set("demo_timer_ticks", #rs, next);
|
|
69
|
-
|
|
70
|
-
if (next == 0) {
|
|
71
|
-
scoreboard_set("demo_timer_active", #rs, 0);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return next;
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
scoreboard_set("demo_timer_active", #rs, 0);
|
|
78
|
-
return 0;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
fn timer_done(name: string) -> int {
|
|
82
|
-
let active: int = scoreboard_get("demo_timer_active", #rs);
|
|
83
|
-
let ticks: int = scoreboard_get("demo_timer_ticks", #rs);
|
|
84
|
-
|
|
85
|
-
if (active == 0) {
|
|
86
|
-
if (ticks <= 0) {
|
|
87
|
-
return 1;
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return 0;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
fn cooldown_start(name: string, ticks: int) {
|
|
95
|
-
scoreboard_set("demo_dash_ticks", #rs, ticks);
|
|
96
|
-
scoreboard_set("demo_dash_active", #rs, 1);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
fn cooldown_ready(name: string) -> int {
|
|
100
|
-
let active: int = scoreboard_get("demo_dash_active", #rs);
|
|
101
|
-
let ticks_left: int = scoreboard_get("demo_dash_ticks", #rs);
|
|
102
|
-
|
|
103
|
-
if (active == 0) {
|
|
104
|
-
return 1;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
if (ticks_left <= 0) {
|
|
108
|
-
return 1;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
return 0;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
fn cooldown_tick(name: string) {
|
|
115
|
-
let active: int = scoreboard_get("demo_dash_active", #rs);
|
|
116
|
-
let ticks_left: int = scoreboard_get("demo_dash_ticks", #rs);
|
|
117
|
-
|
|
118
|
-
if (active == 0) {
|
|
119
|
-
return;
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
if (ticks_left > 0) {
|
|
123
|
-
let next: int = ticks_left - 1;
|
|
124
|
-
scoreboard_set("demo_dash_ticks", #rs, next);
|
|
125
|
-
|
|
126
|
-
if (next == 0) {
|
|
127
|
-
scoreboard_set("demo_dash_active", #rs, 0);
|
|
128
|
-
}
|
|
129
|
-
} else {
|
|
130
|
-
scoreboard_set("demo_dash_active", #rs, 0);
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
@on_trigger("arena_start")
|
|
135
|
-
fn arena_start() {
|
|
136
|
-
scoreboard_set("arena_zone_center", #rs, 0);
|
|
137
|
-
scoreboard_set(@p, #health, 20);
|
|
138
|
-
timer_start("wave", 200);
|
|
139
|
-
cooldown_start("dash", 0);
|
|
140
|
-
title(@p, "Arena started");
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
@tick
|
|
144
|
-
fn arena_tick() {
|
|
145
|
-
let remaining: int = timer_tick("wave");
|
|
146
|
-
cooldown_tick("dash");
|
|
147
|
-
|
|
148
|
-
if (timer_done("wave") == 1) {
|
|
149
|
-
title(@p, "Next wave");
|
|
150
|
-
timer_start("wave", 200);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
let player_x: int = data_get("entity", @p, "Pos[0]");
|
|
154
|
-
let delta: int = player_x - scoreboard_get("arena_zone_center", #rs);
|
|
155
|
-
let distance: int = abs(delta);
|
|
156
|
-
let pressure: int = clamp(distance, 0, 8);
|
|
157
|
-
|
|
158
|
-
if (pressure > 4) {
|
|
159
|
-
damage(1);
|
|
160
|
-
} else {
|
|
161
|
-
heal(1);
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
if (remaining <= 40) {
|
|
165
|
-
tell(@p, "Wave nearly over.");
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
@on_trigger("dash")
|
|
170
|
-
fn dash_trigger() {
|
|
171
|
-
if (cooldown_ready("dash") == 1) {
|
|
172
|
-
raw("effect give @p speed 1 3 true");
|
|
173
|
-
cooldown_start("dash", 80);
|
|
174
|
-
} else {
|
|
175
|
-
tell(@p, "Dash is cooling down.");
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (is_op() == 1) {
|
|
179
|
-
tell(@p, "Operator override available.");
|
|
180
|
-
}
|
|
181
|
-
}
|