| Method | Description |
|---|---|
api.registerCommand(name, executor) | Register simple command |
api.registerCommand(name, desc, usage, executor) | Register command with description |
api.registerCommand(name, desc, usage, executor, completer) | Register command with tab completion |
š Getting Started
Installation
Requirements
- Minecraft Server: Paper/Spigot 1.20+
- Java: Version 21 or higher
- Minecraft Version: 1.20+
- Download the latest release
- Place the JAR file in your server's
plugins/folder - Start or restart your server
- Create JS plugins in
plugins/MC-JS/js-plugins/
Your First Plugin
Create a new file in plugins/MC-JS/js-plugins/ with a .js extension:
// Plugin metadata (optional but recommended)
var pluginInfo = {
name: "My First Plugin",
version: "1.0.0",
author: "YourName",
description: "My awesome first plugin!"
};
// Get MC-JS version
var mcjsVersion = api.getMCJSVersion();
logger.info("Running on MC-JS " + mcjsVersion);
function onEnable() {
logger.info("My plugin is enabled!");
// Register a simple command
api.registerCommand("hello", "Say hello", "/hello", function(sender, args) {
api.sendMessage(sender, "&aHello from JavaScript!");
return true;
});
// Register a player join event
api.registerEvent("player.PlayerJoinEvent", function(event) {
var player = event.getPlayer();
api.sendMessage(player, "&6Welcome to the server!");
});
}
function onDisable() {
logger.info("My plugin is disabled!");
}
// Export functions and metadata
this.onEnable = onEnable;
this.onDisable = onDisable;
this.pluginInfo = pluginInfo;
/jsreload or restart the server, then test with /hello
š Complete API Reference
api- Complete JS API wrapperserver- Minecraft server instanceplugin- Main plugin instancelogger- Plugin logger (logger.info(), logger.warning(), etc.)scheduler- Server schedulerBukkit- Bukkit API access
š¬ Command Registration
Simple Command
api.registerCommand("command", function(sender, args) {
api.sendMessage(sender, "Command executed!");
return true; // Return true for success, false for failure
});
Command with Description and Usage
api.registerCommand("command", "Description", "/command [args]",
function(sender, args) {
if (args.length > 0) {
api.sendMessage(sender, "You said: " + args[0]);
} else {
api.sendMessage(sender, "&cUsage: /command <message>");
}
return true;
}
);
Command with Tab Completion
api.registerCommand("command", "Description", "/command [player]",
function(sender, args) {
// Command executor
var target = api.getPlayer(args[0]);
if (target) {
api.sendMessage(sender, "Found player: " + target.getName());
}
return true;
},
function(sender, args) {
// Tab completer - return array of strings
if (args.length === 1) {
return api.getPlayerNames(); // Return all online player names
}
return [];
}
);
š® Event Registration
Basic Event
api.registerEvent("player.PlayerJoinEvent", function(event) {
var player = event.getPlayer();
api.sendMessage(player, "&aWelcome to the server!");
});
Event with Priority
api.registerEvent("block.BlockBreakEvent", function(event) {
var player = event.getPlayer();
var block = event.getBlock();
// Cancel the event
event.setCancelled(true);
api.sendMessage(player, "&cYou cannot break blocks here!");
}, "HIGH"); // Priorities: LOWEST, LOW, NORMAL, HIGH, HIGHEST, MONITOR
Available Event Packages
| Package | Examples |
|---|---|
player.* |
PlayerJoinEvent, PlayerQuitEvent, PlayerDeathEvent |
block.* |
BlockBreakEvent, BlockPlaceEvent, BlockClickEvent |
entity.* |
EntityDamageEvent, EntitySpawnEvent |
inventory.* |
InventoryClickEvent, InventoryCloseEvent |
server.* |
ServerLoadEvent, PluginEnableEvent |
ā° Task Scheduling
Delayed Task
// Run after 5 seconds (100 ticks = 5 seconds, 20 ticks = 1 second)
api.runTaskLater(100, function() {
logger.info("This runs after 5 seconds");
api.broadcast("&a5 seconds have passed!");
});
Repeating Task
// Run every minute (1200 ticks = 60 seconds)
var task = api.runTaskTimer(0, 1200, function() {
var playerCount = api.getOnlinePlayers().size();
logger.info("Server has " + playerCount + " player(s) online");
});
// Cancel the task later
api.runTaskLater(6000, function() {
api.cancelTask(task);
logger.info("Task cancelled after 5 minutes");
});
Async Task
// Run in a separate thread (for non-blocking operations)
api.runTaskAsync(function() {
// This won't block the main server thread
var response = api.httpGet("https://api.example.com/data");
logger.info("Fetched data: " + response);
// Update something on the main thread
api.runTask(function() {
api.broadcast("&aData fetched successfully!");
});
});
| Method | Description |
|---|---|
api.runTask(task) |
Run task on next tick |
api.runTaskLater(delay, task) |
Run task after delay (in ticks) |
api.runTaskTimer(delay, period, task) |
Run repeating task |
api.runTaskAsync(task) |
Run task asynchronously |
api.runTaskLaterAsync(delay, task) |
Run delayed async task |
api.cancelTask(task) |
Cancel a running task |
š¤ Player Management
Get Players
// Get player by name
var player = api.getPlayer("PlayerName");
if (player) {
api.sendMessage(player, "Hello!");
}
// Get exact player name (case-sensitive)
var exactPlayer = api.getPlayerExact("ExactPlayerName");
// Get all online players
var allPlayers = api.getOnlinePlayers();
for (var i = 0; i < allPlayers.length; i++) {
var p = allPlayers[i];
logger.info("Online: " + p.getName());
}
Send Messages
// Send message to player
api.sendMessage(player, "&aHello &bWorld!");
// Broadcast to all players
api.broadcast("&6Server announcement!");
// Broadcast with permission
api.broadcast("&cAdmin message!", "admin.message");
// Send title
api.sendTitle(player, "&aWelcome!", "&eEnjoy your stay!", 10, 70, 20);
// Send action bar
api.sendActionBar(player, "&bYou are in the spawn area!");
Player Properties
// Health
api.setHealth(player, 20.0);
var health = api.getHealth(player);
var maxHealth = api.getMaxHealth(player);
// Food
api.setFoodLevel(player, 20);
var food = api.getFoodLevel(player);
api.setSaturation(player, 5.0);
// Inventory
api.clearInventory(player); // Clear player inventory (including armor)
// Game Mode
api.setGameMode(player, GameMode.CREATIVE);
var gamemode = api.getGameMode(player);
// Teleportation
var location = api.createLocation(world, 100, 64, 200);
api.teleport(player, location);
// Experience
api.setLevel(player, 10);
api.setExp(player, 0.5);
api.giveExp(player, 100);
š¦ Inventory & Items
Create Inventory
// Create custom inventory (27 = 3 rows)
var inv = api.createInventory(null, 27, "&6My Custom GUI");
// Create inventory by type
var chest = api.createInventory(null, InventoryType.CHEST, "&bChest Menu");
// Create custom inventory (simplified, no holder needed)
var customInv = api.createCustomInventory(27, "&6Custom GUI");
// Create custom inventory with rows (1-6 rows)
var gui = api.createCustomInventory(3, "&bMy Menu", true); // 3 rows = 27 slots
GUI Builder Pattern (Recommended)
// Create a GUI builder for easy inventory creation
var gui = api.createGUI("&6My Custom Menu", 3); // 3 rows
// Set items with slot-specific click handlers
var item1 = api.createItemStack(api.getMaterial("DIAMOND"), 1);
item1 = api.setItemDisplayName(item1, "&bDiamond Option");
gui.setItem(10, item1, function(event) {
event.setCancelled(true);
api.sendMessage(event.getWhoClicked(), "&aYou clicked the diamond!");
});
var item2 = api.createItemStack(api.getMaterial("EMERALD"), 1);
item2 = api.setItemDisplayName(item2, "&aEmerald Option");
gui.setItem(16, item2, function(event) {
event.setCancelled(true);
api.sendMessage(event.getWhoClicked(), "&aYou clicked the emerald!");
});
// Fill borders with background item
var background = api.createItemStack(api.getMaterial("GRAY_STAINED_GLASS_PANE"), 1);
background = api.setItemDisplayName(background, " ");
gui.fillBorders(background);
// Set background for empty slots
gui.setBackground(background);
// Prevent items from being removed from the GUI (default: false)
gui.setAllowItemRemoval(false);
// Global click handler (called for all clicks)
gui.onClick(function(event) {
// This runs for every click, even if slot has specific handler
var slot = event.getSlot();
// Do something...
});
// Close handler
gui.onClose(function(event) {
var player = event.getPlayer();
api.sendMessage(player, "&7You closed the menu");
});
// Build and open for player
var inventory = gui.buildAndOpen(player);
// Or build without opening
var inv = gui.build();
player.openInventory(inv);
Create Items with Enchantments
// Create item stack
var sword = api.createItemStack(api.getMaterial("DIAMOND_SWORD"), 1);
// Set display name
sword = api.setItemDisplayName(sword, "&b&lMagic Sword");
// Add enchantments
api.addEnchantment(sword, "SHARPNESS", 5);
api.addEnchantment(sword, "FIRE_ASPECT", 2);
api.addEnchantment(sword, "UNBREAKING", 3);
// Check enchantments
if (api.hasEnchantment(sword, "SHARPNESS")) {
var level = api.getEnchantmentLevel(sword, "SHARPNESS");
logger.info("Sword has Sharpness level " + level);
}
// Get all enchantments
var enchantments = api.getEnchantments(sword);
for (var enchantName in enchantments) {
logger.info(enchantName + ": " + enchantments[enchantName]);
}
// Remove enchantment
api.removeEnchantment(sword, "FIRE_ASPECT");
// Set lore
sword = api.setItemLore(sword, [
"&7This is a special diamond",
"&7given by the JS plugin!",
"&eRight-click to use"
]);
// Give item to player
api.giveItem(player, diamond);
// Set item in inventory slot
api.setInventoryItem(inv, 0, diamond);
// Fill entire inventory
api.fillInventory(inv, diamond);
// Fill range
api.fillInventoryRange(inv, diamond, 0, 8);
Inventory Events
// Register click handler
api.registerInventoryClick(inv, function(event) {
event.setCancelled(true); // Prevent item movement
var slot = event.getSlot();
var player = event.getWhoClicked();
api.sendMessage(player, "&aYou clicked slot " + slot);
if (slot === 10) {
// Do something when slot 10 is clicked
api.giveItem(player, api.createItemStack(api.getMaterial("DIAMOND"), 5));
}
});
// Register close handler
api.registerInventoryClose(inv, function(event) {
var player = event.getPlayer();
api.sendMessage(player, "&7You closed the inventory");
});
Custom Inventory Holder
// Create a custom inventory holder for advanced usage
var holder = api.createInventoryHolder();
// Store custom data in the holder
holder.setData("menuType", "shop");
holder.setData("player", player);
// Create inventory with custom holder
var inv = api.createInventoryWithHolder(holder, 27, "&6Shop Menu");
// Get holder from inventory
var invHolder = api.getInventoryHolder(inv);
if (invHolder) {
var menuType = invHolder.getData("menuType");
var storedPlayer = invHolder.getData("player");
}
// Check if inventory has custom holder
if (api.isCustomInventory(inv)) {
// This is a custom inventory
}
// Get handlers from custom inventory
var slotHandler = api.getSlotClickHandler(inv, 10);
var globalHandler = api.getGlobalClickHandler(inv);
šļø Database Operations
Create Table
api.createTable("mydb", "players", {
"id": "INTEGER PRIMARY KEY AUTOINCREMENT",
"name": "TEXT NOT NULL",
"level": "INTEGER DEFAULT 1",
"coins": "INTEGER DEFAULT 0",
"last_seen": "INTEGER"
});
Insert Data
api.insertData("mydb", "players", {
"name": "PlayerName",
"level": 10,
"coins": 1000,
"last_seen": api.getCurrentTimeMillis()
});
Update Data
api.updateData("mydb", "players",
{ "level": 20, "coins": 2000 },
"name = 'PlayerName'"
);
Query Data
var results = api.querySQL("mydb",
"SELECT * FROM players WHERE level > 5"
);
for (var i = 0; i < results.length; i++) {
var row = results[i];
logger.info("Player: " + row.name + ", Level: " + row.level);
}
Delete Data
// Delete specific rows
api.deleteData("mydb", "players", "last_seen < " + (api.getCurrentTimeMillis() - 86400000));
// Count rows
var count = api.countRows("mydb", "players");
var activeCount = api.countRows("mydb", "players", "last_seen > " + (api.getCurrentTimeMillis() - 86400000));
š World & Block Management
World Operations
// Get worlds
var world = api.getWorld("world");
var allWorlds = api.getWorlds();
// Time control
api.setWorldTime(world, 6000); // Set to noon
var time = api.getWorldTime(world);
// Weather control
api.setStorm(world, true);
api.setThundering(world, true);
var hasStorm = api.hasStorm(world);
var isThundering = api.isThundering(world);
// World border
var border = api.getWorldBorder(world);
api.setWorldBorderSize(world, 1000);
api.setWorldBorderCenter(world, 0, 0);
Block Operations
// Get block
var block = api.getBlock(location);
var blockType = api.getBlockType(location);
// Set block
api.setBlockType(location, api.getMaterial("DIAMOND_BLOCK"));
// Break block
api.breakBlock(location);
api.breakBlock(location, false); // Don't drop items
// Get block at coordinates
var block = api.getBlockAt(world, 100, 64, 200);
// Get blocks in radius
var blocks = api.getBlocksInRadius(centerLocation, 5.0);
for (var i = 0; i < blocks.length; i++) {
logger.info("Block: " + blocks[i].getType().name());
}
Explosions & Lightning
// Create explosion
api.createExplosion(location, 5.0); // Power 5
api.createExplosion(location, 5.0, true); // With fire
// Strike lightning
api.strikeLightning(location);
api.strikeLightningEffect(location); // Visual only, no damage
šÆ Entity Management
Spawn Entities
// Spawn entity (string or enum)
var zombie = api.spawnEntity(location, "ZOMBIE");
var creeper = api.spawnEntity(location, EntityType.CREEPER);
// Entity properties
api.setEntityCustomName(zombie, "&cCustom Zombie");
api.setEntityGlowing(zombie, true);
api.setEntityGravity(zombie, false);
api.setEntityInvulnerable(zombie, true);
// Remove entity
api.removeEntity(zombie);
š File Operations
YAML Files
// Save YAML
var data = {
"server": {
"name": "My Server",
"maxPlayers": 100
},
"settings": {
"pvp": true,
"spawnProtection": true
}
};
api.saveYamlFile("config", data);
// Load YAML
// Note: loadYamlFile returns a Java Map object, use .get() to access values
var config = api.loadYamlFile("config");
var serverName = config.get("server").get("name");
// For simple values, you can use direct access (works in Rhino)
var serverName2 = config.get("server").get("name");
// Working with arrays in YAML:
var bansData = api.loadYamlFile("bansystem_bans");
var bansList = bansData.get("bans"); // Java List
var nextId = bansData.get("nextId");
// Convert Java List to JavaScript array if needed
var bans = [];
if (bansList instanceof java.util.List) {
for (var i = 0; i < bansList.size(); i++) {
var banObj = bansList.get(i);
// Convert Java Map to JavaScript object
var ban = {};
if (banObj instanceof java.util.Map) {
var keys = banObj.keySet().toArray();
for (var j = 0; j < keys.length; j++) {
var key = keys[j];
ban[key] = banObj.get(key);
}
}
bans.push(ban);
}
}
JSON Files
// Save JSON
var jsonData = {
"players": ["Player1", "Player2"],
"timestamp": api.getCurrentTimeMillis()
};
api.saveJsonFile("data", JSON.stringify(jsonData, null, 2));
// Load JSON
var json = api.loadJsonFile("data");
var data = JSON.parse(json);
Text Files
// Save text
api.saveTextFile("log", "Line 1\nLine 2\nLine 3");
// Load text
var content = api.loadTextFile("log");
logger.info("File content: " + content);
Config System
// Get plugin config
var config = api.getPluginConfig("myplugin");
// Get config value with default
var setting = api.getPluginConfigValue("myplugin", "setting", "default");
// Set config value
api.setPluginConfigValue("myplugin", "setting", "new value");
// Save entire config
api.savePluginConfig("myplugin", {
"setting1": "value1",
"setting2": "value2"
});
ā±ļø Cooldown System
Basic Cooldown
// Check cooldown
if (!api.hasCooldown(player.getName(), "command")) {
// Execute command
api.setCooldown(player.getName(), "command", 5000); // 5 seconds
} else {
var remaining = api.getCooldownRemaining(player.getName(), "command");
api.sendMessage(player, "&cCooldown: " + Math.ceil(remaining / 1000) + " seconds");
}
// Remove cooldown
api.removeCooldown(player.getName(), "command");
// Clear all cooldowns for player
api.clearCooldowns(player.getName());
šØ BossBar
Create and Manage BossBar
// Create boss bar (with enum or string)
var bossBar = api.createBossBar("&cBoss Fight!", "RED", "SOLID");
// Or: api.createBossBar("&cBoss Fight!", BarColor.RED, BarStyle.SOLID);
// Add players
bossBar.addPlayer(player);
bossBar.addAll(api.getOnlinePlayers());
// Update progress (0.0 to 1.0)
bossBar.setProgress(0.5); // 50%
// Update title
bossBar.setTitle("&6New Title");
// Remove players
bossBar.removePlayer(player);
bossBar.removeAll();
// Available colors: BLUE, GREEN, PINK, PURPLE, RED, WHITE, YELLOW
// Available styles: SOLID, SEGMENTED_6, SEGMENTED_10, SEGMENTED_12, SEGMENTED_20
š” Complete Examples
Example 1: Welcome Plugin
var pluginInfo = {
name: "Welcome Plugin",
version: "1.0.0",
author: "YourName"
};
function onEnable() {
api.registerEvent("player.PlayerJoinEvent", function(event) {
var player = event.getPlayer();
// Welcome message
api.sendMessage(player, "&6Welcome to the server, &b" + player.getName() + "&6!");
// Title
api.sendTitle(player, "&aWelcome!", "&eEnjoy your stay!", 10, 70, 20);
// Sound
api.playSound(player, "ENTITY_PLAYER_LEVELUP", 1.0, 1.0);
// Give welcome kit after 1 second
api.runTaskLater(20, function() {
var bread = api.createItemStack(api.getMaterial("BREAD"), 5);
var sword = api.createItemStack(api.getMaterial("WOODEN_SWORD"), 1);
api.giveItem(player, bread);
api.giveItem(player, sword);
api.sendMessage(player, "&aYou received a welcome kit!");
});
});
}
this.onEnable = onEnable;
this.pluginInfo = pluginInfo;
Example 2: Stats Plugin with Database
var pluginInfo = {
name: "Stats Plugin",
version: "1.0.0"
};
function onEnable() {
// Create database
api.createTable("stats", "player_stats", {
"player_name": "TEXT PRIMARY KEY",
"kills": "INTEGER DEFAULT 0",
"deaths": "INTEGER DEFAULT 0",
"playtime": "INTEGER DEFAULT 0"
});
// Stats command
api.registerCommand("stats", "View your stats", "/stats [player]",
function(sender, args) {
var targetName = args.length > 0 ? args[0] : sender.getName();
var results = api.querySQL("stats",
"SELECT * FROM player_stats WHERE player_name = '" + targetName + "'");
if (results.length > 0) {
var stats = results[0];
api.sendMessage(sender, "&6=== Stats for " + targetName + " ===");
api.sendMessage(sender, "&eKills: &a" + stats.kills);
api.sendMessage(sender, "&eDeaths: &c" + stats.deaths);
api.sendMessage(sender, "&ePlaytime: &b" + Math.floor(stats.playtime / 3600) + " hours");
} else {
api.sendMessage(sender, "&cNo stats found for " + targetName);
}
return true;
},
function(sender, args) {
return api.getPlayerNames();
}
);
// Track player deaths
api.registerEvent("entity.PlayerDeathEvent", function(event) {
var killer = event.getEntity().getKiller();
var victim = event.getEntity();
if (killer) {
// Update killer stats
var killerStats = api.querySQL("stats",
"SELECT kills FROM player_stats WHERE player_name = '" + killer.getName() + "'");
if (killerStats.length > 0) {
api.updateData("stats", "player_stats",
{ "kills": killerStats[0].kills + 1 },
"player_name = '" + killer.getName() + "'");
} else {
api.insertData("stats", "player_stats", {
"player_name": killer.getName(),
"kills": 1,
"deaths": 0
});
}
}
// Update victim stats
var victimStats = api.querySQL("stats",
"SELECT deaths FROM player_stats WHERE player_name = '" + victim.getName() + "'");
if (victimStats.length > 0) {
api.updateData("stats", "player_stats",
{ "deaths": victimStats[0].deaths + 1 },
"player_name = '" + victim.getName() + "'");
} else {
api.insertData("stats", "player_stats", {
"player_name": victim.getName(),
"kills": 0,
"deaths": 1
});
}
});
}
this.onEnable = onEnable;
this.pluginInfo = pluginInfo;
Example 3: Custom GUI Menu (Old Method)
var pluginInfo = {
name: "Menu Plugin",
version: "1.0.0"
};
function onEnable() {
api.registerCommand("menu", "Open custom menu", "/menu", function(sender, args) {
if (!(sender instanceof Player)) {
api.sendMessage(sender, "&cOnly players can use this command!");
return false;
}
var player = sender;
var inv = api.createInventory(null, 27, "&6Custom Menu");
// Option 1
var item1 = api.createItemStack(api.getMaterial("DIAMOND"), 1);
item1 = api.setItemDisplayName(item1, "&bOption 1");
item1 = api.setItemLore(item1, ["&7Click to get diamonds!"]);
api.setInventoryItem(inv, 10, item1);
// Option 2
var item2 = api.createItemStack(api.getMaterial("EMERALD"), 1);
item2 = api.setItemDisplayName(item2, "&aOption 2");
item2 = api.setItemLore(item2, ["&7Click to get emeralds!"]);
api.setInventoryItem(inv, 16, item2);
// Close button
var close = api.createItemStack(api.getMaterial("BARRIER"), 1);
close = api.setItemDisplayName(close, "&cClose Menu");
api.setInventoryItem(inv, 22, close);
// Register click handler
api.registerInventoryClick(inv, function(event) {
event.setCancelled(true);
var slot = event.getSlot();
if (slot === 10) {
api.sendMessage(player, "&aYou clicked Option 1!");
api.giveItem(player, api.createItemStack(api.getMaterial("DIAMOND"), 5));
} else if (slot === 16) {
api.sendMessage(player, "&aYou clicked Option 2!");
api.giveItem(player, api.createItemStack(api.getMaterial("EMERALD"), 5));
} else if (slot === 22) {
player.closeInventory();
}
});
player.openInventory(inv);
return true;
});
}
this.onEnable = onEnable;
this.pluginInfo = pluginInfo;
Example 4: GUI Builder Pattern (Recommended)
var pluginInfo = {
name: "Shop Plugin",
version: "1.0.0"
};
function onEnable() {
api.registerCommand("shop", "Open shop", "/shop", function(sender, args) {
if (!(sender instanceof Player)) {
api.sendMessage(sender, "&cOnly players can use this command!");
return false;
}
var player = sender;
// Create GUI with builder pattern
var gui = api.createGUI("&6&lShop Menu", 3);
// Background item
var bg = api.createItemStack(api.getMaterial("GRAY_STAINED_GLASS_PANE"), 1);
bg = api.setItemDisplayName(bg, " ");
gui.fillBorders(bg);
gui.setBackground(bg);
// Shop item 1 - Diamond Sword
var sword = api.createItemStack(api.getMaterial("DIAMOND_SWORD"), 1);
sword = api.setItemDisplayName(sword, "&bDiamond Sword");
sword = api.setItemLore(sword, [
"&7Price: &a100 Coins",
"&7Click to purchase!"
]);
gui.setItem(10, sword, function(event) {
event.setCancelled(true);
api.sendMessage(player, "&aYou purchased a Diamond Sword!");
api.giveItem(player, sword);
});
// Shop item 2 - Golden Apple
var apple = api.createItemStack(api.getMaterial("GOLDEN_APPLE"), 1);
apple = api.setItemDisplayName(apple, "&eGolden Apple");
apple = api.setItemLore(apple, [
"&7Price: &a50 Coins",
"&7Click to purchase!"
]);
gui.setItem(13, apple, function(event) {
event.setCancelled(true);
api.sendMessage(player, "&aYou purchased a Golden Apple!");
api.giveItem(player, apple);
});
// Shop item 3 - Enchanted Book
var book = api.createItemStack(api.getMaterial("ENCHANTED_BOOK"), 1);
book = api.setItemDisplayName(book, "&dEnchanted Book");
book = api.setItemLore(book, [
"&7Price: &a200 Coins",
"&7Click to purchase!"
]);
gui.setItem(16, book, function(event) {
event.setCancelled(true);
api.sendMessage(player, "&aYou purchased an Enchanted Book!");
api.giveItem(player, book);
});
// Close button
var close = api.createItemStack(api.getMaterial("BARRIER"), 1);
close = api.setItemDisplayName(close, "&cClose Shop");
gui.setItem(22, close, function(event) {
event.setCancelled(true);
player.closeInventory();
});
// Global click handler (optional)
gui.onClick(function(event) {
// Log all clicks for debugging
// api.sendMessage(player, "&7Debug: Clicked slot " + event.getSlot());
});
// Close handler
gui.onClose(function(event) {
api.sendMessage(player, "&7Shop closed. Come back soon!");
});
// Build and open
gui.buildAndOpen(player);
return true;
});
}
this.onEnable = onEnable;
this.pluginInfo = pluginInfo;
Example 4: Advanced Cooldown System
var pluginInfo = {
name: "Cooldown Example",
version: "1.0.0"
};
function onEnable() {
api.registerCommand("heal", "Heal yourself", "/heal", function(sender, args) {
if (!(sender instanceof Player)) {
api.sendMessage(sender, "&cOnly players can use this!");
return false;
}
var player = sender;
var cooldownKey = "heal";
if (api.hasCooldown(player.getName(), cooldownKey)) {
var remaining = api.getCooldownRemaining(player.getName(), cooldownKey);
api.sendMessage(player, "&cCooldown: " + Math.ceil(remaining / 1000) + " seconds");
return false;
}
// Heal player
api.setHealth(player, api.getMaxHealth(player));
api.setFoodLevel(player, 20);
api.sendMessage(player, "&aYou have been healed!");
// Set 30 second cooldown
api.setCooldown(player.getName(), cooldownKey, 30000);
return true;
});
}
this.onEnable = onEnable;
this.pluginInfo = pluginInfo;
Example 5: BossBar Progress Bar
var pluginInfo = {
name: "BossBar Example",
version: "1.0.0"
};
var bossBars = {};
function onEnable() {
api.registerEvent("player.PlayerJoinEvent", function(event) {
var player = event.getPlayer();
// Create boss bar
var bossBar = api.createBossBar("&aLoading...", "GREEN", "SOLID");
bossBar.addPlayer(player);
bossBars[player.getName()] = bossBar;
// Animate progress
var progress = 0;
var task = api.runTaskTimer(0, 5, function() {
if (!bossBars[player.getName()]) {
api.cancelTask(task);
return;
}
progress += 0.02;
if (progress > 1) {
progress = 1;
bossBar.setTitle("&aWelcome!");
api.cancelTask(task);
// Remove after 3 seconds
api.runTaskLater(60, function() {
bossBar.removeAll();
delete bossBars[player.getName()];
});
} else {
bossBar.setProgress(progress);
bossBar.setTitle("&aLoading... " + Math.floor(progress * 100) + "%");
}
});
});
api.registerEvent("player.PlayerQuitEvent", function(event) {
var player = event.getPlayer();
if (bossBars[player.getName()]) {
bossBars[player.getName()].removeAll();
delete bossBars[player.getName()];
}
});
}
this.onEnable = onEnable;
this.pluginInfo = pluginInfo;
Example 6: World Protection System
var pluginInfo = {
name: "World Protection",
version: "1.0.0"
};
var protectedRegions = [];
function onEnable() {
// Define protected region (spawn area)
var spawn = api.getWorlds()[0].getSpawnLocation();
protectedRegions.push({
center: spawn,
radius: 50
});
// Protect blocks
api.registerEvent("block.BlockBreakEvent", function(event) {
var player = event.getPlayer();
var block = event.getBlock();
if (isInProtectedRegion(block.getLocation())) {
if (!api.hasPermission(player, "protection.bypass")) {
event.setCancelled(true);
api.sendMessage(player, "&cYou cannot break blocks in the protected area!");
api.playSound(player, "ENTITY_VILLAGER_NO", 1.0, 1.0);
}
}
});
api.registerEvent("block.BlockPlaceEvent", function(event) {
var player = event.getPlayer();
var block = event.getBlock();
if (isInProtectedRegion(block.getLocation())) {
if (!api.hasPermission(player, "protection.bypass")) {
event.setCancelled(true);
api.sendMessage(player, "&cYou cannot place blocks in the protected area!");
}
}
});
// Visual indicator
api.registerEvent("player.PlayerMoveEvent", function(event) {
var player = event.getPlayer();
if (isInProtectedRegion(player.getLocation())) {
api.sendActionBar(player, "&cā Protected Area");
}
});
}
function isInProtectedRegion(location) {
for (var i = 0; i < protectedRegions.length; i++) {
var region = protectedRegions[i];
var distance = api.getDistance(location, region.center);
if (distance <= region.radius) {
return true;
}
}
return false;
}
this.onEnable = onEnable;
this.pluginInfo = pluginInfo;
š Complete API Reference
All Available Methods
This is a comprehensive list of all API methods available in MC-JS. Click on a category to expand:
ā”Command Methods (3 methods)
ā¼šÆEvent Methods (6 methods)
ā¼| Method | Description |
|---|---|
api.registerEvent(eventClassName, handler) | Register event by string name |
api.registerEvent(eventClass, handler, priority) | Register event with priority |
api.registerInventoryClick(inv, handler) | Register inventory click handler |
api.registerInventoryClose(inv, handler) | Register inventory close handler |
api.createCustomInventory(size, title) | Create custom inventory |
api.createGUI(title, rows) | Create GUI builder |
ā±ļøTask Methods (8 methods)
ā¼| Method | Description |
|---|---|
api.runTask(task) | Run task on next tick |
api.runTaskLater(delay, task) | Run task after delay (ticks) |
api.runTaskTimer(delay, period, task) | Run repeating task |
api.runTaskAsync(task) | Run async task |
api.runTaskLaterAsync(delay, task) | Run delayed async task |
api.runTaskSafe(task, onError) | Run task with error handler |
api.runTaskAsyncSafe(task, onError) | Run async task with error handler |
api.cancelTask(task) | Cancel running task |
š¤Player Methods (30+ methods)
ā¼| Method | Description |
|---|---|
api.getPlayer(name) | Get player by name |
api.getPlayerExact(name) | Get player by exact name |
api.getOnlinePlayers() | Get all online players |
api.getPlayerNames() | Get list of online player names |
api.sendMessage(sender, message) | Send message |
api.sendTitle(player, title, subtitle) | Send title |
api.sendActionBar(player, message) | Send action bar |
api.broadcast(message) | Broadcast to all |
api.broadcast(message, permission) | Broadcast with permission |
api.setHealth(player, health) | Set player health |
api.getHealth(player) | Get player health |
api.getMaxHealth(player) | Get max health |
api.setFoodLevel(player, level) | Set food level |
api.getFoodLevel(player) | Get food level |
api.setSaturation(player, saturation) | Set saturation |
api.getSaturation(player) | Get saturation |
api.clearInventory(player) | Clear player inventory (including armor) |
api.damage(player, damage) | Damage player |
api.setExp(player, exp) | Set experience (0.0-1.0) |
api.getExp(player) | Get experience (0.0-1.0) |
api.setLevel(player, level) | Set level |
api.getLevel(player) | Get level |
api.giveExp(player, amount) | Give experience points |
api.setGameMode(player, mode) | Set game mode |
api.getGameMode(player) | Get game mode |
api.teleport(player, location) | Teleport player |
api.teleport(entity, location) | Teleport entity |
api.getPlayerByUUID(uuid) | Get player by UUID |
api.getOfflinePlayer(name) | Get offline player |
api.getOfflinePlayerByUUID(uuid) | Get offline player by UUID |
api.isPlayerOnline(name/player) | Check if player is online |
api.kickPlayer(player, reason) | Kick player |
api.banPlayer(name, reason) | Ban player |
api.unbanPlayer(name) | Unban player |
api.isBanned(name) | Check if banned |
api.addToWhitelist(name) | Add to whitelist |
api.removeFromWhitelist(name) | Remove from whitelist |
api.isWhitelisted(name) | Check if whitelisted |
api.setWhitelistEnabled(enabled) | Enable/disable whitelist |
api.isWhitelistEnabled() | Check if whitelist enabled |
api.generateOfflineUUID(name) | Generate UUID for offline player |
Permission Methods
| Method | Description |
|---|---|
api.hasPermission(sender, permission) | Check permission (CommandSender) |
api.hasPermission(player, permission) | Check permission (Player) |
api.addPermission(player, permission) | Add permission to player |
api.removePermission(player, permission) | Remove permission from player |
api.isOp(player) | Check if player is OP |
api.setOp(player, op) | Set player OP status |
Player Data Methods
| Method | Description |
|---|---|
api.setPlayerMetadata(player, key, value) | Set player metadata |
api.getPlayerMetadata(player, key) | Get player metadata |
api.hasPlayerMetadata(player, key) | Check if player has metadata |
api.removePlayerMetadata(player, key) | Remove player metadata |
š¦Inventory & GUI Methods (20+ methods)
ā¼Basic Inventory Methods
| Method | Description |
|---|---|
api.createInventory(holder, size, title) | Create inventory |
api.createCustomInventory(size, title) | Create custom inventory (simplified) |
api.createCustomInventory(rows, title, useRows) | Create custom inventory by rows |
api.createGUI(title, rows) | Create GUI builder (recommended) |
api.createInventoryHolder() | Create custom inventory holder |
api.createInventoryWithHolder(holder, size, title) | Create inventory with custom holder |
api.getInventoryHolder(inv) | Get holder from inventory |
api.isCustomInventory(inv) | Check if custom inventory |
api.getSlotClickHandler(inv, slot) | Get slot-specific click handler |
api.getGlobalClickHandler(inv) | Get global click handler |
api.setInventoryItem(inv, slot, item) | Set item in slot |
GUI Builder Methods
| Method | Description |
|---|---|
gui.setItem(slot, item) | Set item at slot |
gui.setItem(slot, item, handler) | Set item with click handler |
gui.setItems(startSlot, endSlot, item) | Set items in range |
gui.fill(item) | Fill entire inventory |
gui.fillBorders(item) | Fill borders only |
gui.setBackground(item) | Set background for empty slots |
gui.onClick(handler) | Set global click handler |
gui.onClose(handler) | Set close handler |
gui.setAllowItemRemoval(allow) | Allow/prevent items from being removed from GUI (default: false) |
gui.build() | Build and return inventory |
gui.buildAndOpen(player) | Build and open for player |
Custom Inventory Holder Methods
| Method | Description |
|---|---|
holder.setData(key, value) | Store custom data |
holder.getData(key) | Get custom data |
holder.getAllData() | Get all custom data |
holder.removeData(key) | Remove custom data |
holder.clearData() | Clear all custom data |
Custom Inventory Management
| Method | Description |
|---|---|
api.updateInventoryItem(inv, slot, item) | Update item in custom inventory |
api.getInventoryItem(inv, slot) | Get item from custom inventory |
api.clearInventory(inventory) | Clear custom inventory (GUI) |
api.refreshInventory(inv) | Refresh/rebuild custom inventory |
api.isInventorySlotEmpty(inv, slot) | Check if slot is empty |
api.getFirstEmptySlot(inv) | Get first empty slot |
api.addItemToInventory(inv, item) | Add item to inventory |
api.removeItemFromInventory(inv, item) | Remove item from inventory |
api.inventoryContains(inv, item) | Check if inventory contains item |
api.inventoryContainsAtLeast(inv, item, amount) | Check if inventory has at least amount |
āļøItem Methods (15+ methods)
ā¼| Method | Description |
|---|---|
api.setInventoryItem(inv, slot, item) | Set item in slot |
api.getInventoryItem(inv, slot) | Get item from slot |
api.fillInventory(inv, item) | Fill entire inventory |
api.fillInventoryRange(inv, item, start, end) | Fill inventory range |
api.createItemStack(material, amount) | Create item stack |
api.setItemDisplayName(item, name) | Set item display name |
api.setItemLore(item, lore) | Set item lore |
api.giveItem(player, item) | Give item to player |
api.getItemInMainHand(player) | Get item in main hand |
api.setItemInMainHand(player, item) | Set item in main hand |
api.getItemInOffHand(player) | Get item in off hand |
api.setItemInOffHand(player, item) | Set item in off hand |
api.getItemMeta(item) | Get item meta |
api.setItemMeta(item, meta) | Set item meta |
Enchantment Methods
| Method | Description |
|---|---|
api.addEnchantment(item, name, level) | Add enchantment to item |
api.removeEnchantment(item, name) | Remove enchantment from item |
api.hasEnchantment(item, name) | Check if item has enchantment |
api.getEnchantmentLevel(item, name) | Get enchantment level |
api.getEnchantments(item) | Get all enchantments (returns Map) |
š¾Database Methods (7 methods)
ā¼| Method | Description |
|---|---|
api.createTable(dbName, tableName, columns) | Create database table |
api.insertData(dbName, tableName, data) | Insert data |
api.updateData(dbName, tableName, data, where) | Update data |
api.deleteData(dbName, tableName, where) | Delete data |
api.querySQL(dbName, sql) | Query database |
api.countRows(dbName, tableName) | Count rows |
api.executeSQL(dbName, sql) | Execute SQL |
šFile Methods (9 methods)
ā¼| Method | Description |
|---|---|
api.saveYamlFile(fileName, data) | Save YAML file (data as Map/Object) |
api.loadYamlFile(fileName) | Load YAML file (returns Java Map, use .get() to access values) |
api.saveJsonFile(fileName, content) | Save JSON file |
api.loadJsonFile(fileName) | Load JSON file (returns JSON string) |
api.saveTextFile(fileName, content) | Save text file |
api.loadTextFile(fileName) | Load text file (returns string) |
Important: loadYamlFile returns a Java Map object. Use .get(key) to access values. Arrays are returned as Java List objects. Use instanceof java.util.List to check and convert to JavaScript arrays if needed. See the YAML Files section above for examples.
āļøConfig Methods (4 methods)
ā¼| Method | Description |
|---|---|
api.getPluginConfig(pluginName) | Get plugin config |
api.savePluginConfig(pluginName, data) | Save plugin config |
api.getPluginConfigValue(pluginName, path) | Get config value |
api.setPluginConfigValue(pluginName, path, value) | Set config value |
ā³Cooldown Methods (5 methods)
ā¼| Method | Description |
|---|---|
api.hasCooldown(playerName, key) | Check cooldown |
api.setCooldown(playerName, key, duration) | Set cooldown (ms) |
api.getCooldownRemaining(playerName, key) | Get remaining time |
api.removeCooldown(playerName, key) | Remove cooldown |
api.clearCooldowns(playerName) | Clear all cooldowns |
BossBar Methods
| Method | Description |
|---|---|
api.createBossBar(title, color, style) | Create boss bar |
api.createBossBar(title, colorName, styleName) | Create boss bar (strings) |
Particle & Sound Methods
| Method | Description |
|---|---|
api.spawnParticle(loc, particle, count) | Spawn particles |
api.spawnParticle(loc, particleName, count, ...) | Spawn particles (string) |
api.playSound(loc, sound, volume, pitch) | Play sound at location |
api.playSound(player, sound, volume, pitch) | Play sound for player |
api.playSound(loc, soundName, volume, pitch) | Play sound (string) |
šWorld & Block Methods (20+ methods)
ā¼| Method | Description |
|---|---|
api.getWorld(name) | Get world by name |
api.getWorlds() | Get all worlds |
api.getWorldNames() | Get world names |
api.getWorldTime(world) | Get world time |
api.setWorldTime(world, time) | Set world time |
api.hasStorm(world) | Check if storming |
api.setStorm(world, storm) | Set storm |
api.isThundering(world) | Check if thundering |
api.setThundering(world, thundering) | Set thundering |
api.getBlock(location) | Get block |
api.getBlockType(location) | Get block type |
api.setBlockType(location, material) | Set block type |
api.breakBlock(location) | Break block |
api.breakBlock(location, dropItems) | Break block with drop option |
api.getBlocksInRadius(center, radius) | Get blocks in radius |
api.createExplosion(location, power) | Create explosion |
api.createExplosion(location, power, setFire) | Create explosion with fire |
api.strikeLightning(location) | Strike lightning |
api.strikeLightningEffect(location) | Strike lightning effect |
World Management Methods
| Method | Description |
|---|---|
api.setWorldDifficulty(world, difficulty) | Set world difficulty (PEACEFUL, EASY, NORMAL, HARD) |
api.getWorldDifficulty(world) | Get world difficulty |
api.setWorldPVP(world, pvp) | Enable/disable PvP |
api.isWorldPVP(world) | Check if PvP enabled |
api.setWorldSpawnLocation(world, location) | Set world spawn location |
api.getWorldSpawnLocation(world) | Get world spawn location |
api.setWorldKeepSpawnInMemory(world, keepLoaded) | Keep spawn in memory |
api.isWorldKeepSpawnInMemory(world) | Check if spawn kept in memory |
api.setWorldAutoSave(world, autoSave) | Enable/disable auto-save |
api.isWorldAutoSave(world) | Check if auto-save enabled |
api.getWorldEnvironment(world) | Get world environment |
api.getWorldSeed(world) | Get world seed |
š¾Entity Methods (15+ methods)
ā¼| Method | Description |
|---|---|
api.spawnEntity(location, type) | Spawn entity |
api.spawnEntity(location, typeName) | Spawn entity (string) |
api.getNearbyEntities(location, x, y, z) | Get nearby entities |
api.setEntityCustomName(entity, name) | Set entity name |
api.setEntityGlowing(entity, glowing) | Set glowing |
api.setEntityGravity(entity, gravity) | Set gravity |
api.setEntityInvulnerable(entity, invulnerable) | Set invulnerable |
api.setEntityAI(entity, ai) | Enable/disable AI |
api.hasEntityAI(entity) | Check if entity has AI |
api.setEntitySilent(entity, silent) | Set entity silent |
api.isEntitySilent(entity) | Check if entity is silent |
api.setEntityCollidable(entity, collidable) | Set entity collidable |
api.isEntityCollidable(entity) | Check if entity is collidable |
api.getEntityLocation(entity) | Get entity location |
api.teleportEntity(entity, location) | Teleport entity to location |
api.teleportEntity(entity, target) | Teleport entity to target entity |
api.removeEntity(entity) | Remove entity |
Scoreboard Methods
| Method | Description |
|---|---|
api.getMainScoreboard() | Get main scoreboard |
api.createScoreboard() | Create new scoreboard |
api.getTeam(scoreboard, name) | Get team |
api.createTeam(scoreboard, name) | Create team |
api.getObjective(scoreboard, name) | Get objective |
api.createObjective(scoreboard, name, criteria, displayName) | Create objective |
Potion Effect Methods
| Method | Description |
|---|---|
api.createPotionEffect(type, duration, amplifier) | Create potion effect |
api.createPotionEffect(type, duration, amplifier, ambient) | Create potion effect with ambient |
Location & Vector Methods
| Method | Description |
|---|---|
api.createLocation(world, x, y, z) | Create location |
api.createLocation(world, x, y, z, yaw, pitch) | Create location with rotation |
api.createVector(x, y, z) | Create vector |
api.getDistance(loc1, loc2) | Get distance between locations |
api.getDistanceSquared(loc1, loc2) | Get squared distance |
api.getMidpoint(loc1, loc2) | Get midpoint between locations |
Material Methods
| Method | Description |
|---|---|
api.getMaterial(name) | Get material by name |
api.isBlock(material) | Check if material is block |
api.isItem(material) | Check if material is item |
World Border Methods
| Method | Description |
|---|---|
api.getWorldBorder(world) | Get world border |
api.setWorldBorderSize(world, size) | Set world border size |
api.setWorldBorderCenter(world, x, z) | Set world border center |
Advancement Methods
| Method | Description |
|---|---|
api.grantAdvancement(player, key) | Grant advancement |
api.revokeAdvancement(player, key) | Revoke advancement |
Server & Plugin Methods
| Method | Description |
|---|---|
api.getMCJSVersion() | Get MC-JS plugin version |
api.getServerVersion() | Get server version |
api.getBukkitVersion() | Get Bukkit version |
api.getMaxPlayers() | Get max players |
api.getMotd() | Get MOTD |
api.isPluginEnabled(name) | Check if plugin enabled |
api.getPlugin(name) | Get plugin |
api.hasEconomy() | Check if economy available |
Logging Methods
| Method | Description |
|---|---|
api.logInfo(message) | Log info message |
api.logWarning(message) | Log warning message |
api.logError(message) | Log error message |
Random Methods
| Method | Description |
|---|---|
api.randomInt(min, max) | Random integer |
api.randomDouble(min, max) | Random double |
api.randomBoolean() | Random boolean |
String Utility Methods
| Method | Description |
|---|---|
api.format(format, ...args) | Format string |
api.join(delimiter, ...elements) | Join strings |
Utility Methods
| Method | Description |
|---|---|
api.colorize(text) | Colorize text |
api.stripColor(text) | Strip colors |
api.format(format, ...args) | Format string |
api.round(value, places) | Round number |
api.clamp(value, min, max) | Clamp value |
api.md5(input) | MD5 hash |
api.sha256(input) | SHA256 hash |
api.base64Encode(input) | Base64 encode |
api.base64Decode(input) | Base64 decode |
api.urlEncode(input) | URL encode |
api.urlDecode(input) | URL decode |
api.getCurrentTimeMillis() | Get current time (milliseconds) |
api.getCurrentTime() | Get current time (seconds) |
api.formatDate(timestamp) | Format date |
api.formatDate(timestamp, pattern) | Format date with pattern |
api.parseDate(dateString) | Parse date |
api.parseDate(dateString, pattern) | Parse date with pattern |
api.executeCommand(command) | Execute console command |
api.httpGet(url) | HTTP GET request |
api.httpPost(url, data) | HTTP POST request |
Validation Methods
| Method | Description |
|---|---|
api.isValidPlayer(player) | Check if valid online player |
api.isValidLocation(location) | Check if valid location |
api.isValidWorld(world) | Check if valid world |
api.isValidItemStack(item) | Check if valid item stack |
api.isValidEntity(entity) | Check if valid entity |
api.isValidInventory(inventory) | Check if valid inventory |
File Existence Methods
| Method | Description |
|---|---|
api.yamlFileExists(fileName) | Check if YAML file exists |
api.jsonFileExists(fileName) | Check if JSON file exists |
api.textFileExists(fileName) | Check if text file exists |
api.deleteYamlFile(fileName) | Delete YAML file |
api.deleteJsonFile(fileName) | Delete JSON file |
api.deleteTextFile(fileName) | Delete text file |
Database Methods (Additional)
| Method | Description |
|---|---|
api.countRows(dbName, tableName) | Count rows in table |
api.countRows(dbName, tableName, where) | Count rows with condition |
api.updateData(dbName, tableName, data, where) | Update data |
api.deleteData(dbName, tableName, where) | Delete data |
š§ Advanced Topics
BossBar
// Create boss bar
var bossBar = api.createBossBar("&cBoss Fight!", "RED", "SOLID");
bossBar.addPlayer(player);
bossBar.setProgress(0.5); // 50%
// Update progress
var progress = 0;
var task = api.runTaskTimer(0, 20, function() {
progress += 0.01;
if (progress > 1) progress = 0;
bossBar.setProgress(progress);
bossBar.setTitle("&cBoss: " + Math.floor(progress * 100) + "%");
});
// Remove after 10 seconds
api.runTaskLater(200, function() {
bossBar.removeAll();
api.cancelTask(task);
});
Permissions & Player Management
// Check permissions
if (api.hasPermission(player, "myplugin.use")) {
// Player has permission
}
// Add/remove permissions dynamically
api.addPermission(player, "myplugin.vip");
api.removePermission(player, "myplugin.vip");
// OP management
if (api.isOp(player)) {
api.sendMessage(player, "You are OP!");
}
api.setOp(player, true);
// Player metadata
api.setPlayerMetadata(player, "lastLogin", api.getCurrentTimeMillis());
var lastLogin = api.getPlayerMetadata(player, "lastLogin");
if (api.hasPlayerMetadata(player, "lastLogin")) {
logger.info("Last login: " + lastLogin);
}
// Whitelist management
api.addToWhitelist("PlayerName");
api.removeFromWhitelist("PlayerName");
if (api.isWhitelisted("PlayerName")) {
logger.info("Player is whitelisted");
}
api.setWhitelistEnabled(true);
Particles & Sounds
// Spawn particles (string or enum)
api.spawnParticle(location, "FIREWORK", 10, 0.5, 0.5, 0.5, 0.1);
api.spawnParticle(location, Particle.FLAME, 5, 0, 0, 0);
// Play sounds
api.playSound(location, "ENTITY_PLAYER_LEVELUP", 1.0, 1.0);
api.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 0.5, 1.5);
// Particle effect at player location
api.registerEvent("player.PlayerMoveEvent", function(event) {
var player = event.getPlayer();
if (player.isSprinting()) {
api.spawnParticle(player.getLocation(), "CLOUD", 3, 0, 0, 0);
}
});
Entity Manipulation
// Spawn entity
var zombie = api.spawnEntity(location, "ZOMBIE");
// Set properties
api.setEntityCustomName(zombie, "&cBoss Zombie");
api.setEntityGlowing(zombie, true);
api.setEntityGravity(zombie, false);
api.setEntityInvulnerable(zombie, true);
// AI control
api.setEntityAI(zombie, false); // Disable AI
if (!api.hasEntityAI(zombie)) {
logger.info("Zombie has no AI");
}
// Silent and collidable
api.setEntitySilent(zombie, true);
api.setEntityCollidable(zombie, false);
// Teleport entity
var targetLocation = api.createLocation(world, 100, 64, 200);
api.teleportEntity(zombie, targetLocation);
// Or teleport to another entity
api.teleportEntity(zombie, player);
// Get entity location
var entityLoc = api.getEntityLocation(zombie);
// Remove entity
api.removeEntity(zombie);
World Management
// Difficulty
api.setWorldDifficulty(world, "HARD");
var difficulty = api.getWorldDifficulty(world);
// PvP
api.setWorldPVP(world, true);
if (api.isWorldPVP(world)) {
logger.info("PvP is enabled");
}
// Spawn location
var spawnLoc = api.createLocation(world, 0, 64, 0);
api.setWorldSpawnLocation(world, spawnLoc);
var currentSpawn = api.getWorldSpawnLocation(world);
// Auto-save
api.setWorldAutoSave(world, false);
if (!api.isWorldAutoSave(world)) {
logger.info("Auto-save disabled");
}
// World info
var environment = api.getWorldEnvironment(world);
var seed = api.getWorldSeed(world);
logger.info("World: " + world.getName() + ", Seed: " + seed);
Validation & Error Handling
// Validate objects before use
var player = api.getPlayer("PlayerName");
if (api.isValidPlayer(player)) {
// Safe to use player
api.sendMessage(player, "Hello!");
} else {
logger.warning("Player not found or offline");
}
// Validate locations
var location = api.createLocation(world, 0, 64, 0);
if (api.isValidLocation(location)) {
api.teleport(player, location);
}
// Validate items
var item = api.getItemInMainHand(player);
if (api.isValidItemStack(item)) {
api.addEnchantment(item, "SHARPNESS", 1);
}
// Safe async tasks with error handling
api.runTaskAsyncSafe(function() {
// Async work here
var data = api.loadYamlFile("data");
// Process data...
}, function(error) {
// Error handler
logger.severe("Error in async task: " + error);
});
HTTP Requests
// GET request
api.runTaskAsync(function() {
var response = api.httpGet("https://api.example.com/data");
logger.info("Response: " + response);
// Parse JSON response
var data = JSON.parse(response);
// Update on main thread
api.runTask(function() {
api.broadcast("&aData fetched: " + data.message);
});
});
// POST request
api.runTaskAsync(function() {
var jsonData = JSON.stringify({
"player": "PlayerName",
"action": "join"
});
var response = api.httpPost("https://api.example.com/log", jsonData);
logger.info("POST response: " + response);
});
Utility Methods
// String utilities
var colored = api.colorize("&aHello &bWorld");
var stripped = api.stripColor(colored);
var formatted = api.format("Hello %s! You have %d items.", "Player", 5);
// Math utilities
var rounded = api.round(3.14159, 2); // 3.14
var clamped = api.clamp(150, 0, 100); // 100
// Encoding
var encoded = api.base64Encode("Hello World");
var decoded = api.base64Decode(encoded);
var md5 = api.md5("text");
var sha256 = api.sha256("text");
// Date/Time
var now = api.getCurrentTimeMillis();
var formatted = api.formatDate(now);
var customFormat = api.formatDate(now, "dd.MM.yyyy HH:mm");
var parsed = api.parseDate("2024-01-01 12:00:00");
// Distance
var distance = api.getDistance(loc1, loc2);
var midpoint = api.getMidpoint(loc1, loc2);
- Always wrap code in try-catch blocks for error handling
- Use async tasks for HTTP requests and heavy operations
- Clean up resources (cancel tasks, close connections) in onDisable
- Use cooldowns to prevent spam
- Cache frequently accessed data
⨠Best Practices
Error Handling
// Always wrap risky operations in try-catch
api.registerCommand("risky", "Risky command", "/risky", function(sender, args) {
try {
var player = api.getPlayer(args[0]);
if (!player) {
api.sendMessage(sender, "&cPlayer not found!");
return false;
}
// Risky operation
player.teleport(someLocation);
api.sendMessage(sender, "&aSuccess!");
return true;
} catch (e) {
logger.severe("Error in risky command: " + e);
api.sendMessage(sender, "&cAn error occurred!");
return false;
}
});
// Event handlers should also have error handling
api.registerEvent("player.PlayerJoinEvent", function(event) {
try {
var player = event.getPlayer();
// Your code here
} catch (e) {
logger.severe("Error in PlayerJoinEvent: " + e);
// Don't let errors break the event system
}
});
Performance Optimization
// ā BAD: Checking player every tick
api.runTaskTimer(0, 1, function() {
var players = api.getOnlinePlayers();
for (var i = 0; i < players.length; i++) {
// Heavy operation
}
});
// ā
GOOD: Cache data and check less frequently
var cachedPlayers = [];
api.runTaskTimer(0, 20, function() { // Every second instead of every tick
cachedPlayers = api.getOnlinePlayers();
for (var i = 0; i < cachedPlayers.length; i++) {
// Heavy operation
}
});
// ā
GOOD: Use async for heavy operations
api.runTaskAsync(function() {
var data = api.httpGet("https://api.example.com/heavy");
// Process data...
// Update on main thread
api.runTask(function() {
api.broadcast("Data loaded!");
});
});
// ā
GOOD: Cancel tasks when not needed
var task = api.runTaskTimer(0, 20, function() {
// Do something
});
// Later, when done:
api.cancelTask(task);
Code Organization
// ā
GOOD: Organized plugin structure
var pluginInfo = {
name: "My Plugin",
version: "1.0.0"
};
// Configuration
var config = {
enabled: true,
cooldown: 5000
};
// Data storage
var playerData = {};
// Helper functions
function formatMessage(player, message) {
return "&7[" + player.getName() + "] &f" + message;
}
function hasPermission(player, perm) {
return api.hasPermission(player, "myplugin." + perm);
}
// Main functions
function onEnable() {
logger.info("Loading " + pluginInfo.name + " v" + pluginInfo.version);
// Initialize
initializeDatabase();
registerCommands();
registerEvents();
logger.info(pluginInfo.name + " enabled!");
}
function onDisable() {
// Cleanup
saveData();
logger.info(pluginInfo.name + " disabled!");
}
// Exports
this.onEnable = onEnable;
this.onDisable = onDisable;
this.pluginInfo = pluginInfo;
Player Safety Checks
// Always check if player is online before using
api.registerEvent("player.PlayerQuitEvent", function(event) {
var player = event.getPlayer();
var playerName = player.getName();
// Save data before player leaves
savePlayerData(playerName);
});
// Check if player exists before operations
function giveReward(playerName) {
var player = api.getPlayer(playerName);
if (!player) {
logger.warning("Player " + playerName + " is not online!");
return false;
}
// Safe to use player object
api.giveItem(player, reward);
return true;
}
// Use instanceof to check player type
api.registerCommand("playeronly", "Player only command", "/playeronly", function(sender, args) {
if (!(sender instanceof Player)) {
api.sendMessage(sender, "&cThis command can only be used by players!");
return false;
}
var player = sender;
// Safe to use player methods
player.teleport(location);
return true;
});
š§ Troubleshooting
Common Issues & Solutions
Plugin not loading
- Check file extension: Must be
.js - Check syntax: Use a JavaScript validator
- Check console: Look for error messages
- Check onEnable: Function must be defined and exported
- Check file location: Must be in
plugins/MC-JS/js-plugins/
Events not firing
- Check event name: Use format
player.PlayerJoinEvent - Check registration: Must be in
onEnable - Check handler: Function must accept event parameter
- Check console: Look for registration errors
- Try reload: Use
/jsreload <plugin>
Commands not working
- Check registration: Must be in
onEnable - Check return value: Must return
trueorfalse - Check permissions: Use
api.hasPermission() - Check console: Look for JavaScript errors
- Try reload: Use
/jsreload <plugin>
Player is null errors
- Always check:
if (player) { ... } - Use instanceof:
if (sender instanceof Player) - Check online status:
api.getPlayer(name)returns null if offline - Handle offline players: Use
server.getOfflinePlayer()for UUID
Database errors
- Check table exists: Use
api.createTable()first - Check data types: Match column types
- Check NOT NULL: Provide values for required fields
- Check SQL syntax: Use proper SQL in queries
- Check file permissions: Database files need write access
Performance issues
- Avoid heavy operations: Use async tasks
- Cache data: Don't query database every tick
- Cancel tasks: Clean up repeating tasks
- Limit operations: Don't process all players every tick
- Use cooldowns: Prevent spam
Debug Mode
Enable debug mode in config.yml to see detailed logging:
settings:
debug-mode: true
This will show:
- Event registration details
- Event execution logs
- Plugin loading information
- Command execution details
Common Error Messages
"ReferenceError: X is not defined"
Solution: Check if the variable/class is available. Use instanceof Player instead of checking for undefined properties.
"Cannot read property 'X' of null"
Solution: Always check if objects exist before accessing properties:
var player = api.getPlayer(name);
if (player) {
player.teleport(location);
}
"SQLiteException: NOT NULL constraint failed"
Solution: Ensure all required fields are provided when inserting data:
api.insertData("db", "table", {
"required_field": value, // Must not be null
"optional_field": value || null
});
"Events being called multiple times"
Solution: This is fixed in MC-JS - events are only dispatched once per event instance, even if multiple plugins register the same event.
ā Frequently Asked Questions
General Questions
Q: Can I use ES6+ features?
A: Yes! MC-JS uses Rhino with ES6 support. You can use arrow functions, let/const, template literals, etc.
Q: How do I reload my plugin?
A: Use /jsreload <plugin-name> or /jsreload to reload all plugins.
Q: Can I use npm packages?
A: No, MC-JS uses Rhino which doesn't support Node.js modules. Use the built-in API instead.
Q: How do I check if a player is online?
A: Use api.getPlayer(name) - it returns null if the player is offline.
Q: Can I access Bukkit API directly?
A: Yes! The server object gives you access to the Bukkit Server instance. Also, Bukkit classes like Player, Material, etc. are available.
Q: How do I handle offline players?
A: Use server.getOfflinePlayer(name) to get UUID and other data for offline players.
Q: Can multiple plugins register the same event?
A: Yes! Each plugin's handler will be called. MC-JS ensures events are only dispatched once per event instance.
Q: How do I create a config file?
A: Use api.getPluginConfig(pluginName) and api.savePluginConfig(pluginName, data).
Q: Can I use async/await?
A: No, but you can use api.runTaskAsync() for asynchronous operations.
Q: How do I prevent command spam?
A: Use the cooldown system: api.setCooldown(playerName, "command", 5000)
š Common Code Snippets
Player Utilities
// Check if player is online
function isPlayerOnline(name) {
return api.getPlayer(name) !== null;
}
// Get player safely
function getPlayerSafe(name) {
var player = api.getPlayer(name);
if (!player) {
logger.warning("Player " + name + " is not online!");
return null;
}
return player;
}
// Get UUID for online or offline player
function getPlayerUUID(name) {
var player = api.getPlayer(name);
if (player) {
return player.getUniqueId().toString();
}
try {
var offline = server.getOfflinePlayer(name);
return offline.getUniqueId().toString();
} catch (e) {
return null;
}
}
Command Patterns
// Command with permission check
api.registerCommand("admin", "Admin command", "/admin", function(sender, args) {
if (!api.hasPermission(sender, "myplugin.admin")) {
api.sendMessage(sender, "&cNo permission!");
return false;
}
if (!(sender instanceof Player)) {
api.sendMessage(sender, "&cPlayers only!");
return false;
}
// Command logic
return true;
});
// Command with cooldown
api.registerCommand("cooldown", "Cooldown command", "/cooldown", function(sender, args) {
if (!(sender instanceof Player)) return false;
var player = sender;
var playerName = player.getName();
if (api.hasCooldown(playerName, "cooldown")) {
var remaining = api.getCooldownRemaining(playerName, "cooldown");
api.sendMessage(player, "&cCooldown: " + Math.ceil(remaining / 1000) + "s");
return false;
}
api.setCooldown(playerName, "cooldown", 5000);
api.sendMessage(player, "&aCommand executed!");
return true;
});
Data Storage Patterns
// Save player data
var playerData = {};
function savePlayerData(playerName) {
try {
api.saveYamlFile("players/" + playerName, playerData[playerName] || {});
} catch (e) {
logger.severe("Error saving data for " + playerName + ": " + e);
}
}
function loadPlayerData(playerName) {
try {
var data = api.loadYamlFile("players/" + playerName);
if (data) {
// Convert Java Map to JavaScript object
var playerObj = {};
if (data instanceof java.util.Map) {
var keys = data.keySet().toArray();
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
var value = data.get(key);
// Handle nested Maps
if (value instanceof java.util.Map) {
var nestedObj = {};
var nestedKeys = value.keySet().toArray();
for (var j = 0; j < nestedKeys.length; j++) {
nestedObj[nestedKeys[j]] = value.get(nestedKeys[j]);
}
playerObj[key] = nestedObj;
} else {
playerObj[key] = value;
}
}
}
playerData[playerName] = playerObj;
}
} catch (e) {
logger.warning("No data found for " + playerName);
playerData[playerName] = {};
}
}
// Save on quit
api.registerEvent("player.PlayerQuitEvent", function(event) {
var player = event.getPlayer();
savePlayerData(player.getName());
delete playerData[player.getName()];
});
GUI Patterns
// Simple GUI with GUI Builder
function openMenu(player) {
var gui = api.createGUI("&6Menu", 3);
// Background
var bg = api.createItemStack(api.getMaterial("GRAY_STAINED_GLASS_PANE"), 1);
bg = api.setItemDisplayName(bg, " ");
gui.fillBorders(bg);
// Items
var item1 = api.createItemStack(api.getMaterial("DIAMOND"), 1);
item1 = api.setItemDisplayName(item1, "&bOption 1");
gui.setItem(10, item1, function(event) {
event.setCancelled(true);
api.sendMessage(player, "&aYou clicked Option 1!");
});
gui.buildAndOpen(player);
}
// GUI with data storage
var guiData = {};
function openShop(player) {
var gui = api.createGUI("&6Shop", 3);
var playerName = player.getName();
guiData[playerName] = {
page: 1,
category: "weapons"
};
// Store data in holder
var inv = gui.build();
var holder = api.getInventoryHolder(inv);
if (holder) {
holder.setData("player", playerName);
holder.setData("page", 1);
}
player.openInventory(inv);
}