Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 65 additions & 49 deletions modules/client/commands/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -83,20 +83,48 @@ function Commands:Run(command, context, arguments)
return true, result
end

function Commands:ProcessServer(data, input, inputContext)
return Network:InvokeServer("processCommand", data, input, inputContext)
function Commands:ProcessServer(prefix, commandName, arguments, contextData, input, inputContext)
contextData.prefix = prefix
contextData.commandName = commandName
contextData.arguments = arguments
return Network:InvokeServer("processCommand", contextData, input, inputContext)
end

function Commands:ProcessClient(input, inputContext)
-- Check if the input matches a command string, if not then we can ignore it.
function Commands:ProcessClient(namespace, commandName, arguments, input, inputContext)
local command = namespace.commandLookup[string.lower(commandName)]
if not command then
return ProcessResult.Fail, `Command "{commandName}" was not found.`
end

local context = Commands:CreateContext(command, input, inputContext)
local valid, message = Commands:Validate(command, context, arguments)
if not valid then
return ProcessResult.Error, message
end

local success, commandMessage = Commands:Run(command, context, arguments)
if not success then
return ProcessResult.Error, commandMessage
end

return ProcessResult.Success, commandMessage, context.Data
end

function Commands:Process(input, inputContext)
-- Check if the input matches a command string, if not then we can silently ignore it.
if not string.match(input, "^.+/") then
return ProcessResult.Fail, "Not a valid command string."
if inputContext ~= InputContext.Chat then
Output:append(Output.MessageType.Error, "Not a valid command string.")
end

return
end

local arguments = string.split(input, "/")
local prefix = table.remove(arguments, 1)
if not prefix then
return ProcessResult.Fail, "No prefix was found."
Output:append(Output.MessageType.Error, "No prefix was found.")
return
end

-- Remove last argument if empty.
Expand All @@ -115,53 +143,41 @@ function Commands:ProcessClient(input, inputContext)
-- Not default namespace, command should be the 2nd split string (prefix/command/arguments).
commandName = table.remove(arguments, 1)
else
return ProcessResult.Fail, "No command was given."
end

local command = namespace.commandLookup[string.lower(commandName)]
if not command then
return ProcessResult.Fail, `Command "{commandName}" was not found.`
end

local context = Commands:CreateContext(command, input, inputContext)
local valid, message = Commands:Validate(command, context, arguments)
if not valid then
return ProcessResult.Error, message
end

local success, commandMessage = Commands:Run(command, context, arguments)
if not success then
return ProcessResult.Error, commandMessage
end

return ProcessResult.Success, commandMessage, context.Data
end

function Commands:Process(input, inputContext)
local clientResult, clientMessage, contextData = Commands:ProcessClient(input, inputContext)
if clientResult ~= ProcessResult.Success then
-- Only output fail messages if the inputContext wasn't the chat (because you can also send chat messages in chat, duh),
-- Error messages should always be displayed.
if
clientResult == ProcessResult.Error
or (clientResult == ProcessResult.Fail and inputContext ~= InputContext.Chat)
then
Output:append(Output.MessageType.Error, clientMessage or "Unexpected error occured while running command.")
end

Output:append(Output.MessageType.Error, "No command was given.")
return
elseif clientMessage then
Output:append(Output.MessageType.Success, clientMessage)
end
commandName = commandName:split(" ")

for i, commandName in pairs(commandName) do
local clientResult, clientMessage, contextData =
Commands:ProcessClient(namespace, commandName, arguments, input, inputContext)
if clientResult ~= ProcessResult.Success then
-- Only output fail messages if the inputContext wasn't the chat (because you can also send chat messages in chat, duh),
-- Error messages should always be displayed.
if
clientResult == ProcessResult.Error
or (clientResult == ProcessResult.Fail and inputContext ~= InputContext.Chat)
then
Output:append(
Output.MessageType.Error,
clientMessage or "Unexpected error occured while running command."
)
end

local serverResult, serverMessage = Commands:ProcessServer(contextData, input, inputContext)
if serverResult ~= ProcessResult.Success then
-- We don't check if the ProcessResult was a Fail or Error here, because it should always be an Error.
Output:append(Output.MessageType.Error, serverMessage or "Unexpected error occured while running command.")
continue
elseif clientMessage then
Output:append(Output.MessageType.Success, clientMessage)
end

return
elseif serverMessage then
Output:append(Output.MessageType.Success, serverMessage)
local serverResult, serverMessage =
Commands:ProcessServer(prefix, commandName, arguments, contextData, input, inputContext)
if serverResult ~= ProcessResult.Success then
-- We don't check if the ProcessResult was a Fail or Error here, because it should always be an Error.
Output:append(Output.MessageType.Error, serverMessage or "Unexpected error occured while running command.")
continue
elseif serverMessage then
Output:append(Output.MessageType.Success, serverMessage)
end
end
end

