Plataforma

Um runtime, um protocolo, o jogo como ambiente programável

O W3 Runtime é injetado no jogo original e, na thread do jogo, coleta o mundo inteiro, executa comandos e reporta os resultados. Sua IA só precisa dizer “o que fazer”, conversando com ele por um protocolo de memória compartilhada versionado.

Camadas

A camada de baixo não sabe que a de cima existe

A camada de interface não tem uma única linha de lógica de “atacar ou não”; os cérebros não fazem import uns dos outros e dependem só do SDK. É isso que torna a Arena possível — ela só precisa de “camada de interface + árbitro”, e qualquer cérebro pode se conectar.

Seu agente / Bot
Qualquer modelo, qualquer linguagem
Claude CodeCursorChatGPTQwen localBot em PythonIA de referência
Decisão
import openwar3 · ou gateway WebSocket / JSON · MCP
OpenWar3 SDK
Python · openwar3
Game / BotSnapshot w3worldVia rápida w3fastcombat (cálculo de combate)pathing (caminhos)w3claim (reivindicações)canvasjass (canal JASS)schemes (esquemas)
Interface
Mundo enviado a cada 50 ms · comandos em ~1 frame · recibo para cada um
Protocolo W3P v2
Memória compartilhada · cópia zero · versionado
War3WorldWar3EventsWar3MapWar3TreesWar3Fast (vias de comando)War3Canvas (canvas)
Protocolo
Execução em lote na thread do jogo · 4~8 µs por comando · orçamento de 4 ms por esvaziamento
W3 Runtime
Roda na thread do jogo
Publicador do estado do mundoFluxo de eventosExecutor de comandos semânticosConsultasPermissões e perspectivaCanvas desenhado pelo runtimeChamadas JASSCompatibilidade de versõesSaúde e disjuntores
Runtime
War3.exe 1.27 · jogo original, nenhum arquivo no disco é modificado
Camada de informação em tempo real

O mapa inteiro, a cada 50 ms

O runtime coleta tudo de uma vez na thread do jogo e envia para a memória compartilhada; o cliente lê direto, sem entrar na fila da thread do jogo. Uma coleta leva uma mediana de 0.5 ~ 0.9 ms (100 ~ 120 unidades), e os tempos por etapa ficam sempre registrados no cabeçalho do bloco do mundo.

Jogadores ×16

Ouro, madeira, comida e limite, total coletado, raça

Unidades ×1024

Tipo, dono, coordenadas, vida e mana, ordem atual e alvo, quem está realmente atacando, nível / experiência / pontos de habilidade, visibilidade para cada jogador

Detalhes de unidade ×256

12 habilidades (nível, recarga restante), 8 buffs, 6 espaços de inventário; heróis têm prioridade

Tabela de produção ×128

Treino / pesquisa / construção / melhoria — fila, duração total, tempo decorrido, se está travada

Itens no chão ×256

Tipo, posição, durabilidade; pegar ou usar gera um evento

Árvores ×4096

Posição e vida dos destrutíveis, atualizadas a cada 2 segundos

Mapa

Grade andável / construível em células de 128, área jogável, pontos de início; calculado nos primeiros segundos da partida

Tempo

Relógio do motor, horário do jogo (dia e noite), velocidade, se há partida em andamento

Fluxo de eventos Buffer circular de 8192 entradas, cada uma numerada; se a leitura for lenta demais e houver sobrescrita, o SDK percebe
unit.appearedunit.diedunit.removedunit.damagedorder.changedowner.changedhero.levelupitem.appeareditem.removedspell.castselection.changedmessageplayer.leftgame.startedgame.ended damage · Cada golpe, em nível de motorkilled · Cada golpe, em nível de motor production.done · Inclui os do adversário
Comandos semânticos

O runtime escolhe o caminho

Coletar, recuar, lançar feitiços… tudo é “fazer uma unidade agir”, mas cada um segue um caminho diferente dentro do motor. Essa experiência toda fica no runtime — você diz o que fazer, ele executa com uma receita verificada e, no mesmo frame, lê de volta a ordem antes e depois como recibo.

  • Um lote por envio, executado no mesmo frame
  • Recibo para cada um — código de status + código de motivo do motor + tempo de execução
  • Fila com Shift, pontos de caminho, construção em sequência
  • Consultas — contagem de tecnologia, viabilidade, visibilidade, ouro restante, alvo de ataque do computador
Recibos e códigos de motivo
moveattack_moveattackstopholdpatrolattack_groundgatherrepairbuildbuild_nearbuild_queuetraincancellearncastrallyrevivepick_upuse_itemdrop_itemgive_itemsell_itembuypathcall_to_armspausebatch
Baixa latência

O lento nunca foi cruzar processos

