šŸš€ Getting Started

Installation

Requirements

  • Minecraft Server: Paper 26.1 or higher (recommended: Paper)
  • Java: Version 25 or higher
  • Minecraft Version: 26.1
šŸ“¦ Steps:
  1. Download the latest release
  2. Place the JAR file in your server's plugins/ folder
  3. Start or restart your server
  4. 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:

my-first-plugin.js

var pluginInfo = {
    name: "My First Plugin",
    version: "1.0.0",
    author: "YourName",
    description: "My awesome first plugin!"
};

var mcjsVersion = api.getMCJSVersion();
logger.info("Running on MC-JS " + mcjsVersion);

function onEnable() {
    logger.info("My plugin is enabled!");

    api.registerCommand("hello", "Say hello", "/hello", function(sender, args) {
        api.sendMessage(sender, "&aHello from JavaScript!");
        return true;
    });

    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!");
}

this.onEnable = onEnable;
this.onDisable = onDisable;
this.pluginInfo = pluginInfo;
āœ… Done! Reload the plugin using /jsreload or restart the server, then test with /hello

šŸ“š Complete API Reference

šŸ’” Global Objects: These objects are available in all JavaScript plugins:
  • api - Complete JS API wrapper
  • server - Minecraft server instance
  • plugin - Main plugin instance
  • logger - Plugin logger (logger.info(), logger.warning(), etc.)
  • scheduler - Server scheduler
  • Bukkit - Bukkit API access

šŸ’¬ Command Registration

Simple Command

api.registerCommand("command", function(sender, args) {
    api.sendMessage(sender, "Command executed!");
    return true;
});

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) {

        var target = api.getPlayer(args[0]);
        if (target) {
            api.sendMessage(sender, "Found player: " + target.getName());
        }
        return true;
    },
    function(sender, args) {

        if (args.length === 1) {
            return api.getPlayerNames();
        }
        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();

    event.setCancelled(true);

    api.sendMessage(player, "&cYou cannot break blocks here!");
}, "HIGH");                                                           

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


api.runTaskLater(100, function() {
    logger.info("This runs after 5 seconds");
    api.broadcast("&a5 seconds have passed!");
});

Repeating Task


var task = api.runTaskTimer(0, 1200, function() {
    var playerCount = api.getOnlinePlayers().size();
    logger.info("Server has " + playerCount + " player(s) online");
});

api.runTaskLater(6000, function() {
    api.cancelTask(task);
    logger.info("Task cancelled after 5 minutes");
});

Async Task


api.runTaskAsync(function() {

    var response = api.httpGet("https://api.example.com/data");
    logger.info("Fetched data: " + response);

    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


var player = api.getPlayer("PlayerName");
if (player) {
    api.sendMessage(player, "Hello!");
}

var exactPlayer = api.getPlayerExact("ExactPlayerName");

var allPlayers = api.getOnlinePlayers();
for (var i = 0; i < allPlayers.length; i++) {
    var p = allPlayers[i];
    logger.info("Online: " + p.getName());
}

Send Messages


api.sendMessage(player, "&aHello &bWorld!");

api.broadcast("&6Server announcement!");

api.broadcast("&cAdmin message!", "admin.message");

api.sendTitle(player, "&aWelcome!", "&eEnjoy your stay!", 10, 70, 20);

api.sendActionBar(player, "&bYou are in the spawn area!");

Player Properties


api.setHealth(player, 20.0);
var health = api.getHealth(player);
var maxHealth = api.getMaxHealth(player);

api.setFoodLevel(player, 20);
var food = api.getFoodLevel(player);
api.setSaturation(player, 5.0);

api.clearInventory(player);

api.setGameMode(player, GameMode.CREATIVE);
var gamemode = api.getGameMode(player);

var location = api.createLocation(world, 100, 64, 200);
api.teleport(player, location);

api.setLevel(player, 10);
api.setExp(player, 0.5);
api.giveExp(player, 100);

šŸ“¦ Inventory & Items

Create Inventory


var inv = api.createInventory(null, 27, "&6My Custom GUI");

var chest = api.createInventory(null, InventoryType.CHEST, "&bChest Menu");

var customInv = api.createCustomInventory(27, "&6Custom GUI");

var gui = api.createCustomInventory(3, "&bMy Menu", true);                     

GUI Builder Pattern (Recommended)


var gui = api.createGUI("&6My Custom Menu", 3);

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!");
});

