Giter Club home page Giter Club logo

cmdr's Introduction

Cmdr is a fully extensible and type safe command console for Roblox developers.

  • Great for admin commands, but does much more.
  • Make commands that tie in specifically with your game systems.
  • Intelligent autocompletion and instant validation.
  • Run commands programmatically on behalf of the local user.
  • Bind commands to user input.
  • Secure: the client and server both validate input separately.
  • Embedded commands: dynamically use the output of an inner command when running a command.

Demo video

cmdr's People

Contributors

autonordev avatar benhdev avatar code-sync avatar dependabot[bot] avatar edvinsmineikis avatar evaera avatar gigsd4x avatar hexcede avatar howmanysmall avatar hyphex avatar jaguar-515 avatar kampfkarren avatar logixism avatar luke-gnar avatar misternathan avatar noatblok avatar outofbearspace avatar podskio avatar robinwassen avatar seyaidev avatar signalmansteve avatar slixxed avatar thenexusavenger avatar triplefrequency avatar tsjiptsjip avatar ulferno avatar user-take avatar validark avatar wilyt1 avatar xswezan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

cmdr's Issues

Mark types as listable

which means that argument can be a comma-separated list of values

  • All values need to share type from the first in sequence
  • No prefixed union types allowed on following values
  • Handle in the code that runs through arguments
    • Split by comma no matter what, check first type, then go from there
  • Final values should be merged into the parsed table from the first value when sent to implementation

Let argument definitions override functions from the type definition

...
Args = {
        {
            Type = "players";
            Name = "from";
            Description = "The players to teleport";
            OverrideType = {
                    Autocomplete = function (context, default) -- Accepts the command context, and the default function from the type defintion
                            return function (value) -- Can inspect the context and return either the `default` value or a new function to replace the one in the type definition
                                if context:GetArgument(1):GetValue() == "something" then
                                        return {1, 2, 3}
                                end
                            end
                    end
            }
        },
}
...

Bind to chat and accept bind arguments

Parse bind resources arguments as $1
Ambient arguments like $hover

Bindable resources: !

  • Chat

Bindable players (chat): @

Add commands:

  • echo: prints given text
  • run:

Gui should not be instantiated in StarterGui

There are a number of problems with this. For one, it gives a copy to everyone by default. Furthermore, if this code runs after any players have already joined, then it will not be replicated to them. Instead, authorized players who should be able to use Cmdr should call the instantiation function on their machines.

Alias command

Alias:

  • Registry:RegisterAlias(aliasName, commandName, args)
    • aliasName= aliasName()
    • Ensure no conflicts in self.Commmands[aliasName]
    • self.Commands[aliasName] = self:GetCommand(commandName)
    • self.UserAliases[aliasName] = args
  • Registry:GetUserAlias(aliasName): args
    • Check in auto complete, don't show auto complete if exists
  • Dispatcher.Evaluate:
    • Check GetUserAlias
    • If exists, use args from that

Add a clear command

A client-side command that would use the DefaultUtil group.
When run, it would simply remove all lines besides the input line from the console screen.

playerid type

Autocompletes with players in-game, but also allows any string. Resolves to the player's user ID.

Inhibitors

For example, hiding admin commands from the everyday user if Cmdr is being used as a gameplay element as well as an admin console. Maybe a BeforeRun hook could be used for this, maybe the help command could read from context.State.Hidden if it exists, or maybe context.State.Whitelist?

A custom help command can do this, but what about the default one?

I am confused about this Cmdr

