kustom-mc 0.1.0
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 +809 -0
- package/dist/commands/build.d.ts +2 -0
- package/dist/commands/build.js +447 -0
- package/dist/commands/bundle.d.ts +2 -0
- package/dist/commands/bundle.js +134 -0
- package/dist/commands/init.d.ts +2 -0
- package/dist/commands/init.js +219 -0
- package/dist/commands/list.d.ts +10 -0
- package/dist/commands/list.js +167 -0
- package/dist/commands/login.d.ts +9 -0
- package/dist/commands/login.js +167 -0
- package/dist/commands/new.d.ts +2 -0
- package/dist/commands/new.js +132 -0
- package/dist/commands/prepare.d.ts +9 -0
- package/dist/commands/prepare.js +267 -0
- package/dist/commands/push.d.ts +9 -0
- package/dist/commands/push.js +205 -0
- package/dist/commands/validate.d.ts +2 -0
- package/dist/commands/validate.js +191 -0
- package/dist/compiler/async-transform.d.ts +21 -0
- package/dist/compiler/async-transform.js +158 -0
- package/dist/compiler/inline.d.ts +32 -0
- package/dist/compiler/inline.js +87 -0
- package/dist/compiler/postprocess.d.ts +19 -0
- package/dist/compiler/postprocess.js +134 -0
- package/dist/compiler/rhino-plugin.d.ts +17 -0
- package/dist/compiler/rhino-plugin.js +324 -0
- package/dist/compiler/transform.d.ts +18 -0
- package/dist/compiler/transform.js +59 -0
- package/dist/config.d.ts +86 -0
- package/dist/config.js +166 -0
- package/dist/credentials.d.ts +65 -0
- package/dist/credentials.js +136 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +28 -0
- package/dist/runtime.d.ts +116 -0
- package/dist/runtime.js +96 -0
- package/dist/types/globals.d.ts +80 -0
- package/dist/types/globals.js +10 -0
- package/dist/types/index.d.ts +2094 -0
- package/dist/types/index.js +9 -0
- package/package.json +57 -0
- package/templates/project/kustom.config.json +26 -0
- package/templates/project/scripts/example.ts +17 -0
- package/templates/project/scripts/lib/utils.ts +19 -0
- package/templates/project/tsconfig.json +27 -0
- package/templates/scripts/block.ts.hbs +14 -0
- package/templates/scripts/gui.ts.hbs +28 -0
- package/templates/scripts/item.ts.hbs +13 -0
- package/templates/scripts/script.ts.hbs +18 -0
package/README.md
ADDED
|
@@ -0,0 +1,809 @@
|
|
|
1
|
+
# Kustom MC
|
|
2
|
+
|
|
3
|
+
CLI and type library for developing kustompack scripts with TypeScript support.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install kustom-mc
|
|
9
|
+
# or
|
|
10
|
+
npx kustom-mc <command>
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# Create a new project
|
|
17
|
+
npx kustom-mc init my-pack
|
|
18
|
+
|
|
19
|
+
# Build scripts
|
|
20
|
+
npx kustom-mc build
|
|
21
|
+
|
|
22
|
+
# Build and watch for changes
|
|
23
|
+
npx kustom-mc build --watch
|
|
24
|
+
|
|
25
|
+
# Build and deploy to server
|
|
26
|
+
npx kustom-mc build --deploy
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Table of Contents
|
|
30
|
+
|
|
31
|
+
- [Script Format](#script-format)
|
|
32
|
+
- [Props System](#props-system)
|
|
33
|
+
- [Importing Scripts](#importing-scripts)
|
|
34
|
+
- [Screen GUI System](#screen-gui-system)
|
|
35
|
+
- [Containers & Layouts](#containers--layouts)
|
|
36
|
+
- [Elements](#elements)
|
|
37
|
+
- [Chat GUI System](#chat-gui-system)
|
|
38
|
+
- [Camera System](#camera-system)
|
|
39
|
+
- [Custom Blocks (Shaper)](#custom-blocks-shaper)
|
|
40
|
+
- [Custom Items](#custom-items)
|
|
41
|
+
- [BetterModel Entities](#bettermodel-entities)
|
|
42
|
+
- [Commands](#commands)
|
|
43
|
+
- [Configuration](#configuration)
|
|
44
|
+
|
|
45
|
+
---
|
|
46
|
+
|
|
47
|
+
## Script Format
|
|
48
|
+
|
|
49
|
+
Scripts use the `defineScript` helper for type safety:
|
|
50
|
+
|
|
51
|
+
```typescript
|
|
52
|
+
import { defineScript, Props } from "kustom-mc";
|
|
53
|
+
|
|
54
|
+
export default defineScript({
|
|
55
|
+
props: {
|
|
56
|
+
player: Props.String(),
|
|
57
|
+
message: Props.String("Hello!"),
|
|
58
|
+
count: Props.Number(1),
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
run({ process, props, executor }) {
|
|
62
|
+
const player = process.getPlayer(props.player);
|
|
63
|
+
player.sendMessage(props.message);
|
|
64
|
+
|
|
65
|
+
// Access process methods via `this` or `process`
|
|
66
|
+
this.exit("done");
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Script Context
|
|
72
|
+
|
|
73
|
+
The `run` function receives a context object with:
|
|
74
|
+
|
|
75
|
+
| Property | Description |
|
|
76
|
+
|----------|-------------|
|
|
77
|
+
| `process` | Process API for script management |
|
|
78
|
+
| `props` | Validated props passed to the script |
|
|
79
|
+
| `executor` | Who executed the script (player or console) |
|
|
80
|
+
| `camera` | Camera system for cinematic views |
|
|
81
|
+
| `session` | Chat session system |
|
|
82
|
+
| `chatGUI` | Chat GUI system |
|
|
83
|
+
| `command` | Command registration |
|
|
84
|
+
| `entity` | BetterModel entity system |
|
|
85
|
+
| `shaper` | Custom block system |
|
|
86
|
+
| `items` | Custom item system |
|
|
87
|
+
|
|
88
|
+
The `this` context is also the process, allowing:
|
|
89
|
+
```typescript
|
|
90
|
+
this.exit(value); // Exit with return value
|
|
91
|
+
this.emit("event"); // Emit event to parent
|
|
92
|
+
this.getPlayer(name); // Get player by name
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Props System
|
|
98
|
+
|
|
99
|
+
Define typed properties for your scripts:
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { defineScript, Props } from "kustom-mc";
|
|
103
|
+
|
|
104
|
+
export default defineScript({
|
|
105
|
+
props: {
|
|
106
|
+
// Required string (no default)
|
|
107
|
+
player: Props.String(),
|
|
108
|
+
|
|
109
|
+
// String with default
|
|
110
|
+
title: Props.String("Welcome"),
|
|
111
|
+
|
|
112
|
+
// Number with default
|
|
113
|
+
amount: Props.Number(100),
|
|
114
|
+
|
|
115
|
+
// Boolean with default
|
|
116
|
+
enabled: Props.Boolean(true),
|
|
117
|
+
|
|
118
|
+
// Object/Array
|
|
119
|
+
data: Props.Object({}),
|
|
120
|
+
items: Props.Array([]),
|
|
121
|
+
|
|
122
|
+
// Union type (one of these values)
|
|
123
|
+
mode: Props.Union("easy", "normal", "hard"),
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
run({ props }) {
|
|
127
|
+
console.log(props.player); // string
|
|
128
|
+
console.log(props.amount); // number
|
|
129
|
+
console.log(props.enabled); // boolean
|
|
130
|
+
},
|
|
131
|
+
});
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
---
|
|
135
|
+
|
|
136
|
+
## Typed Events System
|
|
137
|
+
|
|
138
|
+
Scripts can declare typed events for type-safe communication between parent and child scripts:
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
// digicode.ts
|
|
142
|
+
import { defineScript, Props } from "kustom-mc";
|
|
143
|
+
|
|
144
|
+
export default defineScript({
|
|
145
|
+
props: {
|
|
146
|
+
player: Props.String(),
|
|
147
|
+
code: Props.String("1234"),
|
|
148
|
+
},
|
|
149
|
+
|
|
150
|
+
// Declare events with typed payloads
|
|
151
|
+
events: {
|
|
152
|
+
onSuccess: Props.Boolean(), // Event with boolean payload
|
|
153
|
+
onUnlock: Props.String(), // Event with string payload
|
|
154
|
+
},
|
|
155
|
+
|
|
156
|
+
run({ process, props }) {
|
|
157
|
+
// Emit typed events - TypeScript checks payload types!
|
|
158
|
+
process.emit("onSuccess", true); // OK
|
|
159
|
+
process.emit("onUnlock", "1234"); // OK
|
|
160
|
+
// process.emit("onSuccess", "wrong"); // TS Error: expected boolean
|
|
161
|
+
// process.emit("unknown", true); // TS Error: unknown event
|
|
162
|
+
},
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
```typescript
|
|
167
|
+
// main.ts
|
|
168
|
+
import { defineScript, Props } from "kustom-mc";
|
|
169
|
+
import digicode from "./digicode";
|
|
170
|
+
|
|
171
|
+
export default defineScript({
|
|
172
|
+
props: {
|
|
173
|
+
player: Props.String(),
|
|
174
|
+
},
|
|
175
|
+
|
|
176
|
+
run({ process, props }) {
|
|
177
|
+
const child = digicode.run({
|
|
178
|
+
player: props.player,
|
|
179
|
+
code: "1234",
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// TypeScript infers callback parameter types from digicode's events!
|
|
183
|
+
child.on("onSuccess", (value) => {
|
|
184
|
+
// value is typed as boolean
|
|
185
|
+
console.log("Code accepted!", value);
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
child.on("onUnlock", (code) => {
|
|
189
|
+
// code is typed as string
|
|
190
|
+
console.log("Entered code:", code);
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// Use then() for exit handling (not events)
|
|
194
|
+
child.then((result) => {
|
|
195
|
+
console.log("Child exited with:", result);
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### Event Methods
|
|
202
|
+
|
|
203
|
+
Scripts without `events` declaration still work - events are untyped (backward compatible).
|
|
204
|
+
|
|
205
|
+
```typescript
|
|
206
|
+
const child = otherScript.run({ ...props });
|
|
207
|
+
|
|
208
|
+
// Listen for events
|
|
209
|
+
child.on("eventName", (value) => {}); // Listen for event
|
|
210
|
+
child.once("eventName", (value) => {}); // Listen once, auto-remove after first call
|
|
211
|
+
child.off("eventName", callback); // Remove specific listener
|
|
212
|
+
child.off("eventName"); // Remove all listeners for event
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Multiple Listeners
|
|
216
|
+
|
|
217
|
+
Multiple listeners can be registered for the same event:
|
|
218
|
+
|
|
219
|
+
```typescript
|
|
220
|
+
child.on("onSuccess", () => console.log("First handler"));
|
|
221
|
+
child.on("onSuccess", () => console.log("Second handler"));
|
|
222
|
+
// Both handlers are called when onSuccess is emitted
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## Importing Scripts
|
|
228
|
+
|
|
229
|
+
Scripts can import and run other scripts:
|
|
230
|
+
|
|
231
|
+
### ScriptProcess API
|
|
232
|
+
|
|
233
|
+
When running an imported script, you get a `ScriptProcess`:
|
|
234
|
+
|
|
235
|
+
```typescript
|
|
236
|
+
const child = otherScript.run({ ...props });
|
|
237
|
+
|
|
238
|
+
child.on("eventName", (value) => {}); // Listen for events (typed if declared)
|
|
239
|
+
child.once("eventName", (value) => {}); // Listen once (auto-remove)
|
|
240
|
+
child.off("eventName", callback); // Remove specific listener
|
|
241
|
+
child.off("eventName"); // Remove all listeners for event
|
|
242
|
+
child.emit("eventName", ...args); // Send event to child
|
|
243
|
+
child.call("methodName", ...args); // Call method on child
|
|
244
|
+
child.then((result) => {}); // Handle completion
|
|
245
|
+
child.catch((error) => {}); // Handle errors
|
|
246
|
+
child.getId(); // Get process ID
|
|
247
|
+
child.hasExited(); // Check if completed
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
---
|
|
251
|
+
|
|
252
|
+
## Screen GUI System
|
|
253
|
+
|
|
254
|
+
Create inventory-based GUIs:
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
import { defineScript, Screen, Props } from "kustom-mc";
|
|
258
|
+
|
|
259
|
+
export default defineScript({
|
|
260
|
+
props: { player: Props.String() },
|
|
261
|
+
|
|
262
|
+
run({ process, props }) {
|
|
263
|
+
const player = process.getPlayer(props.player);
|
|
264
|
+
|
|
265
|
+
// Create a 27-slot screen (3 rows)
|
|
266
|
+
const screen = new Screen(27, {
|
|
267
|
+
hidePlayerInventory: true, // Hide player's items
|
|
268
|
+
autoCover: true, // Auto-fill empty slots
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
// Or with custom texture
|
|
272
|
+
const texturedScreen = new Screen("my_gui", 54);
|
|
273
|
+
|
|
274
|
+
// Add text overlay
|
|
275
|
+
const title = screen.appendText("My GUI", 12, -30, true);
|
|
276
|
+
|
|
277
|
+
// Add buttons
|
|
278
|
+
screen.addButton(13, "confirm_button", "Click me!", (event) => {
|
|
279
|
+
console.log("Button clicked!");
|
|
280
|
+
event.cancel(); // Prevent item pickup
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
// Handle events
|
|
284
|
+
screen.on("open", (p) => console.log(p.getName() + " opened"));
|
|
285
|
+
screen.on("close", (p) => {
|
|
286
|
+
process.exit(null);
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
// Open for player
|
|
290
|
+
screen.open(player);
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Screen Options
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
new Screen(size, {
|
|
299
|
+
hidePlayerInventory: boolean, // Store and hide player inventory
|
|
300
|
+
playerInventoryEnabled: boolean, // Allow inventory interaction
|
|
301
|
+
usePlayerInventorySlots: boolean, // Use player inv for buttons
|
|
302
|
+
autoCover: boolean, // Cover empty slots
|
|
303
|
+
coverTexture: string, // Custom cover texture
|
|
304
|
+
persistenceKey: string, // Enable persistence
|
|
305
|
+
});
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### Player Inventory Slots
|
|
309
|
+
|
|
310
|
+
Use player inventory slots for extended GUIs (like numpad):
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
const screen = new Screen(9, {
|
|
314
|
+
usePlayerInventorySlots: true, // Enable player inv slots
|
|
315
|
+
autoCover: false,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
// Chest slots: 0-8 (for 9-slot screen)
|
|
319
|
+
// Player inventory slots: 54-89
|
|
320
|
+
// Mapping: main inv (9-35) -> 54-80, hotbar (0-8) -> 81-89
|
|
321
|
+
|
|
322
|
+
screen.addButton(54, "button_1", null, () => addDigit(1));
|
|
323
|
+
screen.addButton(81, "confirm", null, () => confirm());
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
---
|
|
327
|
+
|
|
328
|
+
## Containers & Layouts
|
|
329
|
+
|
|
330
|
+
Organize elements in containers with grid or flex layouts:
|
|
331
|
+
|
|
332
|
+
```typescript
|
|
333
|
+
// Create a scrollable container
|
|
334
|
+
const container = screen.createContainer({
|
|
335
|
+
startSlot: 10,
|
|
336
|
+
rows: 3,
|
|
337
|
+
cols: 7,
|
|
338
|
+
scrollable: true,
|
|
339
|
+
maxCapacity: 100,
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
// Add items dynamically
|
|
343
|
+
for (let i = 0; i < 50; i++) {
|
|
344
|
+
container.pushButton("item_" + i, "Item " + i, (e) => {
|
|
345
|
+
console.log("Clicked item", i);
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Scroll controls
|
|
350
|
+
screen.addButton(8, "arrow_right", "Next", () => {
|
|
351
|
+
container.scrollPage(1);
|
|
352
|
+
screen.refresh();
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
screen.addButton(0, "arrow_left", "Previous", () => {
|
|
356
|
+
container.scrollPage(-1);
|
|
357
|
+
screen.refresh();
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
// Check pagination state
|
|
361
|
+
container.hasNextPage(); // boolean
|
|
362
|
+
container.hasPreviousPage(); // boolean
|
|
363
|
+
container.getCurrentPage(); // 0-based page number
|
|
364
|
+
container.getPageCount(); // total pages
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
### Container Methods
|
|
368
|
+
|
|
369
|
+
```typescript
|
|
370
|
+
// Adding elements
|
|
371
|
+
container.pushButton(texture, title, onClick); // Next available slot
|
|
372
|
+
container.putButton(index, texture, title, onClick); // Specific index
|
|
373
|
+
container.pushContentSlot(); // Slot for player items
|
|
374
|
+
container.pushCover(); // Visual cover element
|
|
375
|
+
container.pushContainer(config); // Nested container
|
|
376
|
+
|
|
377
|
+
// Layout configuration (chainable)
|
|
378
|
+
container
|
|
379
|
+
.setLayout("flex") // "grid" or "flex"
|
|
380
|
+
.setDirection("row") // "row" or "column"
|
|
381
|
+
.setGap(1) // Gap between items
|
|
382
|
+
.setRows(3)
|
|
383
|
+
.setCols(7);
|
|
384
|
+
|
|
385
|
+
// Scrolling
|
|
386
|
+
container.scroll(offset); // Relative scroll
|
|
387
|
+
container.scrollTo(index); // Scroll to specific item
|
|
388
|
+
container.scrollToPage(page); // Go to page
|
|
389
|
+
|
|
390
|
+
// Events
|
|
391
|
+
container.on("scroll", (offset, page) => {});
|
|
392
|
+
container.on("childAdded", (child, index) => {});
|
|
393
|
+
container.on("capacityReached", () => {});
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Elements
|
|
399
|
+
|
|
400
|
+
Create different types of GUI elements:
|
|
401
|
+
|
|
402
|
+
```typescript
|
|
403
|
+
import { Element } from "kustom-mc";
|
|
404
|
+
|
|
405
|
+
// Button element
|
|
406
|
+
const button = Element.button("my_texture", "Button Title");
|
|
407
|
+
button.onClick((e) => console.log("Clicked!"));
|
|
408
|
+
button.onRightClick((e) => console.log("Right clicked!"));
|
|
409
|
+
button.onShiftClick((e) => console.log("Shift clicked!"));
|
|
410
|
+
|
|
411
|
+
// Display-only element (no interaction)
|
|
412
|
+
const display = Element.display("info_icon");
|
|
413
|
+
|
|
414
|
+
// Content slot (accepts player items)
|
|
415
|
+
const slot = Element.contentSlot();
|
|
416
|
+
slot.on("afterItemPlace", (item, player, index) => {
|
|
417
|
+
console.log(player.getName() + " placed " + item.getMaterialName());
|
|
418
|
+
});
|
|
419
|
+
slot.on("afterItemTake", (player, index) => {
|
|
420
|
+
console.log(player.getName() + " took item from slot " + index);
|
|
421
|
+
});
|
|
422
|
+
|
|
423
|
+
// Cover element (visual overlay)
|
|
424
|
+
const cover = Element.cover();
|
|
425
|
+
cover.setColor("#FF0000"); // Red cover
|
|
426
|
+
```
|
|
427
|
+
|
|
428
|
+
### Element Chainable Methods
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
element
|
|
432
|
+
.setTexture("new_texture")
|
|
433
|
+
.setTitle("New Title")
|
|
434
|
+
.setLore(["Line 1", "Line 2"])
|
|
435
|
+
.setHideTooltip(true)
|
|
436
|
+
.setInteractive(false)
|
|
437
|
+
.setData({ custom: "data" });
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
---
|
|
441
|
+
|
|
442
|
+
## Chat GUI System
|
|
443
|
+
|
|
444
|
+
Create chat-based interactive UIs:
|
|
445
|
+
|
|
446
|
+
```typescript
|
|
447
|
+
run({ process, props, chatGUI }) {
|
|
448
|
+
const gui = chatGUI.create();
|
|
449
|
+
|
|
450
|
+
gui.addLine((line) => {
|
|
451
|
+
line.center()
|
|
452
|
+
.background("#1a1a1a")
|
|
453
|
+
.addBoldText("Welcome!", "gold");
|
|
454
|
+
});
|
|
455
|
+
|
|
456
|
+
gui.addEmptyLine();
|
|
457
|
+
|
|
458
|
+
gui.addLine((line) => {
|
|
459
|
+
line.spaceBetween()
|
|
460
|
+
.addButton("[Accept]", "/accept", "Click to accept", "green")
|
|
461
|
+
.addButton("[Decline]", "/decline", "Click to decline", "red");
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
gui.setBlocking(true); // Capture chat input
|
|
465
|
+
|
|
466
|
+
gui.onInput((playerName, message, guiId) => {
|
|
467
|
+
console.log(playerName + " typed: " + message);
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
gui.open(props.player);
|
|
471
|
+
}
|
|
472
|
+
```
|
|
473
|
+
|
|
474
|
+
### ChatGUILine Methods
|
|
475
|
+
|
|
476
|
+
```typescript
|
|
477
|
+
line
|
|
478
|
+
.padding(10) // Add padding
|
|
479
|
+
.center() // Center content
|
|
480
|
+
.spaceBetween() // Space between items
|
|
481
|
+
.background("#1a1a1a") // Background color
|
|
482
|
+
.addText("Hello", "white") // Add text
|
|
483
|
+
.addBoldText("Bold!", "gold") // Bold text
|
|
484
|
+
.addButton("[Click]", "/cmd", "Hover text", "green");
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
---
|
|
488
|
+
|
|
489
|
+
## Camera System
|
|
490
|
+
|
|
491
|
+
Create cinematic camera views:
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
run({ process, props, camera }) {
|
|
495
|
+
const player = process.getPlayer(props.player);
|
|
496
|
+
const loc = player.getLocation();
|
|
497
|
+
|
|
498
|
+
// Create camera at player's position
|
|
499
|
+
const cam = camera.create(loc.getX(), loc.getY() + 5, loc.getZ());
|
|
500
|
+
|
|
501
|
+
// Start spectating
|
|
502
|
+
cam.startCameraMode(props.player);
|
|
503
|
+
|
|
504
|
+
// Camera controls
|
|
505
|
+
cam.lookAt(0, 64, 0); // Look at coordinates
|
|
506
|
+
cam.lookAtPlayer("OtherPlayer"); // Look at player
|
|
507
|
+
cam.setRotation(90, -30); // Set yaw/pitch
|
|
508
|
+
cam.moveTo(100, 70, 100); // Teleport camera
|
|
509
|
+
|
|
510
|
+
// Transparent view (see through blocks)
|
|
511
|
+
cam.setTransparentView(true);
|
|
512
|
+
|
|
513
|
+
// Animations
|
|
514
|
+
const anim = camera.getAnimation();
|
|
515
|
+
|
|
516
|
+
anim.createAnimation()
|
|
517
|
+
.start(0, 64, 0)
|
|
518
|
+
.end(100, 64, 100)
|
|
519
|
+
.duration(5)
|
|
520
|
+
.camera(cam.getId())
|
|
521
|
+
.onEnd(() => console.log("Animation done!"))
|
|
522
|
+
.build()
|
|
523
|
+
.start();
|
|
524
|
+
|
|
525
|
+
// Stop spectating
|
|
526
|
+
cam.stopSpectating();
|
|
527
|
+
cam.remove();
|
|
528
|
+
}
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
## Custom Blocks (Shaper)
|
|
534
|
+
|
|
535
|
+
Define custom blocks with models and collision:
|
|
536
|
+
|
|
537
|
+
```typescript
|
|
538
|
+
run({ process, props, shaper }) {
|
|
539
|
+
// Create block template
|
|
540
|
+
const template = shaper.create("my_block")
|
|
541
|
+
.withModel("kustom:block/my_model")
|
|
542
|
+
.fullBlockCollision() // 1x1x1 collision
|
|
543
|
+
.onClick((event) => {
|
|
544
|
+
event.player.sendMessage("You clicked the block!");
|
|
545
|
+
})
|
|
546
|
+
.onBreak((event) => {
|
|
547
|
+
console.log("Block broken at", event.instance.getLocation());
|
|
548
|
+
})
|
|
549
|
+
.register();
|
|
550
|
+
|
|
551
|
+
// Spawn instance
|
|
552
|
+
const loc = process.getPlayer(props.player).getLocation();
|
|
553
|
+
const instance = template.spawn(loc, 0); // 0 = rotation degrees
|
|
554
|
+
|
|
555
|
+
// Instance methods
|
|
556
|
+
instance.setRotation(90);
|
|
557
|
+
instance.playAnimation("open");
|
|
558
|
+
instance.setState("locked", true);
|
|
559
|
+
instance.getState("locked"); // true
|
|
560
|
+
instance.remove();
|
|
561
|
+
}
|
|
562
|
+
```
|
|
563
|
+
|
|
564
|
+
### Block Definition File
|
|
565
|
+
|
|
566
|
+
```typescript
|
|
567
|
+
// blocks/tower.ts
|
|
568
|
+
import { defineBlock } from "kustom-mc";
|
|
569
|
+
|
|
570
|
+
export default defineBlock({
|
|
571
|
+
id: "tower",
|
|
572
|
+
model: "kustom:block/tower",
|
|
573
|
+
collision: { width: 1, height: 3, depth: 1, cornerY: 0 },
|
|
574
|
+
autoPlace: true, // Auto-generate placement item
|
|
575
|
+
|
|
576
|
+
onClick(event) {
|
|
577
|
+
event.player.sendMessage("Tower clicked!");
|
|
578
|
+
},
|
|
579
|
+
|
|
580
|
+
onBreak(event) {
|
|
581
|
+
return false; // Prevent breaking
|
|
582
|
+
},
|
|
583
|
+
});
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
---
|
|
587
|
+
|
|
588
|
+
## Custom Items
|
|
589
|
+
|
|
590
|
+
Define custom items with events:
|
|
591
|
+
|
|
592
|
+
```typescript
|
|
593
|
+
// items/magic_wand.ts
|
|
594
|
+
import { defineItem } from "kustom-mc";
|
|
595
|
+
|
|
596
|
+
export default defineItem({
|
|
597
|
+
id: "magic_wand",
|
|
598
|
+
material: "STICK",
|
|
599
|
+
model: "kustom:item/magic_wand",
|
|
600
|
+
displayName: "<gold>Magic Wand",
|
|
601
|
+
description: "A powerful magical artifact",
|
|
602
|
+
|
|
603
|
+
onRightClick(event) {
|
|
604
|
+
event.player.sendMessage("<rainbow>Woosh!</rainbow>");
|
|
605
|
+
},
|
|
606
|
+
|
|
607
|
+
onLeftClick(event) {
|
|
608
|
+
// Attack with wand
|
|
609
|
+
},
|
|
610
|
+
|
|
611
|
+
onDamageEntity(event) {
|
|
612
|
+
// Custom damage logic
|
|
613
|
+
},
|
|
614
|
+
});
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
---
|
|
618
|
+
|
|
619
|
+
## BetterModel Entities
|
|
620
|
+
|
|
621
|
+
Spawn and control animated entities:
|
|
622
|
+
|
|
623
|
+
```typescript
|
|
624
|
+
run({ process, props, entity }) {
|
|
625
|
+
const loc = process.getPlayer(props.player).getLocation();
|
|
626
|
+
|
|
627
|
+
// Spawn entity
|
|
628
|
+
const npc = entity.spawn("my_model", loc.getX(), loc.getY(), loc.getZ());
|
|
629
|
+
|
|
630
|
+
// Play animation
|
|
631
|
+
npc.playAnimation("wave", "PLAY_ONCE");
|
|
632
|
+
npc.playAnimation("idle", "LOOP");
|
|
633
|
+
|
|
634
|
+
// Get available animations
|
|
635
|
+
const anims = npc.getAvailableAnimations(); // ["idle", "walk", "wave"]
|
|
636
|
+
|
|
637
|
+
// Disguise player as model
|
|
638
|
+
const disguise = entity.disguisePlayer(props.player, "npc_model");
|
|
639
|
+
disguise.playAnimation("dance");
|
|
640
|
+
|
|
641
|
+
// Remove disguise
|
|
642
|
+
entity.undisguisePlayer(props.player);
|
|
643
|
+
|
|
644
|
+
// Cleanup
|
|
645
|
+
npc.destroy();
|
|
646
|
+
}
|
|
647
|
+
```
|
|
648
|
+
|
|
649
|
+
---
|
|
650
|
+
|
|
651
|
+
## Commands
|
|
652
|
+
|
|
653
|
+
### CLI Commands
|
|
654
|
+
|
|
655
|
+
#### `kustom init [project-name]`
|
|
656
|
+
|
|
657
|
+
Create a new kustompack project.
|
|
658
|
+
|
|
659
|
+
```bash
|
|
660
|
+
npx kustom-mc init my-pack
|
|
661
|
+
npx kustom-mc init # Initialize in current directory
|
|
662
|
+
npx kustom-mc init --force # Overwrite existing files
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
#### `kustom build`
|
|
666
|
+
|
|
667
|
+
Compile TypeScript to JavaScript.
|
|
668
|
+
|
|
669
|
+
```bash
|
|
670
|
+
npx kustom-mc build # Build all scripts
|
|
671
|
+
npx kustom-mc build --watch # Watch mode
|
|
672
|
+
npx kustom-mc build --deploy # Build and copy to server
|
|
673
|
+
npx kustom-mc build --no-validate # Skip validation
|
|
674
|
+
```
|
|
675
|
+
|
|
676
|
+
#### `kustom bundle`
|
|
677
|
+
|
|
678
|
+
Create a distributable zip file.
|
|
679
|
+
|
|
680
|
+
```bash
|
|
681
|
+
npx kustom-mc bundle # Create kustompack.zip
|
|
682
|
+
npx kustom-mc bundle -o my-pack.zip # Custom output name
|
|
683
|
+
npx kustom-mc bundle --include-source # Include .ts files
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
#### `kustom validate`
|
|
687
|
+
|
|
688
|
+
Check scripts for errors.
|
|
689
|
+
|
|
690
|
+
```bash
|
|
691
|
+
npx kustom-mc validate # Validate all scripts
|
|
692
|
+
npx kustom-mc validate --strict # Fail on warnings
|
|
693
|
+
```
|
|
694
|
+
|
|
695
|
+
#### `kustom new <type> <name>`
|
|
696
|
+
|
|
697
|
+
Generate a new script from template.
|
|
698
|
+
|
|
699
|
+
```bash
|
|
700
|
+
npx kustom-mc new script my-script # General script
|
|
701
|
+
npx kustom-mc new block my-block # Block definition
|
|
702
|
+
npx kustom-mc new item my-item # Item definition
|
|
703
|
+
npx kustom-mc new gui my-gui # GUI script
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
### In-Game Commands
|
|
707
|
+
|
|
708
|
+
Register dynamic commands from scripts:
|
|
709
|
+
|
|
710
|
+
```typescript
|
|
711
|
+
run({ process, props, command }) {
|
|
712
|
+
// Register command
|
|
713
|
+
const cmdId = command.register("mycommand", () => {
|
|
714
|
+
console.log("Command executed!");
|
|
715
|
+
return "Success";
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// With arguments
|
|
719
|
+
const cmdId2 = command.registerWithArgs("greet", (sender, args) => {
|
|
720
|
+
const name = args[0] || "World";
|
|
721
|
+
process.getPlayer(sender).sendMessage("Hello, " + name + "!");
|
|
722
|
+
});
|
|
723
|
+
|
|
724
|
+
// Give command to player
|
|
725
|
+
command.givePlayer(props.player, cmdId);
|
|
726
|
+
|
|
727
|
+
// Remove access
|
|
728
|
+
command.removePlayer(props.player, cmdId);
|
|
729
|
+
|
|
730
|
+
// Unregister
|
|
731
|
+
command.unregister(cmdId);
|
|
732
|
+
}
|
|
733
|
+
```
|
|
734
|
+
|
|
735
|
+
---
|
|
736
|
+
|
|
737
|
+
## Configuration
|
|
738
|
+
|
|
739
|
+
### kustom.config.json
|
|
740
|
+
|
|
741
|
+
```json
|
|
742
|
+
{
|
|
743
|
+
"include": [
|
|
744
|
+
"scripts/**/*.ts",
|
|
745
|
+
"blocks/**/*.ts",
|
|
746
|
+
"items/**/*.ts"
|
|
747
|
+
],
|
|
748
|
+
"exclude": [
|
|
749
|
+
"**/*.test.ts"
|
|
750
|
+
],
|
|
751
|
+
"outDir": "dist",
|
|
752
|
+
"lib": ["scripts/lib"],
|
|
753
|
+
"deploy": {
|
|
754
|
+
"target": "../run/plugins/kustom-plugin/kustompack",
|
|
755
|
+
"reloadCommand": "/kustom reload"
|
|
756
|
+
},
|
|
757
|
+
"bundle": {
|
|
758
|
+
"output": "bundle/kustompack.zip",
|
|
759
|
+
"include": ["**/*.js", "textures/**/*", "gui/**/*", "models/**/*"]
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
```
|
|
763
|
+
|
|
764
|
+
### Configuration Options
|
|
765
|
+
|
|
766
|
+
| Option | Description |
|
|
767
|
+
|--------|-------------|
|
|
768
|
+
| `include` | Glob patterns for script files |
|
|
769
|
+
| `exclude` | Patterns to exclude |
|
|
770
|
+
| `outDir` | Output directory for compiled scripts |
|
|
771
|
+
| `lib` | Directories containing shared libraries |
|
|
772
|
+
| `deploy.target` | Server kustompack directory |
|
|
773
|
+
| `deploy.reloadCommand` | Command to reload scripts |
|
|
774
|
+
| `bundle.output` | Output path for bundle zip |
|
|
775
|
+
| `bundle.include` | Files to include in bundle |
|
|
776
|
+
|
|
777
|
+
---
|
|
778
|
+
|
|
779
|
+
## Project Structure
|
|
780
|
+
|
|
781
|
+
```
|
|
782
|
+
my-kustom-pack/
|
|
783
|
+
├── kustom.config.json
|
|
784
|
+
├── tsconfig.json
|
|
785
|
+
├── package.json
|
|
786
|
+
├── scripts/
|
|
787
|
+
│ ├── lib/ # Shared utilities
|
|
788
|
+
│ │ └── utils.ts
|
|
789
|
+
│ ├── main.ts # Main scripts
|
|
790
|
+
│ └── digicode.ts
|
|
791
|
+
├── blocks/
|
|
792
|
+
│ └── tower.ts # Block definitions
|
|
793
|
+
├── items/
|
|
794
|
+
│ └── magic_wand.ts # Item definitions
|
|
795
|
+
├── gui/
|
|
796
|
+
│ └── buttons/ # GUI textures
|
|
797
|
+
├── textures/
|
|
798
|
+
│ └── item/ # Item textures
|
|
799
|
+
├── models/
|
|
800
|
+
│ └── block/ # Block models
|
|
801
|
+
└── dist/ # Compiled output
|
|
802
|
+
└── scripts/
|
|
803
|
+
```
|
|
804
|
+
|
|
805
|
+
---
|
|
806
|
+
|
|
807
|
+
## License
|
|
808
|
+
|
|
809
|
+
MIT
|