A basic scripting engine for paper in lua
LuScript is a high-performance scripting engine designed to bring the lightweight flexibility of Lua to Spigot and Paper servers. Built as a powerful alternative to traditional scripting engines like Skript, it removes complex language parsing in favor of standard coding paradigms.
LuScript allows developers to write server logic using the clean, efficient syntax of Lua while maintaining direct access to powerful server-side capabilities like native permissions, dynamic command registration, and inter-script communication.
LuScript embeds a secure Lua VM directly into your Minecraft server. It maps Bukkit's internal systems—commands, events, and tasks—into simple Lua functions. When you save a script and run /luscript reload [script.lua], the engine instantly unloads the old logic, clears registered listeners, removes dynamically created commands, and injects the new code without requiring a server restart, player re-logins, or resetting other active scripts.
Unload and reload specific scripts on the fly. Running /luscript reload <filename.lua> selectively tears down and rebuilds only the event listeners, custom commands, and global signals belonging to that specific script, leaving all other active server scripts untouched.
No more parsing messy, wall-of-text Java stacktrace dumps when a script fails. LuScript dynamically captures both load-time syntax errors and runtime execution exceptions:
LuScript automatically wraps Bukkit's coordinates into smart Lua tables. These tables fully support fluent, chainable method syntax directly in Lua:
loc.getDirection(): Returns a direction vector table with .getX(), .getY(), and .getZ() helper getters.loc.clone(): Returns an isolated, exact clone of the location table.loc.add(dx, dy, dz): Offsets the coordinate parameters dynamically and returns the modified location table.loc.add(x, y, z)) and colon (loc:add(x, y, z)) calling conventions.Read block states anywhere in the world using GetBlock(location). Easily inspect block properties such as whether a block is solid, is air, or get its material type. Perfect for writing collision-safe teleportation mechanics, custom break events, or interaction constraints.
Register complex commands with dynamic tab-completion and native permissions without editing a single plugin.yml.
RegisterCommand("heal", {
permission = "luscript.command.heal",
usage = "/heal [player]",
tabComplete = function(sender, args)
if #args == 1 then
return {"@a", "@p", sender.getName()}
end
end,
execute = function(sender, args)
local target = sender
if #args > 0 then
target = GetPlayer(args[1])
end
if target then
target.setHealth(20)
sender.sendMessage("&aHealed " .. target.getName())
else
sender.sendMessage("&cPlayer not found.")
end
end
})
Allow multiple scripts to communicate through a global signal bus. Perfect for decoupled, multi-file systems.
-- Script A
RegisterCommand("alert", {
execute = function(sender, args)
EmitSignal("AdminAlert", { user = sender.getName(), msg = args[1] })
end
})
-- Script B
OnSignal("AdminAlert", function(data)
print("ALERT: " .. data.user .. " sent: " .. (data.msg or "nothing"))
end)
Combine the Custom Item Engine and the Block Inspection API to create a sword that teleports players forward only if they won't end up inside solid blocks.
RegisterCommand("godsword", {
execute = function(sender, args)
local item = CreateItem("diamond_sword", 1)
item.setName("&6&lGod Sword")
item.setLore({
"&7A sword with ancient powers.",
"&eRight-click to teleport forward!"
})
item.addEnchant("sharpness", 10)
item.addEnchant("fire_aspect", 2)
sender.giveItem(item)
sender.sendMessage("&eYou received the &6&lGod Sword&e!")
end
})
RegisterEvent("player_interact", function(event)
local player = event.player
local item = event.item
local action = event.action
if item and item.getType() == "diamond_sword" then
if action == "right_click_air" or action == "right_click_block" then
player.sendMessage("&bSwoosh! Teleporting...")
local loc = player.getLocation()
local dir = loc.getDirection()
-- Calculate landing coordinates
local targetLocation = loc.clone().add(dir.getX() * 10, dir.getY() * 10, dir.getZ() * 10)
-- Check if path is clear (feet & head space)
local blockFeet = GetBlock(targetLocation)
local blockHead = GetBlock(targetLocation.clone().add(0, 1, 0))
if blockFeet.isSolid or blockHead.isSolid then
player.sendMessage("&cTeleport path is blocked by solid blocks!")
else
player.teleport(targetLocation)
end
end
end
end)
/luscript reload <filename.lua> without interrupting players or resetting other active scripts.io, os, luajava), ensuring absolute safety for production environments.