16/08/2012

Como fazer scripts


PT-BR/Introducao ao GUI scripting

Um importante recurso no MTA:SA é a capacidade de script GUI (Graphic User Interface/Interface Gráfica do Usuário) personalizado. A GUI consiste de janelas, botões, caixas de edição, caixas de verificação... Quase todos os componentes padrão do formulário em ambientes gráficos. Eles podem ser exibidos enquanto o usuário está em jogo, e usado para entradas e saídas no lugar dos comandos tradicionais.

Admin Console GUI

Contents

 [hide]

Um tutorial para fazer uma janela de login

Neste tutorial, vamos fazer uma janela de login simples, com duas caixas de entrada e um botão. A janela aparece quando o jogador entra no jogo, e quando o botão é clicado, o jogador é gerado no jogo. O tutorial vai continuar o modo de jogo que fizemos no Introdução ao Scripting (Se você já usou o Introdução ao Scripting, você precisará remover ou comentar a linha spawnPlayerda função "joinHandler" em seu código, como iremos substituí-lo por uma GUI alternativa neste tutorial). Nós também vamos dar uma olhada no scripting client-side.

Criando a janela

Toda a GUI deve ser feita do lado client. Também é uma boa prática manter todos os scripts do lado client em uma pasta separada.
Vá até o diretório /SeuServerMTA/mods/deathmatch/resources/, e crie uma pasta chamada "client". Sob o diretório /client/, crie um arquivo de texto com o nome "gui.lua".
Neste arquivo vamos escrever uma função que cria a janela. Para criar uma janela, iremos utilizar guiCreateWindow:
function criarJanelaDeLogin()
 -- definir a posição X e Y da janela
 local X = 0.375
 local Y = 0.375
 -- definir a largura e altura da janela
 local Largura = 0.25
 local Altura = 0.25
 -- criar a janela e salvar o valor de seu elemento na variável 'wdwLogin'
 -- clique no nome da função para ler a sua documentação
 wdwLogin = guiCreateWindow(X, Y, Largura, Altura, "Por favor efetue o Login", true)
end

Relativo e Absoluto

Nota-se que o argumento final passado para guiCreateWindow no exemplo acima é true. Isto indica que as coordenadas e dimensões da janela são relativa, o que significa que é uma porcentagem do tamanho total da tela. Isto significa que se o lado esquerdo da tela é 0, e a extrema-direita é 1, uma posição X de 0.5 representaria o ponto central da tela. Similarmente, se a parte superior da tela é 0 e no fundo é 1, uma posição Y de 0.2 seria 20% do caminho para baixo da tela. Os mesmos princípios se aplicam para largura e altura, bem como (com um valor de largura de 0.5 significa que a janela será a metade da largura da tela).
A alternativa de utilizar valores relativos é utilizar absolutos (passando false ao invés de true para guiCreateWindow). Os valores absolutos são calculados como o número total de pixels do canto superior esquerdo de seu parent (se nenhum elemento parent gui é especificado, o parent é a própria tela). Se assumirmos uma resolução de ecrã de 1920x1200, o lado esquerdo da tela sendo 0 pixel e os extrema-direita, sendo 1920 pixels, uma posição X de 960 representará o ponto central da tela. Similarmente, se a parte superior da tela é de 0 pixel eo fundo é de 1200, uma posição Y de 20 seria de 20 pixels para baixo a partir da parte superior da tela. Os mesmos princípios se aplicam a largura e altura, bem como (com um valor de largura de 50 ou seja, a janela será de 50 pixels de largura). Você pode usar guiGetScreenSize e um pouco de matemática para calcular certas posições absolutas.
As diferenças entre o uso de valores relativos e absolutos é muito simples; gui criada usando valores absolutos será sempre exatamente o mesmo tamanho de pixel e posição, enquanto gui criado usando valores relativos será sempre uma porcentagem do tamanho do seu parent.
Absoluto é geralmente mais fácil de usar quando a edição do código é á mão, no entanto a escolha do tipo depende da situação que você está usando para isso.
Para esta presente introdução iremos utilizar valores relativos.

Adicionando os componentes