var background = api.createItemStack(api.getMaterial("GRAY_STAINED_GLASS_PANE"), 1);
background = api.setItemDisplayName(background, " ");
gui.fillBorders(background);

gui.setBackground(background);

gui.setAllowItemRemoval(false);

gui.onClick(function(event) {

    var slot = event.getSlot();

});

gui.onClose(function(event) {
    var player = event.getPlayer();
    api.sendMessage(player, "&7You closed the menu");
});

var inventory = gui.buildAndOpen(player);

var inv = gui.build();
player.openInventory(inv);

Create Items with Enchantments


var sword = api.createItemStack(api.getMaterial("DIAMOND_SWORD"), 1);

sword = api.setItemDisplayName(sword, "&b&lMagic Sword");

api.addEnchantment(sword, "SHARPNESS", 5);
api.addEnchantment(sword, "FIRE_ASPECT", 2);
api.addEnchantment(sword, "UNBREAKING", 3);

if (api.hasEnchantment(sword, "SHARPNESS")) {
    var level = api.getEnchantmentLevel(sword, "SHARPNESS");
    logger.info("Sword has Sharpness level " + level);
}

var enchantments = api.getEnchantments(sword);
for (var enchantName in enchantments) {
    logger.info(enchantName + ": " + enchantments[enchantName]);
}

api.removeEnchantment(sword, "FIRE_ASPECT");

sword = api.setItemLore(sword, [
    "&7This is a special diamond",
    "&7given by the JS plugin!",
    "&eRight-click to use"
]);

api.giveItem(player, diamond);

api.setInventoryItem(inv, 0, diamond);

api.fillInventory(inv, diamond);

api.fillInventoryRange(inv, diamond, 0, 8);

Inventory Events


api.registerInventoryClick(inv, function(event) {
    event.setCancelled(true);

    var slot = event.getSlot();
    var player = event.getWhoClicked();

    api.sendMessage(player, "&aYou clicked slot " + slot);

    if (slot === 10) {

        api.giveItem(player, api.createItemStack(api.getMaterial("DIAMOND"), 5));
    }
});

api.registerInventoryClose(inv, function(event) {
    var player = event.getPlayer();
    api.sendMessage(player, "&7You closed the inventory");
});

Custom Inventory Holder


var holder = api.createInventoryHolder();

holder.setData("menuType", "shop");
holder.setData("player", player);

var inv = api.createInventoryWithHolder(holder, 27, "&6Shop Menu");

var invHolder = api.getInventoryHolder(inv);
if (invHolder) {
    var menuType = invHolder.getData("menuType");
    var storedPlayer = invHolder.getData("player");
}

if (api.isCustomInventory(inv)) {

}

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


api.deleteData("mydb", "players", "last_seen < " + (api.getCurrentTimeMillis() - 86400000));

var count = api.countRows("mydb", "players");
var activeCount = api.countRows("mydb", "players", "last_seen > " + (api.getCurrentTimeMillis() - 86400000));

šŸŒ World & Block Management

World Operations


var world = api.getWorld("world");
var allWorlds = api.getWorlds();

api.setWorldTime(world, 6000);
var time = api.getWorldTime(world);

api.setStorm(world, true);
api.setThundering(world, true);
var hasStorm = api.hasStorm(world);
var isThundering = api.isThundering(world);

var border = api.getWorldBorder(world);
api.setWorldBorderSize(world, 1000);
api.setWorldBorderCenter(world, 0, 0);

Block Operations


var block = api.getBlock(location);
var blockType = api.getBlockType(location);

