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.
Files changed (50) hide show
  1. package/README.md +809 -0
  2. package/dist/commands/build.d.ts +2 -0
  3. package/dist/commands/build.js +447 -0
  4. package/dist/commands/bundle.d.ts +2 -0
  5. package/dist/commands/bundle.js +134 -0
  6. package/dist/commands/init.d.ts +2 -0
  7. package/dist/commands/init.js +219 -0
  8. package/dist/commands/list.d.ts +10 -0
  9. package/dist/commands/list.js +167 -0
  10. package/dist/commands/login.d.ts +9 -0
  11. package/dist/commands/login.js +167 -0
  12. package/dist/commands/new.d.ts +2 -0
  13. package/dist/commands/new.js +132 -0
  14. package/dist/commands/prepare.d.ts +9 -0
  15. package/dist/commands/prepare.js +267 -0
  16. package/dist/commands/push.d.ts +9 -0
  17. package/dist/commands/push.js +205 -0
  18. package/dist/commands/validate.d.ts +2 -0
  19. package/dist/commands/validate.js +191 -0
  20. package/dist/compiler/async-transform.d.ts +21 -0
  21. package/dist/compiler/async-transform.js +158 -0
  22. package/dist/compiler/inline.d.ts +32 -0
  23. package/dist/compiler/inline.js +87 -0
  24. package/dist/compiler/postprocess.d.ts +19 -0
  25. package/dist/compiler/postprocess.js +134 -0
  26. package/dist/compiler/rhino-plugin.d.ts +17 -0
  27. package/dist/compiler/rhino-plugin.js +324 -0
  28. package/dist/compiler/transform.d.ts +18 -0
  29. package/dist/compiler/transform.js +59 -0
  30. package/dist/config.d.ts +86 -0
  31. package/dist/config.js +166 -0
  32. package/dist/credentials.d.ts +65 -0
  33. package/dist/credentials.js +136 -0
  34. package/dist/index.d.ts +2 -0
  35. package/dist/index.js +28 -0
  36. package/dist/runtime.d.ts +116 -0
  37. package/dist/runtime.js +96 -0
  38. package/dist/types/globals.d.ts +80 -0
  39. package/dist/types/globals.js +10 -0
  40. package/dist/types/index.d.ts +2094 -0
  41. package/dist/types/index.js +9 -0
  42. package/package.json +57 -0
  43. package/templates/project/kustom.config.json +26 -0
  44. package/templates/project/scripts/example.ts +17 -0
  45. package/templates/project/scripts/lib/utils.ts +19 -0
  46. package/templates/project/tsconfig.json +27 -0
  47. package/templates/scripts/block.ts.hbs +14 -0
  48. package/templates/scripts/gui.ts.hbs +28 -0
  49. package/templates/scripts/item.ts.hbs +13 -0
  50. 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