ESPAÇO PUBLICITÁRIO DISPONÍVEL · FALE CONOSCO

Arquitetura de modding na Unity: BepInEx em Mono versus IL2CPP, ganchos do Harmony e injeção de assemblies

365Finds Editorial
11.430 artigos Wiki catalogados

Use o 365 Wiki com sua IA

Copie o prompt abaixo, cole na IA que você já usa e faça sua pergunta.

Baixar o Skill completo

Experimente primeiro com o prompt. Se você usa o 365 Wiki com frequência, instale o Skill completo do 365Wiki para não precisar colá-lo novamente. Se não usa uma IA específica, as versões web do Gemini ou Microsoft Copilot também servem.

Introdução: A mecânica do modding no ecossistema Unity

O motor de jogo Unity sustenta uma fração maciça da produção contemporânea de jogos para PC, desde sucessos de sobrevivência como Valheim e Lethal Company até simuladores complexos como Cities: Skylines II e Dyson Sphere Program. Ao contrário de engines proprietárias baseadas em arquivos binários monolíticos ou no sistema de registros declarativos da Bethesda, os projetos desenvolvidos na Unity fundamentam-se no ecossistema de software .NET e C#.

Modificar um jogo feito na Unity raramente exige a substituição destrutiva de arquivos de recursos compactados no disco. Em vez disso, o modding moderno na Unity opera por meio de injeção dinâmica de código em tempo de execução e interceptação de métodos na memória. No centro dessa arquitetura estão o BepInEx (Bepis Injector Extensible), um injetor e carregador de plugins de código aberto, e a biblioteca Harmony, desenvolvida por Andreas Pardeike.

No entanto, jogadores e criadores de modificações deparam-se frequentemente com incompatibilidades críticas ao tentar aplicar mods em diferentes títulos. A origem dessa complexidade reside no modelo de compilação da Unity: a divisão arquitetural profunda entre o compilador clássico Mono e o compilador antecipado IL2CPP (Intermediate Language to C++). Compreender a mecânica interna do BepInEx e do Harmony ao lidar com essas duas infraestruturas é fundamental para solucionar travamentos, ganchos inoperantes e conflitos de carregamento.

A divisão de backends de script: arquitetura Mono vs. IL2CPP

Ao exportar e compilar um jogo na Unity, o desenvolvedor escolhe obrigatoriamente um de dois destinos de compilação de scripts:

