Pular para o conteúdo

Estrutura Base

Esta seção descreve a estrutura fundamental de uma integração LightScript, cobrindo requisitos técnicos essenciais, exemplos do mundo real, convenções de nomenclatura e dicas de eficiência. Ela percorre o loop de atualização, o comportamento dos medidores, a lógica de acionamento de efeitos e destaca armadilhas comuns. Seja depurando, construindo do zero ou mantendo o código de outra pessoa, este guia enfatiza clareza, estabilidade e desempenho como os padrões fundamentais de integrações de alta qualidade.

Esta seção oferece uma visão geral rápida de como configurar um LightScript do ponto de vista de manutenção, com foco em onde os problemas costumam ocorrer e como identificar e corrigir bugs. Começaremos com uma breve apresentação de uma estrutura ideal de LightScript para familiarizá-lo com o código, depois abordaremos a solução de problemas e terminaremos com um FAQ.

A estrutura básica requer um <head>, um <body> e um <script>. Todas as declarações de medidores e controles de usuário vão dentro do <head>. Todas as declarações de canvas pertencem ao <body>. Todo o resto deve ser colocado na seção <script>.

O <head> é uma das partes mais críticas e complexas de qualquer LightScript. Um controle de usuário ou medidor defeituoso aqui pode causar loops de falha ou se desativar juntamente com quaisquer medidores declarados depois dele.

Ao criar medidores, você precisa garantir:

  • Sintaxe perfeita (para evitar falhas e medidores quebrados)
  • Sem nomes de medidores duplicados (duplicatas são sobrescritas)
  • Nenhum medidor ultrapassando os limites da tela (causa falhas e erros)
  • Sem opções faltantes ou extras nos medidores (leva a falhas)
  • Todos os medidores incluem ajustes de resolução (garante comportamento consistente)

Em relação às resoluções, as proporções de tela mais comuns são:

  • 16:9 (3840x2160, 2560x1440, 1920x1080, 1600x900, 1366x768, 1360x768, 1280x720)
  • 16:10 (2560x1600, 1920x1200, 1680x1050, 1440x900, 1280x800)
  • 21:9 (5120x2160, 3440x1440)

Por padrão, usamos a resolução 2560x1440.

Todos os LightScripts devem suportar as proporções 16:9, 16:10 e 21:9. Embora 4:3 não represente uma parcela significativa da nossa base de usuários, ainda deve ser considerada para compatibilidade futura.

Aqui está um exemplo da estrutura de um medidor com múltiplas configurações de resolução:

A localização e o tamanho padrão dos seus medidores se aplicam a todas as outras resoluções dentro da mesma proporção. Por exemplo, se você ajustou originalmente seus medidores para funcionar com 1600x900, esse medidor deve funcionar corretamente em todas as outras resoluções 16:9. No entanto, há exceções. Fortnite tem múltiplas posições de medição diferentes mesmo dentro da mesma proporção, e algumas proporções em si podem ser enganosas. Por exemplo, 1366x768, uma resolução comum em todo o mundo, é frequentemente listada como 16:9 mas não é realmente uma proporção verdadeira de 16:9, o que não é incomum. Da mesma forma, proporções ultrawide como 21:9 raramente correspondem às suas dimensões nominais. Na minha experiência como desenvolvedor de integração, nunca encontrei uma resolução exata de 21:9 apesar de serem rotuladas como tal. Por isso, cada resolução ultrawide precisa ser criada, testada e configurada individualmente.

Todos os ajustes devem ser colocados entre as tags de abertura <meta> e fechamento </meta>; caso contrário, não funcionarão. Se o seu medidor padrão é baseado em 16:9 e se comporta de forma consistente nessas resoluções, não é necessário adicionar ajustes para outras resoluções 16:9. Porém, é obrigatório adicionar entradas para cada resolução em outras proporções (como 16:10 e 21:9), mesmo que a proporção seja consistente.

Por fim, todo medidor, exceto os OCR, requer um intervalo HSL para acionar. Esses intervalos podem ser complicados por fatores como:

  • Elementos de UI transparentes
  • Gradientes em áreas de cor
  • Efeitos de distorção de tela
  • Abertura de menus no jogo
  • Ajustes de UI por resolução
  • Uso de controle vs. teclado
  • Gravação de vídeo, que pode introduzir erros de pixel relacionados à compressão

Instruções básicas sobre HSL e coordenadas normalizadas são abordadas nos nossos docs para desenvolvedores e não serão repetidas aqui. Os testes desses medidores serão discutidos na seção “Identificando Problemas”, mas é importante enfatizar: a quantidade de testes necessária para verificar todos os medidores perfeitamente é calculada como (número de medidores) × (número de ajustes de resolução) × (número de modos de jogo) × (número de personagens jogáveis) × (duração de uma partida média). Isso pode facilmente somar horas de verificação por jogo, especialmente se modos de prática ou outras alternativas não estiverem disponíveis.

MANTENHA SEUS MEDIDORES EFICIENTES, nosso padrão é a perfeição.

A tag <body> é onde o elemento canvas é declarado. Ela deve sempre parecer mais ou menos com o exemplo a seguir. O id real do canvas pode ser alterado se quiser, mas certifique-se de buscá-lo corretamente no script.

Economize tempo e copie-e-cole isso.

Quatro coisas devem acontecer dentro desta tag em cada integração:

  • O canvas é buscado e usado para criar o contexto 2D.
  • O loop de atualização inicial define os valores dos medidores e se rechama indefinidamente para mantê-los.
  • O loop de atualização mantém as variáveis de controle do usuário atualizadas.
  • Os medidores executam suas funções de callback quando estão estáveis.

