- Foi descoberto um bug estranho no começo de Half-Life 2 em que a porta não abre e o progresso fica travado
- A causa é que, ao abrir, a porta colide com a ponta do pé do guarda que está parado dentro dela, fazendo com que ela feche de novo e fique trancada
- A mesma colisão já existia no código original, mas o resultado mudou por causa da diferença de precisão entre os cálculos de ponto flutuante x87 de 2004 e os cálculos SSE de 2013
- No ambiente x87, uma rotação minúscula empurra levemente o pé e resolve a colisão, mas no SSE a rotação não é suficiente e a porta acaba fechando
- Este caso é um exemplo clássico de como a precisão de ponto flutuante e as diferenças de compilador afetam o comportamento real de um jogo
Bug descoberto durante o processo de portar Half-Life 2 para VR
- Em 2013, durante um experimento da Valve para portar Team Fortress 2 para VR, Half-Life 2 e Portal 1, que usam o mesmo motor, também passaram a funcionar em VR
- Portal 1 causava tanta tontura em VR por causa da distorção de perspectiva que era praticamente injogável
- Half-Life 2 funcionava relativamente bem, e cenas como a do barco, empilhar caixas e o combate contra manhacks ganhavam mais imersão em VR
- Durante os testes, um desenvolvedor jogou o game inteiro em VR do começo ao fim e encontrou um estado sem progressão possível na cena inicial da estação de trem
Análise da causa da porta não abrir
- No roteiro original, o guarda (na verdade, Barney) bate na porta, diz “entre” e, quando o jogador entra na sala, a próxima sequência de script começa
- Porém, na situação com bug, a porta fica chacoalhando, trava e se fecha completamente, enquanto o guarda continua apontando para ela e o jogador fica preso
- Mesmo recompilando o código-fonte original de Half-Life 2, o mesmo problema acontecia, gerando confusão por parecer um bug surgido ao voltar no tempo
Causa raiz: mudança na forma de cálculo de ponto flutuante
- Quando Half-Life 2 foi lançado em 2004, usava o conjunto de instruções matemáticas x87, com uma estrutura em que se misturavam precisões de 32, 64 e 80 bits
- Nas builds a partir de 2013, o conjunto de instruções SSE passou a ser usado por padrão, aplicando precisão claramente limitada a 32 ou 64 bits
- Nos dois ambientes, a porta e a ponta do pé do guarda colidem, mas o resultado muda por causa de pequenas diferenças de cálculo na engine de física
- No x87, na colisão o guarda gira só um pouquinho, o pé sai da frente da porta e ela abre
- No SSE, a rotação fica ligeiramente menor, o pé continua encostando e a porta volta a fechar e trancar
Correção e solução
- Depois de identificar o problema, ele foi resolvido com uma correção simples: mover o guarda cerca de 1 mm para trás
- O processo de depuração consumiu bastante tempo, incluindo reaprender a usar ferramentas antigas
- Este caso mostra como diferenças de precisão e mudanças nas configurações do compilador podem alterar o comportamento de código antigo
Reação da comunidade
- Desenvolvedores concordaram com a frase: “o problema é sempre a precisão de ponto flutuante”
- Alguns citaram casos parecidos de mudanças no cálculo de colisão nos remakes de Sonic 1, 2 e 3
- Junto da lição de que “o código é o mesmo, mas o compilador é diferente”, o caso foi visto como um lembrete de como é difícil manter código legado
- Outros desenvolvedores também relacionaram isso ao motivo de jogos como Fallout 4 serem projetados para impedir que NPCs atravessem portas
- No geral, houve muitas reações dizendo que esta era “uma das histórias de bug mais interessantes”
1 comentários
Comentários no Hacker News
Na época em que eu trabalhava com desenvolvimento de jogos, lembro que havia uma falha de asserção causada por erro de cálculo da FPU que só acontecia em certos PCs
A causa era um software de entrada por escrita manual que injetava uma DLL em todos os processos e fazia reset do modo da FPU para o valor padrão
No fim, movemos o código de configuração da FPU da etapa de inicialização para o loop de eventos, evitando a interferência de DLLs de terceiros
Um dos meus objetivos é fazer com que a Valve use Nix
Acho que isso vai ficar ainda mais atraente com o suporte a Windows em andamento
Assim, seria possível reproduzir completamente não só o código-fonte original, mas também o toolchain e as dependências da época, o que deve facilitar muito encontrar a causa raiz de bugs como esse
Isso me faz lembrar do meme “DOOR STUCK”
Vídeo relacionado
Fico me perguntando se o “Half-Life 2 VR beta” é realmente jogável
Se for, por que eu não sabia disso? Se não for, por que ainda não é?
Também quero muito experimentar Portal VR. Dizem que dá muito enjoo, mas eu sou imune a motion sickness em VR, então valeria a pena tentar
É tão bem feito que me fez rejogar HL2 depois de muito tempo
É comum que alguns cálculos quebrem na transição de x87 para SSE
Isso também aconteceu em TF2: na build para Linux usavam SSE, então o cálculo de munição ficava um pouco diferente
Caixas pequenas davam +40 ou +41, e isso variava conforme o SO do servidor
Era divertido descobrir qual era o sistema operacional cada vez que eu entrava em um servidor novo
Se só trocar de x87 para SSE já quebra o jogo, é impressionante como a tradução de x86 para ARM funciona tão bem
Ela usa registradores de 80 bits e tem mais precisão, mas se comporta de forma estranha, como perder precisão ao fazer spill para memória
Já passei por um bug de precisão parecido ao depurar um sintetizador por software
A simulação de um circuito RC precisava se aproximar de 0 para mudar de estado, mas em certos CPUs os valores denormal não eram flushed, então a condição nunca era satisfeita
No fim, ajustei o limiar de forma aproximada para algo como 0.7 e 0.01, e aí funcionou bem em todas as plataformas
Falando em meta, se eu fosse criar um clone do Twitter, colocaria uma função para banir imediatamente quem tentasse blogar em vários parágrafos