api.setBlockType(location, api.getMaterial("DIAMOND_BLOCK"));

api.breakBlock(location);
api.breakBlock(location, false);

var block = api.getBlockAt(world, 100, 64, 200);

var blocks = api.getBlocksInRadius(centerLocation, 5.0);
for (var i = 0; i < blocks.length; i++) {
    logger.info("Block: " + blocks[i].getType().name());
}

Explosions & Lightning


api.createExplosion(location, 5.0);
api.createExplosion(location, 5.0, true);

api.strikeLightning(location);
api.strikeLightningEffect(location);                          

šŸŽÆ Entity Management

Spawn Entities


var zombie = api.spawnEntity(location, "ZOMBIE");
var creeper = api.spawnEntity(location, EntityType.CREEPER);

api.setEntityCustomName(zombie, "&cCustom Zombie");
api.setEntityGlowing(zombie, true);
api.setEntityGravity(zombie, false);
api.setEntityInvulnerable(zombie, true);

api.removeEntity(zombie);

šŸ“ File Operations

YAML Files


var data = {
    "server": {
        "name": "My Server",
        "maxPlayers": 100
    },
    "settings": {
        "pvp": true,
        "spawnProtection": true
    }
};
api.saveYamlFile("config", data);

var config = api.loadYamlFile("config");
var serverName = config.get("server").get("name");

var serverName2 = config.get("server").get("name");

var bansData = api.loadYamlFile("bansystem_bans");
var bansList = bansData.get("bans");
var nextId = bansData.get("nextId");

var bans = [];
if (bansList instanceof java.util.List) {
    for (var i = 0; i < bansList.size(); i++) {
        var banObj = bansList.get(i);

        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


var jsonData = {
    "players": ["Player1", "Player2"],
    "timestamp": api.getCurrentTimeMillis()
};
api.saveJsonFile("data", JSON.stringify(jsonData, null, 2));

var json = api.loadJsonFile("data");
var data = JSON.parse(json);

Text Files


api.saveTextFile("log", "Line 1\nLine 2\nLine 3");

var content = api.loadTextFile("log");
logger.info("File content: " + content);

Config System


var config = api.getPluginConfig("myplugin");

var setting = api.getPluginConfigValue("myplugin", "setting", "default");

api.setPluginConfigValue("myplugin", "setting", "new value");

api.savePluginConfig("myplugin", {
    "setting1": "value1",
    "setting2": "value2"
});

ā±ļø Cooldown System

Basic Cooldown


var name = pluginInfo.name;
var scope = "command";

if (api.systems.claimCooldown(name, scope, player.getName(), 5)) {
    api.sendMessage(player, "&aCommand ready!");
} else {
    var remaining = api.systems.cooldownRemaining(name, scope, player.getName());
    api.sendMessage(player, "&cCooldown: " + Math.ceil(remaining) + " seconds");
}

šŸ’° Economy & Systems

Vault Economy


if (api.vault.isAvailable()) {
    var balance = api.vault.balance(player);
    api.sendMessage(player, "&aBalance: " + api.vault.format(balance));

    var result = api.vault.deposit(player, 1000.0);
    if (result.isSuccess()) {
        api.sendMessage(player, "&aDeposited!");
    }
}

Persistent Data


var name = pluginInfo.name;
var scope = "stats";

api.systems.writeData(name, scope, "kills-" + player.getName(), JSON.stringify({"kills": 10}));

var data = api.systems.readData(name, scope, "kills-" + player.getName(), "{}");

api.systems.deleteData(name, scope, "kills-" + player.getName());

šŸ’” 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();

        api.sendMessage(player, "&6Welcome to the server, &b" + player.getName() + "&6!");

        api.sendTitle(player, "&aWelcome!", "&eEnjoy your stay!", 10, 70, 20);

        api.playSound(player, "ENTITY_PLAYER_LEVELUP", 1.0, 1.0);

        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() {

    api.createTable("stats", "player_stats", {
        "player_name": "TEXT PRIMARY KEY",
        "kills": "INTEGER DEFAULT 0",
        "deaths": "INTEGER DEFAULT 0",
        "playtime": "INTEGER DEFAULT 0"
    });

    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();
        }
    );

    api.registerEvent("entity.PlayerDeathEvent", function(event) {
        var killer = event.getEntity().getKiller();
        var victim = event.getEntity();

        if (killer) {

            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
                });
            }
        }

        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");

        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);

        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);

        var close = api.createItemStack(api.getMaterial("BARRIER"), 1);
        close = api.setItemDisplayName(close, "&cClose Menu");
        api.setInventoryItem(inv, 22, close);

        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;

        var gui = api.createGUI("&6&lShop Menu", 3);

        var bg = api.createItemStack(api.getMaterial("GRAY_STAINED_GLASS_PANE"), 1);
        bg = api.setItemDisplayName(bg, " ");
        gui.fillBorders(bg);
        gui.setBackground(bg);

        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);
        });

        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);
        });

        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);
        });

        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();
        });

        gui.onClick(function(event) {

        });

        gui.onClose(function(event) {
            api.sendMessage(player, "&7Shop closed. Come back soon!");
        });

        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 name = pluginInfo.name;
        var scope = "heal";

        if (!api.systems.claimCooldown(name, scope, player.getName(), 30)) {
            var remaining = api.systems.cooldownRemaining(name, scope, player.getName());
            api.sendMessage(player, "&cCooldown: " + Math.ceil(remaining) + " seconds");
            return false;
        }

        api.setHealth(player, api.getMaxHealth(player));
        api.setFoodLevel(player, 20);
        api.sendMessage(player, "&aYou have been healed!");

        return true;
    });
}