Can you at least give us a place demo? (It can be useful when people don't understand how to use this)

And Where is the adminlist userid? I can't find it somewhere.

And what's the prefix key? To open the command bar?

All of your tutorial is which I don't understand how to run it.

Make tab completion encapsulate entire argument in quotes, not just last segment

If you have a listable type, and attempt to use CSV with quotes, the values aren't found.

As a simple example using built-in types/commands:
This command would work: teleport TripleFrequency,TripleFrequency TripleFrequency
But this command wouldn't: teleport "TripleFrequency",TripleFrequency TripleFrequency

This is only an issue when specifying multiple values, if you only have one value of a listable type, then it still works: teleport "TripleFrequency" TripleFrequency

If any of values in a listable type are in quotes, then it fails.

Prefixed union types

Union types that default to one type, but given a prefix (such as %) turn into another type. Would be delivered to function runner as { type="type"; value="value" }.

This could be useful for re-implementing team matches. Union between players and teams. Maybe a new type known as teamplayers, which matches teams, but returns array of players to the function. Under that system, current players type would be players % teamplayers (union)

another example:
"players % teamplayers # place : string"

Add more conditions to runif

  • contains
  • endsWith
  • pattern
  • ==
  • !=
  • >
  • <
  • >=
  • <=
  • # (length)

And add runif to the meta-commands section (and rename that section to "meta-commands")

  • Fix order of runif arguments
  • And generalize command strings, support && in all contexts, not just alias.
  • Look into escaping both && and quotes, generalize escaping if possible
  • Print command with color
  • Rename run to eval

Question

Will this be all it is or do you plan to make a full-fledged admin system or is that up to the developer themselves. Just curious.

Add types

  • brickColor, brickColors https://gist.github.com/TripleFrequency/e43fe44d50d596634894ee236fdac71e
  • duration, durations
  • brickColor3, brickColor3s - resolves into a Color3, but selected by brickColor name
  • teamColor, teamColors - resolves into BrickColor matching by team, uses that team's color
  • hexColor3, hexColor3s - resolve hex into Color3
  • color3, color3s (delineate by comma or spaces, checking comma first) - Color3
  • vector3, vector3s (delineate by comma or spaces, checking comma first) - Vector3
  • time
  • integers
  • strings
  • numbers
  • booleans

Embedded commands

Commands that are executed inside of other commands, with the format ${command}

Write documentation

  • Mention automated commands
  • Prefixed union types
  • Event handlers
  • API
  • Default commands array
  • Bind and Alias
  • Embedded commands

Model file is unnecessary

Here is what my Model to Lua plugin spit out, which could easily be integrated into the Scripts. It would make setup easier and it would better guarantee that this repo is fully functional.

local Cmdr = Instance.new("ScreenGui")
Cmdr.DisplayOrder = 1000
Cmdr.Name = "Cmdr"
Cmdr.ResetOnSpawn = false

local Frame = Instance.new("ScrollingFrame")
Frame.BackgroundColor3 = Color3.fromRGB(17, 17, 17)
Frame.BackgroundTransparency = 0.4
Frame.BorderSizePixel = 0
Frame.CanvasSize = UDim2.new(0, 0, 0, 100)
Frame.Name = "Frame"
Frame.Position = UDim2.new(0.025, 0, 0, 25)
Frame.ScrollBarThickness = 6
Frame.ScrollingDirection = Enum.ScrollingDirection.Y
Frame.Selectable = false
Frame.Size = UDim2.new(0.95, 0, 0, 50)
Frame.Visible = false
Frame.Parent = Cmdr

local Autocomplete = Instance.new("Frame")
Autocomplete.BackgroundColor3 = Color3.fromRGB(59, 59, 59)
Autocomplete.BackgroundTransparency = 0.5
Autocomplete.BorderSizePixel = 0
Autocomplete.Name = "Autocomplete"
Autocomplete.Position = UDim2.new(0, 167, 0, 75)
Autocomplete.Size = UDim2.new(0, 200, 0, 200)
Autocomplete.Visible = false
Autocomplete.Parent = Cmdr

local UIListLayout = Instance.new("UIListLayout")
UIListLayout.SortOrder = Enum.SortOrder.LayoutOrder
UIListLayout.Parent = Frame

local Line = Instance.new("TextLabel")
Line.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
Line.BackgroundTransparency = 1
Line.Font = Enum.Font.Code
Line.Name = "Line"
Line.Size = UDim2.new(1, 0, 0, 20)
Line.TextColor3 = Color3.fromRGB(255, 255, 255)
Line.TextSize = 14
Line.TextXAlignment = Enum.TextXAlignment.Left
Line.Parent = Frame

local UIPadding = Instance.new("UIPadding")
UIPadding.PaddingBottom = UDim.new(0, 10)
UIPadding.PaddingLeft = UDim.new(0, 10)
UIPadding.PaddingRight = UDim.new(0, 10)
UIPadding.PaddingTop = UDim.new(0, 10)
UIPadding.Parent = Frame

local Entry = Instance.new("Frame")
Entry.BackgroundTransparency = 1
Entry.LayoutOrder = 999999999
Entry.Name = "Entry"
Entry.Size = UDim2.new(1, 0, 0, 20)
Entry.Parent = Frame

local UIListLayout2 = Instance.new("UIListLayout")
UIListLayout2.SortOrder = Enum.SortOrder.LayoutOrder
UIListLayout2.Parent = Autocomplete

local Title = Instance.new("Frame")
Title.BackgroundColor3 = Color3.fromRGB(59, 59, 59)
Title.BackgroundTransparency = 0.2
Title.BorderSizePixel = 0
Title.LayoutOrder = -2
Title.Name = "Title"
Title.Size = UDim2.new(1, 0, 0, 40)
Title.Parent = Autocomplete

local Description = Instance.new("Frame")
Description.BackgroundColor3 = Color3.fromRGB(59, 59, 59)
Description.BackgroundTransparency = 0.2
Description.BorderSizePixel = 0
Description.LayoutOrder = -1
Description.Name = "Description"
Description.Size = UDim2.new(1, 0, 0, 20)
Description.Parent = Autocomplete

local TextButton = Instance.new("TextButton")
TextButton.BackgroundColor3 = Color3.fromRGB(59, 59, 59)
TextButton.BackgroundTransparency = 0.5
TextButton.BorderSizePixel = 0
TextButton.Font = Enum.Font.Code
TextButton.Size = UDim2.new(1, 0, 0, 30)
TextButton.Text = ""
TextButton.TextColor3 = Color3.fromRGB(255, 255, 255)
TextButton.TextSize = 14
TextButton.TextXAlignment = Enum.TextXAlignment.Left
TextButton.Parent = Autocomplete

local TextBox = Instance.new("TextBox")
TextBox.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
TextBox.BackgroundTransparency = 1
TextBox.ClearTextOnFocus = false
TextBox.Font = Enum.Font.Code
TextBox.LayoutOrder = 999999999
TextBox.Position = UDim2.new(0, 140, 0, 0)
TextBox.Size = UDim2.new(1, 0, 0, 20)
TextBox.Text = "x"
TextBox.TextColor3 = Color3.fromRGB(255, 255, 255)
TextBox.TextSize = 14
TextBox.TextXAlignment = Enum.TextXAlignment.Left
TextBox.Parent = Entry

local TextLabel = Instance.new("TextLabel")
TextLabel.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
TextLabel.BackgroundTransparency = 1
TextLabel.Font = Enum.Font.Code
TextLabel.Size = UDim2.new(0, 133, 0, 20)
TextLabel.Text = ""
TextLabel.TextColor3 = Color3.fromRGB(255, 223, 93)
TextLabel.TextSize = 14
TextLabel.TextXAlignment = Enum.TextXAlignment.Left
TextLabel.Parent = Entry

local Field = Instance.new("TextLabel")
Field.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
Field.BackgroundTransparency = 1
Field.Font = Enum.Font.SourceSansBold
Field.Name = "Field"
Field.Size = UDim2.new(0, 37, 1, 0)
Field.Text = "from"
Field.TextColor3 = Color3.fromRGB(255, 255, 255)
Field.TextSize = 20
Field.TextXAlignment = Enum.TextXAlignment.Left
Field.Parent = Title

local UIPadding2 = Instance.new("UIPadding")
UIPadding2.PaddingLeft = UDim.new(0, 10)
UIPadding2.Parent = Title

local Label = Instance.new("TextLabel")
Label.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
Label.BackgroundTransparency = 1
Label.Font = Enum.Font.SourceSansLight
Label.Name = "Label"
Label.Size = UDim2.new(1, 0, 1, 0)
Label.Text = "The players to teleport. The players to teleport. The players to teleport. The players to teleport. "
Label.TextColor3 = Color3.fromRGB(255, 255, 255)
Label.TextSize = 16
Label.TextWrapped = true
Label.TextXAlignment = Enum.TextXAlignment.Left
Label.TextYAlignment = Enum.TextYAlignment.Top
Label.Parent = Description

local UIPadding3 = Instance.new("UIPadding")
UIPadding3.PaddingBottom = UDim.new(0, 10)
UIPadding3.PaddingLeft = UDim.new(0, 10)
UIPadding3.PaddingRight = UDim.new(0, 10)
UIPadding3.Parent = Description

local Typed = Instance.new("TextLabel")
Typed.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
Typed.BackgroundTransparency = 1
Typed.Font = Enum.Font.Code
Typed.Name = "Typed"
Typed.Size = UDim2.new(1, 0, 1, 0)
Typed.Text = "Lab"
Typed.TextColor3 = Color3.fromRGB(131, 222, 255)
Typed.TextSize = 14
Typed.TextXAlignment = Enum.TextXAlignment.Left
Typed.Parent = TextButton

local UIPadding4 = Instance.new("UIPadding")
UIPadding4.PaddingLeft = UDim.new(0, 10)
UIPadding4.Parent = TextButton

local Suggest = Instance.new("TextLabel")
Suggest.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
Suggest.BackgroundTransparency = 1
Suggest.Font = Enum.Font.Code
Suggest.Name = "Suggest"
Suggest.Size = UDim2.new(1, 0, 1, 0)
Suggest.Text = "   el"
Suggest.TextColor3 = Color3.fromRGB(255, 255, 255)
Suggest.TextSize = 14
Suggest.TextXAlignment = Enum.TextXAlignment.Left
Suggest.Parent = TextButton

local Type = Instance.new("TextLabel")
Type.BackgroundColor3 = Color3.fromRGB(255, 255, 255)
Type.BackgroundTransparency = 1
Type.BorderColor3 = Color3.fromRGB(255, 153, 153)
Type.Font = Enum.Font.SourceSans
Type.Name = "Type"
Type.Position = UDim2.new(1, 0, 0, 0)
Type.Size = UDim2.new(0, 0, 1, 0)
Type.Text = ": Players"
Type.TextColor3 = Color3.fromRGB(255, 255, 255)
Type.TextSize = 15
Type.TextXAlignment = Enum.TextXAlignment.Left
Type.Parent = Field

Hooks not working properly

I may be doing something horribly wrong, but hooks don't seem to work properly and I can't create a permissions system because of it.
Trying to do it this way on the server:

local Cmdr = require(script.Cmdr)

Cmdr:AddHook("BeforeRun", function(context)
	print("test")
end)

Cmdr:RegisterDefaultCommands()

'test' never gets printed on accurate play solo, or testing with 2 players.
This is using the .rbxm under release and seems to also apply to the RoStrap version.

Add "Tab→" note on autocompletion entries

Imagine this:

Type h. You see help, but you want history. Down arrow to select history, review the description, looks good. Right arrow... doesn't autocomplete, nothing happens. That's okay... clicking on the item also does nothing... Well heck, now I have to type a whole 5 letters. This is definitely not okay.

:)