Em seguida, vamos adicionar os rótulos de texto (labels) (dizendo "username:" e "senha:"), caixas de edição (edit boxes) (para inserir seus dados) e um botão para efetuar login.
Para criar botões você deve usar guiCreateButton e para criar caixas de edição você deve usar guiCreateEdit:
Note que agora iremos escrever mais código para a nossa função atual 'criarJanelaDeLogin'. Esta não é uma nova função e se destina a substituir o que você já tem.
function criarJanelaDeLogin()
 local X = 0.375
 local Y = 0.375
 local Largura = 0.25
 local Altura = 0.25
 wdwLogin = guiCreateWindow(X, Y, Largura, Altura, "Por favor efetue o Login", true)
 
 -- definir as novas posições X e Y para o primeiro label
 X = 0.0391
 Y = 0.1979
 -- definir o novo valor de largura e altura para o primeiro label
 Largura = 0.3672
 Altura = 0.25
 -- criar o primeiro label, note que o último argumento passado é 'wdwLogin', que significa a janela
 -- o que criámos acima é o parent deste rótulo de texto (label)
 -- (assim toda a posição e os valores de tamanho são agora relativo para a posição dessa janela)
 guiCreateLabel(X, Y, Largura, Altura, "Nome de Usuario", true, wdwLogin)
 -- altere o valor de Y, assim o segundo label esteja ligeiramente abaixo do primeiro
 Largura = 0.25
 Y = 0.5
 guiCreateLabel(X, Y, Largura, Altura, "Senha", true, wdwLogin)
 
 X = 0.415
 Y = 0.2
 Largura = 0.5
 Altura = 0.15
 editUsuario = guiCreateEdit(X, Y, Largura, Altura, "", true, wdwLogin)
 Y = 0.5
 edtSenha = guiCreateEdit(X, Y, Largura, Altura, "", true, wdwLogin)
 -- definir o tamanho máximo de caracteres do nome de usuário e Senha para 50
 guiEditSetMaxLength(editUsuario, 50)
 guiEditSetMaxLength(edtSenha, 50)
 
 X = 0.415
 Y = 0.7
 Largura = 0.25
 Altura = 0.2
 btnLogin = guiCreateButton(X, Y, Largura, Altura, "Login", true, wdwLogin)
 
 -- tornar a janela invisível
 guiSetVisible(wdwLogin, false)
end
Note que cada componente GUI criado é um filho da janela, isto é feito através da especificação do elemento pai (wdwLogin, neste caso) ao criar o componente.
Isto é muito útil porque não só significa que todos os componentes estão anexados à janela e irá mover-se com ela, mas também que todas as alterações feitas para a janela pai será aplicada para todos os elementos filho. Por exemplo, agora podemos ocultar toda a GUI que acabamos de criar, basta ocultar a janela:
guiSetVisible(wdwLogin, false) -- oculta toda a GUI que fizemos para que possamos mostrá-los para o jogador, quando for preciso.

Usando a função criada anteriormente

A função criarJanelaDeLogin agora está completa, mas nada vai acontecer até que nós a chamamos. È Recomendado criar toda a GUI quando o recurso client for iniciado, então será ocultada, e mostrará para o jogador quando necessário. Portanto, vamos escrever um manipulador de eventos para "onClientResourceStart" para criar a janela:
-- anexar o manipulador de eventos para o elemento raiz (root element) do recurso
-- isso significa que ele só irá desencadear (trigger) quando seu próprio recurso é iniciado
addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()), 
 function ()
  criarJanelaDeLogin()
 end
)
Como este é uma janela de login, agora precisamos mostrar a janela quando o jogador entra no jogo. Isto pode ser feito usando o mesmo evento, "onClientResourceStart", para que possamos modificar o código acima e incluir para mostrar a janela:
Observe que agora estamos escrevendo mais código para o nosso manipulador 'onClientResourceStart' existente. Este não é um novo manipulador de eventos e se destina a substituir o que você já tem.
addEventHandler("onClientResourceStart", getResourceRootElement(getThisResource()), 
 function ()
  -- criar a janela de login e seus componentes
  criarJanelaDeLogin()
 
  -- saída de uma mensagem de boas-vindas ao jogador
                outputChatBox("Bem-vindo ao meu servidor MTA:SA, por favor efetue o login.")
 
  -- se a GUI foi criada com êxito, então, mostrar a GUI para o jogador
         if (wdwLogin ~= nil) then
   guiSetVisible(wdwLogin, true)
  else
   -- se a GUI não foi criada corretamente, notificar o jogador
   outputChatBox("Um erro inesperado ocorreu e a janela de login não foi criada.")
         end
 
  -- habilitar o cursor para os jogadores (para que eles possam selecionar e clique sobre os componentes)
         showCursor(true)
  -- definir o foco de entrada para a GUI, permitindo que os jogadores (por exemplo) para pressione 'T', sem que o chatbox abra
         guiSetInputEnabled(true)
 end
)
Note que temos uma simples verificação de segurança antes de tornar a janela visível, no caso improvável de que a janela não foi criada, significa que wdwLogin não é um elemento válido, nós não temos um erro. e apenas informamos o jogador o que aconteceu. Na próxima etapa, vamos criar a funcionalidade para o botão de login.

