Comandos
Um comando é uma palavra digitada em um console: o console do servidor no servidor, o console do jogo (F8) no cliente. Você associa uma função a essa palavra com addCommandHandler.
Estas 4 funções existem no servidor e no cliente. Você pode usá-las em scripts declarados em server_files, client_files ou shared_files.
O fluxo de uma linha de comando
Seção intitulada “O fluxo de uma linha de comando”Os registros continuam separados por lado, mas uma linha digitada pelo jogador no F8 é encaminhada automaticamente ao servidor. Se o mesmo nome estiver registrado nos dois lados, os dois conjuntos de manipuladores executam — primeiro no cliente, depois no servidor.
| Origem | Ordem exata |
|---|---|
| F8 do jogador | Manipuladores do cliente → onClientConsole → envio ao servidor → onPlayerCommand → manipuladores do servidor → onConsole. |
executeCommandHandler no cliente | Só os manipuladores do cliente. Não dispara onClientConsole e não envia nada ao servidor. |
| Console do servidor | Para um comando que não seja embutido: manipuladores do servidor → onConsole, com source = root. Não dispara onPlayerCommand. Comandos embutidos como start, status, ac e shutdown são resolvidos antes do Lua e não percorrem esse fluxo. |
executeCommandHandler no servidor | onPlayerCommand → manipuladores do servidor → onConsole, todos com o jogador informado como origem. |
Um manipulador local não consome a linha: mesmo que ele execute, a linha digitada no F8 ainda segue para o servidor. Cancelar onPlayerCommand, por outro lado, interrompe o lado do servidor antes de qualquer manipulador e também impede onConsole.
O cliente limita a parte encaminhada ao servidor a 255 bytes em UTF-8, sem cortar um caractere no meio. Os manipuladores locais e onClientConsole recebem a linha antes desse corte; handlers e eventos do servidor recebem a versão limitada.
Como o manipulador é chamado
Seção intitulada “Como o manipulador é chamado”Aqui está a diferença mais importante entre os dois lados: o servidor passa um argumento a mais, na frente de todos.
-- servidorhandler(source, nomeDoComando, ...)
-- clientehandler(nomeDoComando, ...)| Posição | Conteúdo |
|---|---|
source | Só no servidor. O jogador que digitou no F8 ou que um script informou em executeCommandHandler; false quando a linha veio do console do servidor. |
nomeDoComando | O nome exatamente como foi digitado. |
... | O resto da linha, quebrado nos espaços — um argumento por palavra. |
No servidor, use source == false para reconhecer o console. Uma linha recebida do F8 e uma execução feita por código em nome de um jogador entregam o elemento desse jogador.
No cliente não existe source: o comando só pode ter vindo do próprio jogador, então o primeiro parâmetro já é o nome do comando.
Todos os argumentos chegam como string: converta com tonumber quando precisar de números. Espaços repetidos não geram argumentos vazios, e uma linha sem argumentos simplesmente não passa nada além dos parâmetros fixos.
-- servidoraddCommandHandler("dar", function(source, cmd, item, quantidade) if source == false then outputDebugString("/dar não funciona pelo console do servidor", 2) return end darItem(source, item, tonumber(quantidade) or 1)end)
-- cliente: o mesmo comando, um parâmetro a menosaddCommandHandler("dar", function(cmd, item, quantidade) outputDebugString("pedindo " .. (tonumber(quantidade) or 1) .. "x " .. tostring(item))end)Segurança e controle de acesso
Seção intitulada “Segurança e controle de acesso”Qualquer jogador conectado pode digitar no F8 o nome de um comando registrado no servidor. Isso independe de existir um manipulador com o mesmo nome no cliente.
Valide a permissão dentro de cada manipulador sensível ou use o onPlayerCommand, que é cancelável e roda antes de todos eles:
local comandosDeAdmin = { kick = true, dar = true }
addEventHandler("onPlayerCommand", root, function(comando) local nome = string.lower(comando) if comandosDeAdmin[nome] and not getElementData(source, "admin") then cancelEvent(true, "sem permissão") endend)
addCommandHandler("dar", function(source, comando, item, quantidade) if source == false then outputDebugString("use este comando como jogador", 2) return end if not getElementData(source, "admin") then return end
darItem(source, item, tonumber(quantidade) or 1)end, true) -- `true` não elimina a checagem acima