bind states for keydown/keyup

If the first argument of a bound command is of type inputState, then send true on key down, and false and key release.

any arguments should be appended after this

More number types

natural, which would be a subset of the current integer type, would allow numbers in the range 0..n.
positive, which would be a subset of natural, would allow the range 1..n

byte, which would allow the range 0..255.
digit, which would allow the range 0..9.

RegisterDefaultCommands doesn't respect filter array

Code:

Server:

local replicatedStorage = game:GetService('ReplicatedStorage')
local cmdr = require(replicatedStorage.Cmdr)

cmdr:RegisterDefaultCommands({'Help', 'DefaultUtil'})

Client:

local replicatedStorage = game:GetService('ReplicatedStorage')
local cmdr = require(replicatedStorage:WaitForChild('CmdrClient'))

cmdr:SetPlaceName('[censored]')
cmdr:SetMashToEnable(true)
cmdr:SetActivationKeys({Enum.KeyCode.Semicolon})

Result:

image

You sure this is only help and util?

I installed it with RoStrap, I'll try manually installing it from the repo and see if the issue's fixed.

Add priority parameter to hooks

Add a third, optional parameter as a number. Lower should be sooner.

  • Allows "passive" hooks to fully execute before getting to a hook that could potentially interrupt a command, thereby not executing any later hooks (right now this is just random)
  • Lets hooks that modify state (as described in #28) come before other hooks that rely on that state (such as permissions reading a permission level)

Relative Vector3 type

Like a relative3 type that accepts ~ coordinates like Minecraft does. to @ ~, ~500, ~ would teleport you 500 studs into the air. to @ ~, ~-500, ~ 500 studs down.

Interpreting what these coordinates are relative to would be at the command's discretion.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.