itemscore-helper 1.2.3 → 1.3.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/lib/manifest.js CHANGED
@@ -289,6 +289,33 @@ function validateItem(idx, item) {
289
289
  }
290
290
  }
291
291
 
292
+ if (item.events !== undefined && item.customEvents === undefined) {
293
+ warnings.push('the custom-event field is named "customEvents", not "events"; rename it so the plugin reads it')
294
+ }
295
+
296
+ if (item.customEvents !== undefined) {
297
+ if (!Array.isArray(item.customEvents)) errors.push("customEvents must be an array")
298
+ else {
299
+ item.customEvents.forEach((ce, ci) => {
300
+ const cp = "customEvents[" + ci + "]"
301
+ if (typeof ce !== "object" || ce === null) {
302
+ errors.push(cp + " must be an object")
303
+ return
304
+ }
305
+ if (typeof ce.event !== "string" || ce.event.length === 0) {
306
+ errors.push(cp + '.event is required and must be a full Bukkit event class name, e.g. "org.bukkit.event.block.BlockBreakEvent"')
307
+ } else if (!ce.event.includes(".")) {
308
+ warnings.push(cp + '.event "' + ce.event + '" should be a fully-qualified class name like org.bukkit.event.block.BlockBreakEvent')
309
+ }
310
+ if (ce.cooldown !== undefined && typeof ce.cooldown !== "string" && typeof ce.cooldown !== "number") {
311
+ warnings.push(cp + '.cooldown should be a duration like "5s", "1m", "1h" or a number of seconds')
312
+ }
313
+ if (!Array.isArray(ce.steps)) errors.push(cp + ".steps must be an array")
314
+ else ce.steps.forEach((s, si) => validateStep(idx, s, cp + ".steps[" + si + "]", errors, warnings))
315
+ })
316
+ }
317
+ }
318
+
292
319
  if (item.stats !== undefined && !Array.isArray(item.stats)) errors.push("stats must be an array when present")
293
320
  if (item.lore !== undefined && !Array.isArray(item.lore)) errors.push("lore must be an array of strings when present")
294
321
  if (item.enchantments !== undefined && !Array.isArray(item.enchantments)) errors.push("enchantments must be an array when present")
@@ -314,8 +341,15 @@ function itemSchema(idx) {
314
341
  customModelData: "number",
315
342
  skullOwner: "string - player name for PLAYER_HEAD skins",
316
343
  stats: "object[] - stat modifiers (see editor)",
317
- actions: "Action[] - the behavior graph",
318
- events: "object[] - custom event definitions",
344
+ actions: "Action[] - the built-in trigger behavior graph",
345
+ customEvents: "object[] - react to ANY Bukkit event by its full class name (see customEvent)",
346
+ },
347
+ customEvent: {
348
+ event:
349
+ 'string (required) - the FULL Bukkit event class name, e.g. "org.bukkit.event.block.BlockBreakEvent", "org.bukkit.event.entity.EntityDeathEvent". The plugin checks it exists on import.',
350
+ cooldown: "optional - per-player reuse delay, same format as an action cooldown",
351
+ steps:
352
+ "Step[] - same step format as an action. Variables available: player (the player from the event), item, event (the fired Bukkit event), plus core/particles/values/api.",
319
353
  },
320
354
  action: {
321
355
  trigger: "string (required) - one of: " + idx.TRIGGER_NAMES.join(", "),
@@ -354,7 +388,7 @@ function generateItemTemplate(kind) {
354
388
  actions: [
355
389
  { trigger: "rightAction", needBlock: "BOTH", steps: [{ call: "core.broadcastMessage", args: ["A wand was cast!"], operatorToNext: "END" }] },
356
390
  ],
357
- events: [],
391
+ customEvents: [],
358
392
  }
359
393
  }
360
394
  return {
@@ -369,7 +403,7 @@ function generateItemTemplate(kind) {
369
403
  actions: [
370
404
  { trigger: "leftAction", needBlock: "BOTH", steps: [{ call: "core.broadcastMessage", args: ["Hello from my custom sword!"], operatorToNext: "END" }] },
371
405
  ],
372
- events: [],
406
+ customEvents: [],
373
407
  }
374
408
  }
375
409
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "itemscore-helper",
3
- "version": "1.2.3",
3
+ "version": "1.3.0",
4
4
  "description": "One command sets up any AI (Claude, Codex, Cursor, Gemini, and others) to build and edit custom Minecraft items for the ItemsCore plugin. Auto-detects your AI tools and connects a local MCP server that runs entirely on your machine.",
