About This File
This resource adds a very flexible command handler for serverside JavaScript.
Installing
Drag and drop the improved-commands folder to your server-files/packages/ folder.
NOTE: The archive also contains a folder named improved-commands-example, it's an example resource so don't install it along with the library.
Features
- Command aliases
- Capture command requests (and cancel them if you want to)
- Somewhat customizable command not found message (like serverside C#)
- beforeRun property that lets you do final checks before a command actually runs (see example)
API
Instead of extending the global mp object, I've decided to export CommandEvents and CommandRegistry objects. You can access to the library by doing:
const { CommandEvents, CommandRegistry } = require("../improved-commands");
API Properties
/** * This property is used to toggle the "command not found" message feature. * Default value: false */ CommandRegistry.notFoundMessageEnabled; // get CommandRegistry.notFoundMessageEnabled = bool; // set /** * This property is used to set the "command not found" message. * Default value: "SERVER: Command not found." */ CommandRegistry.notFoundMessage; // get CommandRegistry.notFoundMessage = string; // set
API Functions
/** * Adds a command to the registry. * The command object must contain "name" (string) and "run" (function) properties at the very least. * Optionally, the command object can have "aliases" (array of strings) and "beforeRun" (function, needs to return true for further execution) properties. * Other properties will be collected into an "extra" (object) property, which is useful for storing data on commands. */ CommandRegistry.add(command); /** * Returns all command names, aliases not included. * @return {string[]} */ CommandRegistry.getNames(); /** * Returns all command names with aliases. * @return {string[]} */ CommandRegistry.getNamesWithAliases(); /** * Returns the command object for the specified command name/alias. * @param {string} commandName * @return {Object|undefined} Will be undefined if there is no command with the given name/alias. */ CommandRegistry.find(commandName);
Events
/** * receive * This event is emitted when a player tries to run a command. * @param {mp.Player} player The player who is trying to use the command. * @param {Object} command The command object. * @param {string} fullText All arguments that will be passed to the command, as one string. * @param {string[]} commandArgs All arguments that will be passed to the command. * @param {Object} cancel Whether the execution should be cancelled. Set this object's cancel property to true to stop further processing of the command. */ CommandEvents.on("receive", function (player, command, fullText, commandArgs, cancel) { // your code }); /** * fail * This event is emitted when an error is thrown during command execution. * @param {mp.Player} player The player whose command execution failed. * @param {Object} command The command object. * @param {string} fullText All arguments that were be passed to the command, as one string. * @param {string[]} commandArgs All arguments that were be passed to the command. * @param {Error} error The error that was thrown during command execution. */ CommandEvents.on("fail", function (player, command, fullText, commandArgs, error) { // your code });
Example
const { CommandEvents, CommandRegistry } = require("../improved-commands"); // Should we inform the player when they enter an invalid command? Probably... // Note that commands added with mp.events.addCommand aren't known by this resource so they'll trigger the not found message // This is disabled by default CommandRegistry.notFoundMessageEnabled = true; // Events // Example: Players can't use commands in a vehicle CommandEvents.on("receive", function (player, command, fullText, commandArgs, cancel) { if (player.vehicle) { player.outputChatBox("You cannot use commands in a vehicle."); cancel.cancel = true; } }); // Example: Send a message to the player and print the error to the console on execution failure CommandEvents.on("fail", function (player, command, fullText, commandArgs, error) { player.outputChatBox(`Failed to run command "${command.name}".`); console.error(error.stack || error); }); // Commands // Example: /argtest lorem ipsum dolor sit amet -> results in "You wrote: lorem ipsum dolor sit amet" CommandRegistry.add({ name: "argtest", aliases: ["echo", "combineargs"], beforeRun: function (player, fullText) { if (fullText.length === 0) { player.outputChatBox("No arguments provided."); return false; } return true; }, run: function (player, fullText) { player.outputChatBox(`You wrote: ${fullText}`); } }); // Example: /freemode_male_only -> will only work when player's model is mp_m_freemode_01 CommandRegistry.add({ name: "freemode_male_only", beforeRun: function (player) { return player.model === mp.joaat("mp_m_freemode_01"); }, run: function (player) { player.outputChatBox("Yes, only freemode male can run this command."); } }); // Example: /boom -> will emit "fail" event CommandRegistry.add({ name: "boom", run: function (player) { throw new Error("error thrown"); } }); // Properties that aren't named "name", "aliases", "beforeRun" or "run" will be collected into the "extra" property // Example: /getweapon weapon_carbinerifle 500 -> will only work when player's adminLevel property value is equal to or higher than cmdAdminLevel extra property CommandRegistry.add({ name: "getweapon", aliases: ["giveweapon"], // You can access this property in handlers by using "this.extra.cmdAdminLevel" if the handlers are regular functions (meaning it doesn't work with arrow functions!) cmdAdminLevel: 5, beforeRun: function (player) { return player.adminLevel >= this.extra.cmdAdminLevel; }, run: function (player, fullText, weaponName, ammo = 9999) { // You can do this in beforeRun as well (see argtest example) if (!weaponName || weaponName.length === 0) { player.outputChatBox("Syntax: /getweapon [name]"); return; } player.giveWeapon(mp.joaat(weaponName), Number(ammo)); player.outputChatBox(`Gave yourself ${weaponName} with ${ammo} ammo.`); } }); // Example: Extra property #2 CommandRegistry.add({ name: "count_runs", // You can access this property in handlers by using "this.extra.timesRan" if the handlers are regular functions (meaning it doesn't work with arrow functions!) timesRan: 0, beforeRun: function (player) { player.outputChatBox(`This command was used ${this.extra.timesRan} time(s).`); return true; }, run: function (player) { this.extra.timesRan++; player.outputChatBox(`Now it's used ${this.extra.timesRan} time(s).`); } }); // Example: List all commands CommandRegistry.add({ name: "commands", aliases: ["cmds"], run: function (player) { const commands = CommandRegistry.getNamesWithAliases(); commands.sort(); player.outputChatBox(`Commands: ${commands.join(", ")}`); } }); // Example: Async beforeRun (v1.1 and above) // Important: You should check if player object is still valid by mp.players.exists(player) after awaiting // sleep function can be found here: https://stackoverflow.com/a/39914235 CommandRegistry.add({ name: "async", beforeRun: async function (player) { // Getting data from slow API await sleep(5000); const result = Math.random() < 0.5; if (result) { player.outputChatBox("You're allowed..."); } else { player.outputChatBox("You're not allowed..."); } return result; }, run: async function (player) { // Getting data from slow API again await sleep(2000); if (Math.random() < 0.5) { player.outputChatBox("You waited for nothing!"); } else { throw new Error("Failed so bad it caused an error"); // should emit fail } } });
Notes
- This resource does not know about commands added with mp.events.addCommand or C# commands. Meaning if you're using the command not found message feature, addCommand and C# commands will also result in command not found message.
- Commands are case insensitive.
- Also on GitHub: https://github.com/root-cause/ragemp-improved-commands
Edited by rootcause
What's New in Version 1.1.1 See changelog
Released
- Improved fullText performance while processing a command.
As a downside, additional spaces in the fullText argument of command handlers and events is no longer removed by the library and needs to be handled by scripters.
Recommended Comments
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now