Introducing the CustomCommands module!

Introduction

Admin commands are difficult to make and take a lot of work. This is where the CustomCommands module comes in. It lets you create commands with relatively low effort, and it has many other useful features for string parsing, and the such.

Who is this for?

This module is specifically for people who don’t need all of the features of HD Admin, and just need to add a few commands here and there. It is also for people who need to process things like ints, floats, bools, and strings from strings.

Syntax

CustomCommands admin syntax is relatively easy to learn.
For example, in a lot of admin commands modules, they include a kill command, usually along the lines of this:

;kill others

in CustomCommands, the syntax is a bit different, but pretty similar:

!kill("others")

CustomCommands can process more than one function in one execution too, like this:

!command1("Hello!", 12.34) !command2(true)

There are 4 types of items you can put into a command:
player, string, int, float, and bool.

A player can be a specific name, like !command("RDJpower"), or something like !greet("others").
A string is, well, a string! strings like !newline("\n") are also handled correctly.
An int is any whole number, -10, 1, 10, 99 and the such.
A float is any integer, and any decimal number, -5.3, 9.1, 10.73 etc.
A bool is true or false.

Getting Started

first, import CustomCommands (https://create.roblox.com/store/asset/108012389991573/CustomCommands) into your project, and put it wherever you like.

For this example, I will make a simple damage command, that hurts someone by the given HP amount to the given Player.

Let’s begin.

local CustomCommands = require(--[[Wherever you put the module]])

first, we call add_command to make create a command.

--[[
function CustomCommands.add_command(name: string, command: {
    params: {"player" | "int" | "float" | "bool" | "string"},
    fn: (...any) -> ()
}): CustomCommands -- itself
]]
CustomCommands.add_command("damage", {
    params = {"player", "float"},
    fn = function(players: {Player}, damageAmt: number)
          for i, v in players do
                 if not v.Character then continue end
                 local hum = v.Character:FindFirstChildOfClass("Humanoid")
                 if not hum then continue end
                 hum:TakeDamage(damageAmt)
          end
    end
})

You might have caught on that players is a table, and that is because the user can do something like
!damage("all", 100) or !damage("others", 100), and it’s easier for you to just expect a table.

Next, params. Params is required so then the user cannot input other types like 3.5 for the player name.

If you so choose, you can also lock the module so no further commands can be added as follows:

CustomCommands.lock()

We can now try to execute the command when a player sends a message.

game.Players.PlayerAdded:Connect(function(player: Player)
	player.Chatted:Connect(function(message: string)
		CustomCommands.execute(message, player)  -- Player is optional, but required for "me", and "others" to work.
	end)
end)

And boom, you got working commands!

Documentation

There are more functions in this module, and they will be documented here.

Public Functions
function CommandsHandler.add_command(name: string, command: Command)
Adds a command with named name that will run according to the command if it is requested when CommandsHandler.execute is called.

function CommandsHandler.execute(command: string, playerWhoCalled: Player?)
Attempts to execute the command string from the commands given by CommandsHandler.add_command, with an optional playerWhoCalled if for example !command("me") or !command("others") should work.

function CommandsHandler.lock()
Blocks CommandsHandler.add_command from functioning if called.

function CommandsHandler.filter<K,V>(t: {[K]: V}, fn: (K, V) -> any?): {[K]: any}
Takes in table t of type {[K]: V}, and fn of type (K,V) -> any?, and for every index and value in t it gets changed to the value of fn called with the value and index.

function CommandsHandler.guess_name(name: string, items: {any}, access_str: (any) -> string): any?
Attempts to “guess” the name in items, using access_str to get the string form of each item of items, and returns the value that most accurately matches the name, if found.

Private Functions
These are by default not accessible from the module, but you can make them public if you need them.

function finished(inputstr: {string}, pos: number): boolean
Given the array of characters (inputstr), finished returns if pos is greater than the length of inputstr.

function skipWhitespace(inputstr: {string}, pos: number): number
Given the array of chars (inputstr), skipWhitespace returns the index of the next character past any whitespace characters.

function isAlpha(c: string): boolean
Returns true if the character c is alphabetic.

function isNumeric(c: string): boolean
Returns true if the character c is numeric.

function isAlphaNumeric(c: string): boolean
Returns true if the character c is alphabetic, or numeric.

function ident(inputstr: {string}, pos: number) : (boolean, number?, string?)
Given the array of chars inputstr, and the start position of pos, this function returns the success of the function, and if successful, the index past the identifier, and the identifier (think of a variable name).

function bool(inputstr: {string}, pos: number) : (boolean, number?, {[any]: any}?)
Given the array of chars inputstr, and the start position of pos, this function returns the success of the function, and if successful, the index past the boolean, and a table with indexes of ["type"] = "bool", and ["data"] equal to if the boolean was true or false.

function num(inputstr: {string}, pos: number) : (boolean, number?, {[any]: any}?)
Given the array of chars inputstr, and the start position of pos, this function returns the success of the function, and if successful, the index past the number, and a table with indexes of ["type"] equaling to "int" or "float" depending on whether the parsed number is whole or not, and ["data"] with the parsed number.

function str(inputstr: {string}, pos: number) : (boolean, number?, {[any]: any}?)
Given the array of chars inputstr, and the start position of pos, this function returns the success of the function, and if successful, the index past the string, and a table with indexes of ["type"] = "string" and ["data"] equal to the string processed minus the quotes.

function primary(inputstr: {string}, pos: number) : (boolean, number?, {[any]: any}?)
Given the array of chars inputstr, and the start position of pos, this function returns the success of the function, and if successful, and returns the value from either the bool, str, or num functions.

function parseFunction(inputstr: {string}, pos: number) : (boolean, number?, {[any]: any}?)
Given the array of chars inputstr, and the start position of pos, this function returns the success of the function, and if successful, returns a table with indexes of ["type"] = "function", and a data table that has the parameters of the call, and the name of the function attempting to be called.

function parseInput(inp: string) : {[any]: any}?
Given the string inp, parseInput returns a table consisting of parseFunction calls using inp if the inp string is a valid command.

5 Likes

This is a incredible feature! I might use it for a upcoming game that I’m currently working on, nice job!

3 Likes