5
5
  "bin": {
6
6
  "itemscore-helper": "bin/cli.js",
@@ -18,8 +18,8 @@ This is the offline reference for the item format ItemsCore imports. When the li
18
18
  | `customModelData` | number | Resource-pack model id |
19
19
  | `skullOwner` | string | Player name, for `PLAYER_HEAD` skins |
20
20
  | `stats` | object[] | Stat modifiers (authored in the editor; preserved on re-import) |
21
- | `actions` | Action[] | The behavior graph (see below) |
22
- | `events` | object[] | Custom event definitions |
21
+ | `actions` | Action[] | The built-in trigger behavior graph (see below) |
22
+ | `customEvents` | object[] | React to ANY Bukkit event by its full class name (see Custom events) |
23
23
 
24
24
  ## Action
25
25
 
@@ -112,6 +112,29 @@ For most items, every step uses `END`. Operators other than `END` build a single
112
112
  | `landLocation` | arrowLandAction |
113
113
  | `lastLocation` | projectile hit events |
114
114
 
115
+ ## Custom events
116
+
117
+ `actions` only cover the built-in triggers above. To react to ANY other Bukkit event, add a `customEvents` entry with the event's full class name. The plugin checks the class exists on import and blocks the import if it does not.
118
+
119
+ ```json
120
+ "customEvents": [
121
+ {
122
+ "event": "org.bukkit.event.block.BlockBreakEvent",
123
+ "steps": [
124
+ { "call": "core.sendColorMessage", "args": [ { "var": "player" }, "&aYou broke a block while holding this!" ], "operatorToNext": "END" }
125
+ ]
126
+ }
127
+ ]
128
+ ```
129
+
130
+ | Field | Type | Notes |
131
+ |---|---|---|
132
+ | `event` | string, required | The FULL Bukkit event class, e.g. `org.bukkit.event.block.BlockBreakEvent`, `org.bukkit.event.entity.EntityDeathEvent`, `org.bukkit.event.player.PlayerInteractEvent` |
133
+ | `cooldown` | duration string | Optional, same format as an action cooldown |
134
+ | `steps` | Step[] | Same step format as an action (below) |
135
+
136
+ Variables in a custom event step: `player` (the player the plugin finds on the event), `item`, `event` (the fired event itself - read its data with calls like `{ "call": "event.getBlock", "args": [] }`), plus `core` / `particles` / `values` / `api`. A custom event only fires while the player has the item (held, worn, or anywhere in the inventory for talismans). Use the exact class name; do not guess the package.
137
+
115
138
  ## Bukkit objects expose their full Spigot API
116
139
 
117
140
  `player`, `shooter`, `victim`, `arrow`, `event`, and any entity, block, world, location, or `ItemStack` returned by a method are real Bukkit/Spigot objects. You can call any standard Spigot method on them in a step, not only the ItemsCore methods:
@@ -160,7 +183,7 @@ Always confirm a method's exact name and parameters with `get_method` / `search_
160
183
  ]
161
184
  }
162
185
  ],
163
- "events": []
186
+ "customEvents": []
164
187
  }
165
188
  ```
166
189
 
@@ -184,7 +207,7 @@ Always confirm a method's exact name and parameters with `get_method` / `search_
184
207
  ]
185
208
  }
186
209
  ],
187
- "events": []
210
+ "customEvents": []
188
211
  }
189
212
  ```
190
213
 
package/skill/SKILL.md CHANGED
@@ -53,7 +53,7 @@ Minimal shape:
53
53
  ]
54
54
  }
55
55
  ],
56
- "events": []
56
+ "customEvents": []
57
57
  }
58
58
  ```
59
59
 
@@ -64,6 +64,7 @@ Rules:
64
64
  - Each step has a `call`, an `args` array, and `operatorToNext`. `call` is `core.method`, `particles.method`, a Bukkit call like `player.getLocation`, or a bare variable name to read it.
65
65
  - An arg is a JSON literal, `{ "var": "player" }` to pass a variable, or a nested `{ "call": ..., "args": ... }` to pass one method's result into another.
66
66
  - `operatorToNext` joins a step to the next one. Use `END` to end a statement. Other values (`ADD`, `EQUALS`, `AND`, ...) build expressions and conditions. See `ITEM_FORMAT.md`.
67
+ - `actions` only cover the built-in triggers. To react to any OTHER Bukkit event, add a `customEvents` entry with the event's full class name (e.g. `org.bukkit.event.block.BlockBreakEvent`) and the same `steps` format - variables are `player`, `item`, `event`. The import is blocked if the class name is not found on the server, so use the exact fully-qualified name.
67
68
 
68
69
  Find the exact method you need with `search_methods` / `get_method` before using it. Do not invent method names.
69
70