this.onEnable = onEnable;
this.pluginInfo = pluginInfo;

Example 5: Vault Economy

var pluginInfo = {
    name: "Economy Example",
    version: "1.0.0"
};

function onEnable() {
    api.registerCommand("balance", "Check your balance", "/balance", function(sender, args) {
        var player = sender;
        if (!(player instanceof Player)) {
            api.sendMessage(sender, "&cOnly players can use this!");
            return false;
        }

        if (!api.vault.isAvailable()) {
            api.sendMessage(player, "&cNo economy plugin found!");
            return false;
        }

        var balance = api.vault.balance(player);
        api.sendMessage(player, "&6Your balance: &e" + api.vault.format(balance));
        return true;
    });

    api.registerCommand("pay", "Pay another player", "/pay  ", function(sender, args) {
        var player = sender;
        if (!(player instanceof Player)) {
            api.sendMessage(sender, "&cOnly players can use this!");
            return false;
        }
        if (args.length < 2) {
            api.sendMessage(player, "&cUsage: /pay <player> <amount>");
            return false;
        }

        var target = api.getPlayer(args[0]);
        var amount = Number(args[1]);
        var result = api.vault.transfer(player, target, amount);

        if (result.isSuccess()) {
            api.sendMessage(player, "&aYou paid &e" + api.vault.format(amount) + " &ato " + target.getName());
            api.sendMessage(target, "&aYou received &e" + api.vault.format(amount) + " &afrom " + player.getName());
        } else {
            api.sendMessage(player, "&cPayment failed: " + result.getError());
        }
        return true;
    });
}

this.onEnable = onEnable;
this.pluginInfo = pluginInfo;

Example 6: World Protection System

var pluginInfo = {
    name: "World Protection",
    version: "1.0.0"
};

var protectedRegions = [];

function onEnable() {

    var spawn = api.getWorlds()[0].getSpawnLocation();
    protectedRegions.push({
        center: spawn,
        radius: 50
    });

    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!");
            }
        }
    });

    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)

ā–¼
MethodDescription
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

šŸŽÆEvent Methods (6 methods)

ā–¼
MethodDescription
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)

ā–¼
MethodDescription
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)

ā–¼
MethodDescription
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
MethodDescription
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
MethodDescription
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
MethodDescription
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
MethodDescription
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
MethodDescription
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
MethodDescription
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)

