Wizards of Lua is a server-side mod for Fabric and NeoForge that lets you write spells in Lua and cast them inside Minecraft. No Java or modding experience needed, no server restarts, no client mods.
Type a one-liner in the chat to change something on the spot:
/lua spell:move("down"); spell.block = Block("gold_block")
Turns the block at your feet into gold.
Or start a long-running spell that reacts to everything happening in your world:
/lua require "midas"
Starts the spell in config/wizards-of-lua/midas.lua which turns every block a player hits into gold:
local queue = spell:collect("PlayerAttackBlockEvent")
while true do
local event = queue:next()
spell.pos = event.pos
spell.block = Block("gold_block")
end
Browse the Examples to see what else you can build with a few lines of Lua.
Get Started
The Quickstart Video walks you through installing the mod and casting your first spell in under two minutes. The Getting Started Guide covers the same ground in writing, and goes on from there.
What You Can Do
- Run Lua in-game: Cast spells with the
/luacommand, either as inline code or from files inconfig/wizards-of-lua. Edited files are recompiled the next time they're used, so no server restart is needed. - Change the world: Place blocks, summon mobs, edit items and entities, all through an extensive Lua API.
- Give mobs orders: Send any mob walking to a spot, following or fleeing from someone, standing guard or attacking a target. An order only borrows the mob's attention: when it's done, the mob goes back to its own business.
- Play with bots: Spawn bot players that join like real players and that spells control: they walk, fight, dig, build and chat, so you can play-test a mini-game alone or have companions at your side.
- React to events: Respond when players join, break blocks or swing tools, and cancel or extend what happens next.
- Add your own commands: Register Brigadier commands at runtime, with typed arguments and auto-completion.
- Code with autocompletion: Write spells in Visual Studio Code with full type support.
- Stay in control: Spells run on a per-tick budget and yield automatically, so a busy spell doesn't freeze your server. Access is controlled by permission levels and nodes, compatible with LuckPerms. Use
/wol spell list allto see what's running and/wol spell break allto stop it. - Install on the server only: Works in singleplayer and multiplayer. Players don't need to install anything.
What People Build
- Safe zones where PvP is disabled
- Minecarts that climb ladders
- A magic wand that strikes hostile mobs with lightning
- A spider bodyguard that stays at your side and attacks whoever hurts you
- Piglin guards who hold their posts against hostile mobs without chasing them too far
- A squire, a bot player who follows you, fights at your side behind its shield, and holds a spot when you tell it to
- A piglin miner who digs a tunnel, lights it with torches, and fetches a fresh pickaxe from a chest when his breaks
- A lumberjack spell that makes the whole tree fall when any player breaks a single log
- A magic hoe that harvests a whole wheat field with one swing
- Mini-games like Journey
Versioning
Versions follow the format MAJOR.MINOR.PATCH-MCVERSION, for example 8.0.0-1.21.11. The first part follows Semantic Versioning and describes compatibility with your scripts. The part after the - is the Minecraft version.
Updates that raise MINOR or PATCH are safe. If MAJOR increases, check the changelog first, because your scripts may need changes.
Learn More
This mod is a complete rewrite for Fabric and NeoForge of the original Wizards of Lua for Forge, which is no longer maintained. The two APIs differ, and scripts written for the Forge version won't run unchanged.
New here? Watch the Quickstart Video, then find guides, examples and the full API reference at wizards-of-lua.net.
How to Install Wizards of Lua (Mod)
Wizards of Lua by mickkay is verified for Fabric, Neoforge across Minecraft versions 1.21.1, 1.21.10, 1.21.11, 1.21.2, 1.21.3, 1.21.4, 1.21.5, 1.21.6 (latest release: 8.0.0-26.3-neoforge, file size: 2.1 MB). Follow the steps below to install it safely from ModCraft.tv:
- Click the Download button above and select your Minecraft version (1.21.1, 1.21.10, 1.21.11, 1.21.2, 1.21.3, 1.21.4, 1.21.5, 1.21.6) and platform (Fabric, Neoforge).
- Make sure you have the compatible loader or environment installed for Fabric, Neoforge.
- Move the downloaded Wizards of Lua file into your Minecraft
.minecraft/modsfolder and launch the game.
All Versions
+ Add Version| Name | Game version | Platforms | Published | Downloads | Actions |
|---|---|---|---|---|---|
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 2d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 7d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 22d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 26d ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 1mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 2mo ago | 1 | ||||
| 5mo ago | 1 | ||||
| 5mo ago | 1 | ||||
| 5mo ago | 1 | ||||
| 5mo ago | 1 | ||||
| 5mo ago | 1 | ||||
| 5mo ago | 1 | ||||
| 5mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 7mo ago | 1 | ||||
| 11mo ago | 1 | ||||
| 11mo ago | 1 | ||||
| 11mo ago | 1 | ||||
| 11mo ago | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 | ||||
| last yr. | 1 |
- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**- Breaking Change:
assertanderrorare plain Lua again** - They took a format like
string.format. That broke messages with a%in them, even of anassertthat passed,errorwith a table, and the level oferror. A message with values now needsstring.format:
lua
assert(radius >= 1, string.format("The radius must be at least 1, not %d.", radius))
`
- Breaking Change: An unknown block or item id is an error**
Block:new("stne") gave air, so spell.block = Block:new("stne") deleted the block there, and Item:new("stne") gave an empty item, all without a word. Now they raise an error, and so do the ignored block ids of spell:copyStructure and spell:pasteStructure, where a misspelled id left out all air.Breaking Change: [PlayerDropItemEvent](https://wizards-of-lua.net/api/PlayerDropItemEvent/) can be canceled, and event.droppedItem is now event.item**The event now comes before the item leaves the player, so it carries an Item instead of an ItemEntity. A canceled item goes back into the inventory; if it can't, it is deleted, so it never drops. What a player loses on death fires no event.Breaking Change: [raycast](https://wizards-of-lua.net/api/Spell/#raycast) and [raycastBlock](https://wizards-of-lua.net/api/Spell/#raycastBlock) return nil if nothing was hit**For spells and entities alike, as raycastEntity always did. They gave a result of the type "miss" before, with its position at the end of the ray, so if hit then was always true. HitType has no "miss" any more.Breaking Change: Item components are read without the namespace minecraft:**item.nbt.components.custom_name instead of item.nbt.components["minecraft:custom_name"], also in the components of the enchantments and of items in chests, entities and structures. Keys in custom_data stay as they are. Writing and NBT paths take both forms.Breaking Change: WizardsOfLua.setCommand refuses a pattern that could never run**A placeholder next to an argument of an existing command, like time set %i, was accepted, but Minecraft always took its own command. It now raises an error. New words still work, like time warp %i.Breaking Change: String patterns work on bytes, as in Lua 5.3** string.find, match, gmatch and gsub worked on decoded text while #, sub and byte count bytes, so s:sub(s:find("x")) was off in a text with an umlaut, and gsub damaged binary data. Now a . takes one byte, which is half of an ä, and classes mean what they mean in Lua: %a, %l and %u take only A to Z, %p all punctuation, %s and %c only ASCII. To go through a text by characters, use utf8.charpattern.Breaking Change: SpellFinishEvent` is now [SpellFinishedEvent](https://wizards-of-lua.net/api/SpellFinishedEvent/)**