Ler e escrever memória compartilhada leva nanossegundos; ler um snapshot leva ~0.05 ms. O canal antigo era lento porque cada requisição disputava um lock único da máquina e depois esperava o jogo buscar a próxima mensagem (uma vez por frame, 16 ~ 33 ms). 93% do tempo de relógio do cérebro de referência ia nessa espera.

Antigo · canal de controle20 ~ 40 ms / chamada
  1. Disputar um mutex compartilhado pela máquina inteira
  2. Postar uma mensagem para a thread do jogo
  3. Esperar o jogo buscar a próxima mensagem (uma vez por frame)
  4. Esperar o evento de conclusão, liberar o lock

Com 6 processos usando juntos, a vazão travava em ~88 chamadas/s.

Novo · via rápida~1 frame, em lote
  1. Cada cliente tem uma via exclusiva — um escritor, um leitor, sem lock
  2. A execução acontece na distribuição de eventos da thread do jogo (centenas de vezes por segundo); sem envios, o custo é só algumas comparações de inteiros
  3. 16 comandos por envio, todos executados na mesma distribuição; cada esvaziamento tem orçamento de 4 ms
  4. Cada comando tem prazo — depois de sair da pausa, comandos vencidos não são executados

O recibo de cada comando traz o tempo de execução, e o cabeçalho da via registra o comando mais lento e quanto levou o último esvaziamento — dá para ver na hora onde está a lentidão.

FaixaCanalLatênciaQuem usaStatus
0 Snapshot enviado + fluxo de eventos Ler uma cópia leva ~0.4 ms; uma nova a cada 50 ms (ajustável até 16 ms) Todos os Bots Verificado em jogo
1 Via rápida ~1 frame; mediana de 0.06 ms com 6 processos em paralelo, vazão de ~3000 cmd/s Padrão do SDK Verificado em jogo
2 Canal de controle 20 ~ 40 ms Fallback, algumas operações de interface Verificado em jogo
3 Gateway (WebSocket / JSON) Faixa 1 + ~1 ms Qualquer linguagem, páginas de navegador, LLMs (MCP), outra máquina Verificado em jogo

Medido (instância de teste 1.27, 2026-09-23 / 24)

Vazão de comandos
Antes 88
3.000 cmd/s
6 processos em paralelo
Espera mediana em paralelo
Antes 67 ms
0.06 ms
Canal de controle antigo → via rápida
16 comandos
Antes 121 ms
13 ms
Um a um → um lote
8 movimentos
Antes 68~99 ms
6.5~10 ms
with g.batch()
Uma coleta do estado do mundo
Antes 11.8 ms
0.58 ms
Na thread do jogo; reutiliza regiões de memória já confirmadas como legíveis
Um comando no início da partida
Antes 4~10 ms
4~8 µs
O amostrador apontou o log síncrono, que passou a ser assíncrono
Uma rodada do cérebro de referência
Antes 0.15~0.56 s
0.02~0.07 s
Partida de 39 minutos, 0 erros de tarefa
Rodada mais lenta do cérebro de referência
Antes 1.3~3.2 s
0.24~0.42 s
Nenhuma rodada ≥ 2 segundos na partida inteira

Nota de engenharia: nos 3 primeiros minutos, cada comando ficava 1000 vezes mais lento

Depois de registrar o tempo de execução de cada comando, descobrimos que, nos primeiros minutos da partida, do segundo comando de cada lote em diante cada um levava 4 ~ 10 ms, e por volta dos 180 segundos de jogo isso caía de repente para alguns microssegundos. Com o amostrador da thread do jogo embutido no runtime, coletamos 1700 amostras — 93% caíam na própria função de log do runtime, que abria e fechava o arquivo de log de forma síncrona a cada linha escrita, e no início da partida cada ordem do motor gerava uma linha. Com o log de depuração desligado por padrão e a gravação do log passando a ser assíncrona, até os comandos aos 14 segundos de partida levam só 4 ~ 8 µs.

Acreditamos em números medidos, não em palpites.

Permissões e perspectiva

Cada via tem um papel

A verificação de propriedade e o filtro de visão ficam no runtime — a camada de execução do motor não verifica a quem a unidade pertence, então isso só pode ser feito aqui. Duas IAs se enfrentando são duas vias player na mesma partida.

PapelVêPode
player Tudo do próprio lado + inimigos e neutros na visão (modo justo) Só comandar unidades do próprio lado
Jogadores, o seu Bot
observer O mapa inteiro Não dá ordens; pode consultar, controlar a câmera e ler o HUD
Direção, narração, revisão de partidas
Compatibilidade de versões · P4

Não adivinhar, não quebrar