ā–¼
MethodDescription
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
MethodDescription
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)

ā–¼
MethodDescription
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)

ā–¼
MethodDescription
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)

ā–¼
MethodDescription
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 & Systems Methods (9 methods)

ā–¼
MethodDescription
api.systems.claimCooldown(name, scope, key, seconds)Claim a cooldown (true if freshly claimed)
api.systems.cooldownRemaining(name, scope, key)Get remaining seconds
api.systems.writeData(name, scope, key, json)Store JSON data (survives restarts)
api.systems.readData(name, scope, key, fallback)Read JSON data
api.systems.deleteData(name, scope, key)Delete data
api.systems.changeNumber(name, scope, key, delta)Change a stored number
api.systems.grantKit(name, player, key, seconds, items)Grant an item kit with cooldown
api.systems.purchase(name, player, currency, cost, item)Purchase an item
api.systems.createMenu(title, rows)Create an interactive menu with buttons

Vault Economy Methods

MethodDescription
api.vault.isAvailable()Check if a Vault economy is present
api.vault.balance(player)Get player balance
api.vault.has(player, amount)Check if the player has enough money
api.vault.deposit(player, amount)Add money to balance
api.vault.withdraw(player, amount)Remove money from balance
api.vault.transfer(from, to, amount)Transfer money between players
api.vault.purchase(player, cost, item)Buy an item with balance check
api.vault.format(amount)Format money amount

Particle & Sound Methods

MethodDescription
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)

ā–¼
MethodDescription
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
MethodDescription
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)

ā–¼
MethodDescription
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

MethodDescription
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

MethodDescription
api.createPotionEffect(type, duration, amplifier)Create potion effect
api.createPotionEffect(type, duration, amplifier, ambient)Create potion effect with ambient

Location & Vector Methods

MethodDescription
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

MethodDescription
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

MethodDescription
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

MethodDescription
api.grantAdvancement(player, key)Grant advancement
api.revokeAdvancement(player, key)Revoke advancement

Server & Plugin Methods

MethodDescription
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

MethodDescription
api.logInfo(message)Log info message
api.logWarning(message)Log warning message
api.logError(message)Log error message

Random Methods

MethodDescription
api.randomInt(min, max)Random integer
api.randomDouble(min, max)Random double
api.randomBoolean()Random boolean

String Utility Methods

MethodDescription
api.format(format, ...args)Format string
api.join(delimiter, ...elements)Join strings

Utility Methods

MethodDescription
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

MethodDescription
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

MethodDescription
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)

MethodDescription
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

Systems & Cooldowns


var name = pluginInfo.name;

// Persistent per-player cooldowns
var scope = "vote";
if (api.systems.claimCooldown(name, scope, player.getName(), 300)) {
    api.sendMessage(player, "&aYou can vote again!");
} else {
    var remaining = api.systems.cooldownRemaining(name, scope, player.getName());
    api.sendMessage(player, "&cVote again in " + Math.ceil(remaining / 60) + " minutes");
}

// Storable data + counters
api.systems.writeData(name, "stats", "deaths-" + player.getName(),
    JSON.stringify({"deaths": 3}));
api.systems.changeNumber(name, "stats", "deaths-" + player.getName(), 1);

Permissions & Player Management


if (api.hasPermission(player, "myplugin.use")) {

}

api.addPermission(player, "myplugin.vip");
api.removePermission(player, "myplugin.vip");

if (api.isOp(player)) {
    api.sendMessage(player, "You are OP!");
}
api.setOp(player, true);

api.setPlayerMetadata(player, "lastLogin", api.getCurrentTimeMillis());
var lastLogin = api.getPlayerMetadata(player, "lastLogin");
if (api.hasPlayerMetadata(player, "lastLogin")) {
    logger.info("Last login: " + lastLogin);
}

api.addToWhitelist("PlayerName");
api.removeFromWhitelist("PlayerName");
if (api.isWhitelisted("PlayerName")) {
    logger.info("Player is whitelisted");
}
api.setWhitelistEnabled(true);