Programando o botão

Agora que nós criamos nossa GUI e mostrou-a para o jogador, é preciso programa-la para que possa funcionar.

Detectando o clique

Quando o jogador clica em qualquer parte da GUI, o evento "onClientGUIClick" será acionado para o componente GUI que você clicou. Isso nos permite facilmente detectar quaisquer cliques sobre o elemento GUI que deseja usar. Por exemplo, podemos anexar o evento para o botão btnLogin para obter todos os cliques sobre ele:
-- anexar o evento onClientGUIClick para btnLogin e definir-lo para chamar a função 'submeterLoginClient'
addEventHandler("onClientGUIClick", btnLogin, submeterLoginClient, false)
Observe o argumento final passado é "false". Isto indica que o evento só irá acionar diretamente sobre btnLogin, não se o evento tem propagado para cima ou para baixo da árvore. Se configurado para "true", enquanto anexado ao elemento gui significa que se clicar em qualquer elemento no mesmo ramo vai disparar esse evento.
Esta linha de código agora pode ser adicionada dentro da função criarJanelaDeLogin. É um erro comum, tentar anexar eventos a elementos GUI inexistentes, então certifique-se sempre de anexar os seus eventos depois o elemento gui (neste caso, o botão) foi criado:
Note que vamos agora escrever mais código para a nossa função 'criarJanelaDeLogin'.
function criarJanelaDeLogin()
 -- criar todos os nossos elementos da GUI
 ...
 
 -- agora adicionar o evento onClientGUIClick para o botão que acabamos de criar
 addEventHandler("onClientGUIClick", btnLogin, submeterLoginClient, false)

Gerenciando o clique

Agora que podemos detectar quando o jogador clica no botão, é preciso escrever o código para gerenciar o que acontece quando ele é clicado. Em nosso manipulador de eventos onClientClick, a função submeterLoginClient sempre será chamada quando o botão btnLogin for clicado. Portanto, agora podemos usar a função submeterLoginClient para controlar o que acontece quando o botão é clicado:
-- criar a função e definir os parâmetros para 'botão' (button) e 'estado' (state)
-- (eles são passados automaticamente pelo onClientGUIClick)
function submeterLoginClient(button,state)
 -- se o nosso botão de login foi clicado com o botão esquerdo do mouse, eo estado do botão do mouse é up
 if button == "left" and state == "up" then
  -- mover o foco de entrada de volta para o jogo (permitindo aos jogadores para se movimentar, abrir o chat, etc)
  guiSetInputEnabled(false)
  -- ocultar a janela e todos os componentes
  guiSetVisible(wdwLogin, false)
  -- desabilitar o cursor do mouse
  showCursor(false)
 end
end
Agora, quando o botão é clicado, a janela será ocultada e todos os controles serão permitidos para o jogador. Em seguida, vamos ligar com o lado server para permitir que o jogador execute spawn.

Chamando o lado server