Expand Down
9 changes: 3 additions & 6 deletions modules/client/wm/sandbox/rules.luau
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,16 @@ function Module.Init(_, Sandbox)

local parentThread = coroutine.running()
local warnThread
local fullName = GetFullName(self)
local traceback = debug.traceback(`Infinite yield possible on '{fullName}:WaitForChild("{childName}")`, 2)
if not timeOut and typeof(self) == "Instance" then
local fullName = GetFullName(self)
warnThread = task.delay(5, function()
-- Incase the WaitForChild thread stopped yielding (could be because the function threw an error), then don't emit the warning
if coroutine.status(parentThread) ~= "suspended" then
return
end

-- TODO: Add stacktrace
ManagerCommunication:Send(
"warn",
`Infinite yield possible on '{fullName}:WaitForChild("{childName}")'`
)
ManagerCommunication:Send("warn", traceback)
end)
sandbox.Threads[warnThread] = true
end
Expand Down
25 changes: 1 addition & 24 deletions modules/server/commands/init.luau
Original file line number Diff line number Diff line change
Expand Up @@ -79,34 +79,11 @@ function Commands:Run(command, context, arguments)
end

function Commands:Process(player, data, input, inputContext)
-- Check if the input matches a command string, if not then we can ignore it.
if not string.match(input, "^.+/") then
return ProcessResult.Fail, "Not a valid command string."
end

local arguments = string.split(input, "/")
local prefix = table.remove(arguments, 1)
if not prefix then
return ProcessResult.Fail, "No prefix was found."
end

-- Remove last argument if empty.
if #arguments[#arguments] == 0 then
table.remove(arguments, #arguments)
end

-- Find namespace, and get the command.
local commandName
local prefix, arguments, commandName = data.prefix, data.arguments, data.commandName
local namespace = Commands.namespaceLookup[string.lower(prefix)]
if not namespace then
-- No namespace with prefix found, default namespace, command should be the 1st split string (command/arguments).
commandName = prefix
namespace = Commands.namespaces.default
elseif arguments[1] and #arguments[1] > 0 then -- Check if there is a 2nd split string, otherwise no command was given.
-- Not default namespace, command should be the 2nd split string (prefix/command/arguments).
commandName = table.remove(arguments, 1)
else
return ProcessResult.Fail, "No command was given."
end

local command = namespace.commandLookup[string.lower(commandName)]
Expand Down
19 changes: 6 additions & 13 deletions modules/server/wm/sandbox/rules.luau
Original file line number Diff line number Diff line change
Expand Up @@ -95,20 +95,16 @@ function Module.Init(_, Sandbox)

local parentThread = coroutine.running()
local warnThread
local fullName = GetFullName(self)
local traceback = debug.traceback(`Infinite yield possible on '{fullName}:WaitForChild("{childName}")`, 2)
if not timeOut and typeof(self) == "Instance" then
local fullName = GetFullName(self)
warnThread = task.delay(5, function()
-- Incase the WaitForChild thread stopped yielding (could be because the function threw an error), then don't emit the warning
if coroutine.status(parentThread) ~= "suspended" then
return
end

-- TODO: Add stacktrace
ManagerCommunication:Send(
"warn",
sandbox.Owner,
`Infinite yield possible on '{fullName}:WaitForChild("{childName}")'`
)
ManagerCommunication:Send("warn", sandbox.Owner, traceback)
end)
sandbox.Threads[warnThread] = true
end
Expand Down Expand Up @@ -150,8 +146,7 @@ function Module.Init(_, Sandbox)
assertTerminated(sandbox)

if type(func) ~= "function" then
-- TODO: Add stacktrace
ManagerCommunication:Send("error", sandbox.Owner, Errors.connectNonFunction())
ManagerCommunication:Send("error", sandbox.Owner, debug.traceback(Errors.connectNonFunction(), 2))
return Connect(unwrap(self))
end

Expand All @@ -171,8 +166,7 @@ function Module.Init(_, Sandbox)
assertTerminated(sandbox)

if type(func) ~= "function" then
-- TODO: Add stacktrace
ManagerCommunication:Send("error", sandbox.Owner, Errors.connectNonFunction())
ManagerCommunication:Send("error", sandbox.Owner, debug.traceback(Errors.connectNonFunction(), 2))
return ConnectParallel(unwrap(self))
end

Expand All @@ -192,8 +186,7 @@ function Module.Init(_, Sandbox)
assertTerminated(sandbox)

if type(func) ~= "function" then
-- TODO: Add stacktrace
ManagerCommunication:Send("error", sandbox.Owner, Errors.connectNonFunction())
ManagerCommunication:Send("error", sandbox.Owner, debug.traceback(Errors.connectNonFunction(), 2))
return Once(unwrap(self))
end

Expand Down