Particles & Sounds


api.spawnParticle(location, "FIREWORK", 10, 0.5, 0.5, 0.5, 0.1);
api.spawnParticle(location, Particle.FLAME, 5, 0, 0, 0);

api.playSound(location, "ENTITY_PLAYER_LEVELUP", 1.0, 1.0);
api.playSound(player, Sound.ENTITY_EXPERIENCE_ORB_PICKUP, 0.5, 1.5);

api.registerEvent("player.PlayerMoveEvent", function(event) {
    var player = event.getPlayer();
    if (player.isSprinting()) {
        api.spawnParticle(player.getLocation(), "CLOUD", 3, 0, 0, 0);
    }
});

Entity Manipulation


var zombie = api.spawnEntity(location, "ZOMBIE");

api.setEntityCustomName(zombie, "&cBoss Zombie");
api.setEntityGlowing(zombie, true);
api.setEntityGravity(zombie, false);
api.setEntityInvulnerable(zombie, true);

api.setEntityAI(zombie, false);
if (!api.hasEntityAI(zombie)) {
    logger.info("Zombie has no AI");
}

api.setEntitySilent(zombie, true);
api.setEntityCollidable(zombie, false);

var targetLocation = api.createLocation(world, 100, 64, 200);
api.teleportEntity(zombie, targetLocation);

api.teleportEntity(zombie, player);

var entityLoc = api.getEntityLocation(zombie);

api.removeEntity(zombie);

World Management


api.setWorldDifficulty(world, "HARD");
var difficulty = api.getWorldDifficulty(world);

api.setWorldPVP(world, true);
if (api.isWorldPVP(world)) {
    logger.info("PvP is enabled");
}

var spawnLoc = api.createLocation(world, 0, 64, 0);
api.setWorldSpawnLocation(world, spawnLoc);
var currentSpawn = api.getWorldSpawnLocation(world);

api.setWorldAutoSave(world, false);
if (!api.isWorldAutoSave(world)) {
    logger.info("Auto-save disabled");
}

var environment = api.getWorldEnvironment(world);
var seed = api.getWorldSeed(world);
logger.info("World: " + world.getName() + ", Seed: " + seed);

Validation & Error Handling


var player = api.getPlayer("PlayerName");
if (api.isValidPlayer(player)) {

    api.sendMessage(player, "Hello!");
} else {
    logger.warning("Player not found or offline");
}

var location = api.createLocation(world, 0, 64, 0);
if (api.isValidLocation(location)) {
    api.teleport(player, location);
}

var item = api.getItemInMainHand(player);
if (api.isValidItemStack(item)) {
    api.addEnchantment(item, "SHARPNESS", 1);
}

api.runTaskAsyncSafe(function() {

    var data = api.loadYamlFile("data");

}, function(error) {

    logger.severe("Error in async task: " + error);
});

HTTP Requests


api.runTaskAsync(function() {
    var response = api.httpGet("https://api.example.com/data");
    logger.info("Response: " + response);

    var data = JSON.parse(response);

    api.runTask(function() {
        api.broadcast("&aData fetched: " + data.message);
    });
});

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


var colored = api.colorize("&aHello &bWorld");
var stripped = api.stripColor(colored);
var formatted = api.format("Hello %s! You have %d items.", "Player", 5);

var rounded = api.round(3.14159, 2);
var clamped = api.clamp(150, 0, 100);

var encoded = api.base64Encode("Hello World");
var decoded = api.base64Decode(encoded);
var md5 = api.md5("text");
var sha256 = api.sha256("text");

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");

var distance = api.getDistance(loc1, loc2);
var midpoint = api.getMidpoint(loc1, loc2);
āš ļø Important:
  • 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


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;
        }

        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;
    }
});

api.registerEvent("player.PlayerJoinEvent", function(event) {
    try {
        var player = event.getPlayer();

    } catch (e) {
        logger.severe("Error in PlayerJoinEvent: " + e);

    }
});