Já configuramos a estrutura básica do código. O próximo passo é percorrer o loop de execução que aciona efeitos do início ao fim.

  1. A interface do videogame exibe informações na forma de barras coloridas, botões, caixas de texto, etc. O SignalRGB captura esses dados várias vezes por segundo, mas a taxa de captura real depende muito da eficiência do seu código. Para ser claro, um único loop ou variável não declarada pode quebrar todo o seu script, e até mesmo travar o SignalRGB. Pior ainda, é fácil escrever código que tecnicamente funciona, mas é tão ineficiente que captura informações a apenas 1-2 FPS.
  2. Cada medidor declarado no <head> deve ser o menor e mais eficiente possível para reduzir o overhead. Faça seus cálculos cedo e com frequência; um medidor que ocupa 25% da tela nunca é eficiente. Com medidores OCR, capture letras individuais em vez de palavras inteiras. Para barras de vida e mana, monitore apenas os segmentos essenciais. MANTENHA SEUS MEDIDORES O MENOR POSSÍVEL.
  3. Os medidores capturam informações que se atualizam a cada loop.
  4. Anteriormente, abordamos a definição da classe Meter, que armazena dados de medidores e aciona um callback quando o array de informações se torna estável. No topo do seu script, declare todos os Meters em um bloco. Você pode organizá-los ou alfabetizá-los; apenas não os espalhe por milhares de linhas. Eventualmente você precisará ajustar os valores de estabilidade, e é uma perda de tempo tentar lembrar onde os colocou.
  5. Dentro da função update, esses medidores receberão valores da lógica de leitura de tela a cada loop. Sua lógica interna avalia a estabilidade e, quando estável, aciona a função de callback associada.
  6. Essas funções de callback devem ser declaradas no seu script mas fora da função update. Dentro delas, verifique o estado dos valores do seu Meter (value, decreased, increased, diff) e use-os para determinar se deve reproduzir uma animação de efeito. Estruturar seu código dessa forma, em vez de colocar tudo diretamente dentro do loop de atualização, nos permite construir integrações escaláveis.

Agora que você tem a ideia geral, vou percorrer rapidamente um exemplo de loop do mundo real.

  • Estou jogando League of Legends, que envolve as habilidades disponíveis com um destaque amarelo brilhante.
  • A cada loop, o medidor de habilidade específico capta essa cor como um valor de “1” porque passa completamente pelo intervalo HSL do medidor.
  • Esse “1” é passado para a instância Meter vinculada ao medidor de leitura de tela e inserido no array de informações desse Meter.
  • Se todos os valores nesse array forem “1”, é considerado estável e ativará a função de callback de efeito associada. Essa função de callback também seria ativada se todos os valores fossem “0”, ou “.1”, por exemplo; tudo que o Meter verifica é a estabilidade. Uma observação importante aqui é que a função de callback não será continuamente ativada se o Meter estiver constantemente estável no mesmo valor — apenas a estabilidade com um NOVO valor ativará o callback.
  • Uma vez que a função de callback é executada, chegamos a algumas verificações condicionais — neste caso, tudo que precisamos fazer é verificar se o Meter.value é “0”, indicando que uma habilidade foi usada.
  • Como o valor do Meter é “1”, falhamos nessa verificação e não reproduziremos o efeito de habilidade.
  • Alguns segundos depois, ativo a habilidade e o destaque amarelo em torno do botão desaparece.
  • O novo valor do medidor é 0, que é passado para sua classe Meter.
  • Uma vez que a estabilidade é alcançada, o callback é ativado e nossa condição é satisfeita, reproduzindo o efeito de habilidade. A latência depende inteiramente do comprimento do array do Meter, que você define na declaração. Mais comprimento significa mais latência e menos acionamentos falsos, então teste até encontrar um bom equilíbrio.

Os medidores de leitura de tela devem ter nomes simples, claros e descritivos, sempre começando com uma letra minúscula. Nomear um medidor de barra de vida como “healthBar” é excelente. Nomear dois medidores “healthBarRed” e “healthBarGreen” quando rastreiam cores diferentes na mesma área também é ótimo. Mas nomear um medidor pequeno que só aparece durante o efeito de ultimate de um herói como “hrO21_yes” só vai trazer dor e sofrimento para qualquer outra pessoa que tentar corrigir seu código. Descobrir o que um medidor mal nomeado e minúsculo está rastreando pode literalmente levar uma hora olhando para pixels individuais se você tiver azar, então não faça isso.

As instâncias da classe Meter devem começar com maiúscula e terminar com a palavra Meter. Exemplos como “Q_Meter”, “TookDamageMeter” e “TowerDestroyedMeter” são todos perfeitamente adequados. Eles devem ser claramente distinguíveis dos medidores declarados na seção <head>.

As funções de efeito também devem ser nomeadas de forma o mais simples e descritiva possível. Alguns jogos têm centenas dessas funções; outros podem ter menos de dez. Se múltiplos heróis têm habilidades únicas, inclua o nome do herói como prefixo, como “SonaQ”, “ChamberE” ou “AshUlt”. Em League of Legends, por exemplo, existem funções como “DragonEffect”, “TowerEffect” e “Q_Effects”, que contêm múltiplos condicionais e são usadas por vários medidores. Portanto, esse tipo de nomenclatura também ajuda a otimizar para escala.

Não escreva palavras erradas. Se não tiver certeza de como escrever algo, pesquise. Os nomes devem ser claros e legíveis, independentemente de quem está trabalhando no código ou quanto tempo passou. Organizar os nomes em ordem alfabética ajuda na busca rápida, especialmente se você for editar essa seção com frequência. Embora esse nível de organização não seja necessário para o código funcionar, faz uma grande diferença para os nossos desenvolvedores de manutenção.