[Código-fonte C#: Scripts do Jogo]
               │
               ▼
[Compilador C# Roslyn / Unity] ---> Common Intermediate Language (Bytecode CIL)
               │
               ├─────────────────────────────────────────┐
               ▼                                         ▼
      [Caminho do Backend Mono]                [Caminho do Backend IL2CPP]
- Empacota CIL em assemblies gerenciados     - Transpilador IL2CPP converte CIL em C++
- Arquivo principal: Assembly-CSharp.dll     - Compilador C++ gera GameAssembly.dll
- Executado via Máquina Virtual JIT Mono     - Metadados extraídos para global-metadata.dat
- Reflexão completa, fácil descompilação     - Código de máquina puro, sem CLR/JIT nativo

O backend de scripts Mono

Nos jogos compilados com Mono, toda a lógica de jogo, scripts de inteligência artificial e entidades são empacotados em assemblies gerenciados .NET, principalmente em Managed/Assembly-CSharp.dll.

O backend de scripts IL2CPP

Nos jogos baseados em IL2CPP, o fluxo de compilação segue uma rota drasticamente distinta:

A arquitetura de inicialização do BepInEx

Para contornar a ausência de um ponto de entrada oficial para scripts externos, o BepInEx utiliza uma técnica conhecida como sequestro de proxy de DLL (DLL proxy hijacking).

A cadeia de injeção Doorstop

No ecossistema Windows, os executáveis priorizam bibliotecas de vínculo dinâmico (DLLs) localizadas no próprio diretório de trabalho antes de consultar os diretórios do sistema operacional (C:\Windows\System32). O BepInEx aproveita essa prioridade:

  1. A DLL de proxy: O BepInEx instala uma biblioteca de fachada no diretório do jogo—geralmente winhttp.dll, version.dll ou doorstop.dll.
  2. Interceptação de execução: Quando o carregador do sistema operacional inicializa o executável do jogo, ele carrega a winhttp.dll local em vez da biblioteca oficial do Windows.
  3. Inicialização do runtime: A DLL proxy executa o Unity Doorstop, que localiza e carrega imediatamente na memória as bibliotecas BepInEx.Preloader.dll e BepInEx.Core.dll antes que os procedimentos de inicialização da própria Unity assumam o controle.
  4. Descoberta de plugins: Com o ambiente configurado, o BepInEx abre um console de depuração (se configurado), inicializa canais de log e faz a varredura da pasta BepInEx/plugins/ em busca de mods compatíveis.

BepInEx 5 vs. BepInEx 6: A ponte de interoperabilidade IL2CPP

Harmony: interceptação e modificação dinâmica de métodos em memória

Após a inicialização do BepInEx, os mods utilizam a biblioteca Harmony para alterar o comportamento do jogo sem modificar nenhum byte dos arquivos originais no disco. O Harmony atua reescrevendo em tempo real os prólogos dos métodos compilados na memória JIT.

Os quatro tipos principais de ganchos do Harmony

[Chamada do Método: ex. PlayerController.TakeDamage(float amount)]
           │
           ▼
[Gancho Prefix do Harmony] ---> Retorna true (continua) OU Retorna false (anula original)
           │
           ▼
[Execução do Método Original: Cálculo e dedução de vida]
           │
           ▼
[Gancho Postfix do Harmony] ---> Lê/Altera o valor retornado (__result) ou estado
           │
           ▼
[Gancho Finalizer do Harmony] ---> Captura exceções não tratadas e evita fechamento do jogo
  1. Prefix ([HarmonyPrefix]):
    • É disparado imediatamente antes da execução do método original do jogo.
    • Pode inspecionar e alterar parâmetros de entrada (por exemplo, modificar o valor de dano float amount antes do cálculo).
    • Permite cancelar a execução do código original: se o Prefix retornar false, o método nativo do jogo é completamente ignorado.
  2. Postfix ([HarmonyPostfix]):
    • É executado logo após o término do método original.
    • Permite consultar e alterar o valor de retorno por meio do parâmetro especial ref __result.
    • É o mecanismo ideal para acionar eventos secundários (como conceder uma conquista após a conclusão de uma receita de criação).
  3. Transpiler ([HarmonyTranspiler]):
    • Representa o tipo de gancho de maior precisão e complexidade. Intercepta o bytecode CIL bruto do método como uma sequência enumerável de instruções (IEnumerable de CodeInstruction) antes da compilação JIT.
    • Permite adicionar, remover ou substituir instruções operacionais específicas (como trocar uma instrução de constante ldc.i4.0 por ldc.i4.1 ou alterar ramificações condicionais).
  4. Finalizer ([HarmonyFinalizer]):
    • Funciona como um invólucro de proteção dinâmico try/finally em torno do método manipulado. Ele captura e neutraliza exceções inesperadas, impedindo que bugs internos de um mod causem o encerramento forçado do jogo para o desktop.

Matriz de diagnóstico: falhas comuns no modding de Unity

Caso suas modificações não carreguem ou causem travamentos espontâneos, verifique os sintomas a partir desta matriz diagnóstica de arquitetura:

Sintoma de FalhaCausa Raiz EstruturalIndicador de DiagnósticoProcedimento Corretivo
Console ausente / Mods ignoradosDLL de proxy bloqueada ou ignorada pelo carregadorArquivo BepInEx/LogOutput.log não é geradoConfirmar presença de winhttp.dll na raiz; verificar permissões da pasta
Travamento instantâneo no lançamento (IL2CPP)Tentativa de utilizar BepInEx 5 em jogo IL2CPPGameAssembly.dll existe na raiz, mas BepInEx 5 está instaladoRemover instalação antiga e instalar BepInEx 6 x64 específico para IL2CPP
Cache de interop defasadoAtualização do jogo sem regeneração dos assembliesExceção TypeLoadException ou MissingMethodException no logExcluir a pasta BepInEx/interop/ para forçar reconstrução dos wrappers
Conflito entre ganchos PrefixMúltiplos mods interceptando mesmo método com retorno falseMod A funciona normalmente, Mod B tem funções inoperantesReordenar prioridade de plugins; evitar anulações agressivas no Prefix
Bloqueio por sistema antitrapaçaEAC ou BattlEye impedindo injeção da DLL proxyJogo encerra com erro de arquivo não confiávelExecutar em modo offline ou utilizar parâmetros oficiais de inicialização modificada

Ao montar ordens personalizadas de carregamento de mods, diagnosticar colisões entre assemblies ou desenvolver extensões em C# para diferentes motores de jogo, recorrer aos guias técnicos e arquiteturais do 365Finds garante que sua bancada de testes respeite a integridade dos binários nativos. Tratar o modding na Unity a partir do gerenciamento de memória, injeção de proxy e manipulação não destrutiva de bytecode preserva a estabilidade das suas instalações mesmo após atualizações de versão.

Referências