Performance Optimization


api.runTaskTimer(0, 1, function() {
    var players = api.getOnlinePlayers();
    for (var i = 0; i < players.length; i++) {

    }
});

var cachedPlayers = [];
api.runTaskTimer(0, 20, function() {
    cachedPlayers = api.getOnlinePlayers();
    for (var i = 0; i < cachedPlayers.length; i++) {

    }
});

api.runTaskAsync(function() {
    var data = api.httpGet("https://api.example.com/heavy");

    api.runTask(function() {
        api.broadcast("Data loaded!");
    });
});

var task = api.runTaskTimer(0, 20, function() {

});

api.cancelTask(task);

Code Organization


var pluginInfo = {
    name: "My Plugin",
    version: "1.0.0"
};

var config = {
    enabled: true,
    cooldown: 5000
};

var playerData = {};

function formatMessage(player, message) {
    return "&7[" + player.getName() + "] &f" + message;
}

function hasPermission(player, perm) {
    return api.hasPermission(player, "myplugin." + perm);
}

function onEnable() {
    logger.info("Loading " + pluginInfo.name + " v" + pluginInfo.version);

    initializeDatabase();
    registerCommands();
    registerEvents();

    logger.info(pluginInfo.name + " enabled!");
}

function onDisable() {

    saveData();
    logger.info(pluginInfo.name + " disabled!");
}

this.onEnable = onEnable;
this.onDisable = onDisable;
this.pluginInfo = pluginInfo;

Player Safety Checks


api.registerEvent("player.PlayerQuitEvent", function(event) {
    var player = event.getPlayer();
    var playerName = player.getName();

    savePlayerData(playerName);
});

function giveReward(playerName) {
    var player = api.getPlayer(playerName);
    if (!player) {
        logger.warning("Player " + playerName + " is not online!");
        return false;
    }

    api.giveItem(player, reward);
    return true;
}

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;

    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 true or false
  • 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,
    "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.systems.claimCooldown(pluginInfo.name, "command", playerName, 5)

šŸ“‹ Common Code Snippets

Player Utilities


function isPlayerOnline(name) {
    return api.getPlayer(name) !== null;
}

function getPlayerSafe(name) {
    var player = api.getPlayer(name);
    if (!player) {
        logger.warning("Player " + name + " is not online!");
        return null;
    }
    return 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


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;
    }

    return true;
});

api.registerCommand("cooldown", "Cooldown command", "/cooldown", function(sender, args) {
    if (!(sender instanceof Player)) return false;

    var player = sender;
    var playerName = player.getName();
    var scope = "cooldown";

    if (!api.systems.claimCooldown(pluginInfo.name, scope, playerName, 5)) {
        var remaining = api.systems.cooldownRemaining(pluginInfo.name, scope, playerName);
        api.sendMessage(player, "&cCooldown: " + Math.ceil(remaining) + "s");
        return false;
    }

    api.sendMessage(player, "&aCommand executed!");
    return true;
});

Data Storage Patterns


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) {

            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);

                    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] = {};
    }
}

api.registerEvent("player.PlayerQuitEvent", function(event) {
    var player = event.getPlayer();
    savePlayerData(player.getName());
    delete playerData[player.getName()];
});

GUI Patterns


function openMenu(player) {
    var gui = api.createGUI("&6Menu", 3);

    var bg = api.createItemStack(api.getMaterial("GRAY_STAINED_GLASS_PANE"), 1);
    bg = api.setItemDisplayName(bg, " ");
    gui.fillBorders(bg);

    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);
}

var guiData = {};

function openShop(player) {
    var gui = api.createGUI("&6Shop", 3);
    var playerName = player.getName();

    guiData[playerName] = {
        page: 1,
        category: "weapons"
    };

    var inv = gui.build();
    var holder = api.getInventoryHolder(inv);
    if (holder) {
        holder.setData("player", playerName);
        holder.setData("page", 1);
    }

    player.openInventory(inv);
}