As versões 1.24 ~ 1.28 compartilham a mesma estrutura de motor, ideal para “um runtime + vários profiles”. A 1.29 em diante e o Reforged usam outro motor, sem promessa de compatibilidade automática.

  1. Identificação Lê o recurso de versão e o hash do Game.dll e escolhe o profile
  2. Tabela de símbolos As receitas referenciam nomes de símbolos, não números; cada símbolo traz convenção de chamada e formato dos parâmetros
  3. Assinatura como fallback Em versões desconhecidas, varre pelos bytes do início das funções e só usa se achar uma única correspondência
  4. Autoteste na inicialização Cada símbolo é verificado sem efeitos colaterais; o que não passar é marcado como indisponível
  5. Lista de capacidades Se o SDK vir que uma capacidade está indisponível, a chamada lança um erro claro em vez de retornar 0 em silêncio
Alta disponibilidade

O bug de um Bot não deveria derrubar a partida

É por isso que cada IA roda no próprio processo — um ponteiro nulo dentro do processo do jogo derruba a partida inteira; um processo separado que cai só para aquele lado.

MecanismoComoStatus
Não derrubar o jogo Toda chamada ao jogo tem proteção contra exceções; orçamento de 4 ms por esvaziamento (timer de alta precisão) Pronto
Clientes isolados Uma via e uma cota para cada cliente; um travado não bloqueia os outros Pronto
Vencido não executa Cada comando tem prazo; vencidos são só marcados, sem execução, e não são reenviados ao sair da pausa Pronto
Observável Tempo de execução de cada comando; tempos por etapa de cada coleta no cabeçalho do bloco do mundo Pronto
Reconexão automática O SDK acompanha a troca de partida e de processo e reconecta sozinho Parcial
Disjuntor de capacidades Uma capacidade que falha N vezes seguidas → marcada como indisponível, com evento; as outras seguem normais Planejado
Camada de extensão

Dentro do jogo, faça as suas próprias coisas

Os comandos semânticos deixam a IA operar como um jogador; a camada de extensão muda o que o jogador vê e vivencia — desenhe sua própria interface clicável, chame todas as funções de um autor de mapas. Os dois caminhos se dividem por “é seguro em partidas multijogador ou não”.

Canvas Seguro em multijogador
0.27 ~ 0.34 ms Custo por frame (9 elementos, ~63 frames/s)
  • Caixas de texto, painéis, barras de progresso, imagens, círculos colados ao terreno, rotas com setas
  • Presos a unidades, a coordenadas do mundo ou a posições da tela; fonte chinesa, cantos arredondados, transparência, qualquer cor
  • Desenhado pelo próprio runtime — não cria objetos de jogo nem altera o estado do jogo
  • Uma linha de Python por elemento; também via HTTP ou escrevendo direto na memória compartilhada
  • Botões e cartões de escolha clicáveis, com destaque ao passar o mouse; desenhados abaixo do cursor do mouse, e o jogo não recebe o clique dado neles
Documentação do canvas
Canal JASS Partida solo · ferramentas locais
1291 funções JASS, chamadas direto pelo nome
  • Criar unidades, alterar atributos, efeitos, painéis, diálogos, sons, câmera, névoa de guerra, clima…
  • Console Farsight, linha de comando, HTTP, Python — a mesma forma de escrever scripts
  • Efeitos comuns em uma linha cada — texto flutuante, linhas, círculos de alcance, diálogo com retrato, filtros de tela cheia
  • Em partidas multijogador, só funções de leitura são liberadas, para evitar dessincronização
Documentação do canal JASS
CanvasFunções de tela do JASS
Quem desenha O runtime O próprio jogo
Multijogador Seguro: desenha só na sua tela Só em partida solo
Estilo Livre: fontes, cantos arredondados, transparência, imagens Estilo nativo do jogo
Acompanha Unidade / coordenadas do mundo / posição da tela Depende da função
Custo 0.2 ~ 0.35 ms por frame ~13 ms por chamada
1291 funções, por finalidade
Efeitos visuais 80 Painéis de interface 146 Câmera 44 Sons e música 50 Névoa e visão 25 Unidades 161 Itens 63 Heróis 32 Jogadores / alianças / recursos 71 Gatilhos / timers 62 Terreno / clima 45 Fluxo do jogo 57

O que o jogador fez vai direto para o fluxo de eventos

O runtime informa diretamente as ações do jogador: em qual botão desenhado clicou, que tecla de atalho apertou, onde clicou no chão, quem selecionou, que feitiço lançou, o que digitou no chat. Os eventos de gatilho do próprio jogo (entrada em regiões, botões de diálogo, setas do teclado) ainda podem ser captados com um gatilho vazio: só registrar o evento, sem condições nem ações, e contar quantas vezes ele foi executado.