Chamando o lado server pode ser feito usando triggerServerEvent. Isto lhe permite chamar um evento especificado no server através do client. Se quiser chamar o client através do server pode ser feito usando triggerClientEvent. Aqui, usamos a funçãotriggerServerEvent para chamar o nosso evento personalizado no lado server, chamado "submeterLogin", que irá controlar a função de spawn que é do lado server.
Note que iremos agora escrever mais código para a nossa função 'submeterLoginClient'. Esta não é uma nova função e se destina a substituir o que você já tem.
function submeterLoginClient(button,state)
 if button == "left" and state == "up" then
  -- obter o texto inserido no campo 'nomeDeUsuario'
  local nomeDeUsuario = guiGetText(editUsuario)
  -- obter o texto inserido no campo 'senha'
  local senha = guiGetText(edtSenha)
 
  -- se o nome de usuário e senha existem
  if nomeDeUsuario and senha then
   -- acionar o evento server 'submeterLogin' e passar o nome de usuário e senha para ele
   triggerServerEvent("submeterLogin", getRootElement(), nomeDeUsuario, senha)
 
   -- ocultar a gui, desabilitar o cursor e retornar o controle para o jogador
   guiSetInputEnabled(false)
   guiSetVisible(wdwLogin, false)
   showCursor(false)
  else
   -- caso contrário, irá sair uma mensagem para o jogador, se o nome de usuário e/ou senha não existem
   -- e não ocultar a gui
   outputChatBox("Por favor, digite o nome de usuário e senha.")
  end
 end
end

Criando o evento do lado server

Neste ponto nós temos agora todos os códigos necessários no lado do client, então abrra seu arquivo do lado server 'script.lua' (do Introdução ao Scripting) ou outro arquivo do lado server adequado para trabalhar.
No lado do servidor, lembre-se que o jogador executará o spawn assim que entrar. Então, em primeiro lugar, teremos que definir o evento personalizado que iremos usar antes no client. Isto pode ser feito usando addEvent e AddEventHandler.
-- criar nossa função loginHandler, com parâmetros 'username' e 'senha' (passado pelo client gui)
function loginHandler(username,senha)
 
end
 
-- definir o nosso evento personalizado e permitir que ele seja acionado a partir do cliente ('true')
addEvent("submeterLogin",true)
-- adicionar um manipulador de eventos para quando 'submeterLogin' for acionado, a função 'loginHandler' é chamada
addEventHandler("submeterLogin",root,loginHandler)

Efetuando login

Agora, temos uma função que é chamada através do evento personalizado 'submeterLogin', podemos começar a trabalhar com o login e spawn do jogador, usando a nossa função 'loginHandler':
function loginHandler(username,senha)
 -- verificar se o nome de usuário e senha estão corretos
 if username == "user" and senha == "apple" then
  -- se o jogador foi logado com sucesso, então gerar ele no jogo
  if (client) then
   spawnPlayer(client, 1959.55, -1714.46, 10)
   fadeCamera(client, true)
                        setCameraTarget(client, client)
   outputChatBox("Bem-vindo ao servidor.", client)
  end
 else
  -- se o nome de usuário ou senha não estão corretos, informar para o jogador
  outputChatBox("Nome de usuário e senha inválidos. Por favor, tente novamente.",client)
        end   
end
 
addEvent("submeterLogin",true)
addEventHandler("submeterLogin",root,loginHandler)
Para os fins deste tutorial, um sistema de username e senha muito básico é mostrado. Para uma alternativa mais compreensiva, você pode usar o Sistema de Conta ou um banco de dados MySQL.
Observe também o uso da variável "client", é uma variável interna usada pelo MTA para identificar o jogador que disparou o evento.

Finalmente, não se esqueça de incluir o arquivo gui.lua novo no meta.xml do recurso principal, e nomeá-lo como um script client:
<script src="client/gui.lua" type="client" />

Neste ponto, temos agora uma janela de login básico que verifica nome de usuário do jogador e senha quando o botão de login é clicado. Se eles estiverem corretos, o jogador é automaticamente gerado no jogo.
Para mais ajuda com GUI, consulte Tutoriais GUI.

Isso foi retirado da wiki oficial do mta,clique aqui para acessar