Technical Design Document · Systems Architecture

VORGS
LAB SIMULATOR

Documentação técnica abrangendo arquitetura de sistemas, padrões de código, pipeline de renderização, C# Job System com Burst Compiler e infraestrutura cloud do projeto Vorgs Lab Simulator.

Engine Unity 6 LTS
Linguagem C#
Plataformas PC · Mobile
Pipeline URP
Arquitetura OOP + Job System (Burst)
Versão do Doc 0.1 · DRAFT
04

Tech Stack

Todas as tecnologias, bibliotecas e pacotes utilizados no projeto

CategoriaTecnologiaVersão / NotaUso
EngineUnity6.x LTSEngine principal, build pipeline, Editor
LinguagemC# (.NET).NET 9 / C# 13Toda a lógica do jogo
Render PipelineUniversal Render Pipeline (URP)17.xRenderização PC e Mobile com custom passes
Job SystemC# Job System + Burst CompilerNativo Unity 6Cálculos de tradução genética e morfogênese (L-System) de alta performance
DI FrameworkVContainerlatestInjeção de dependência em toda a camada OOP
Reactive ExtensionsR3latestStreams reativos para binding de UI e eventos de domínio
Async/AwaitUniTask2.xOperações assíncronas (I/O, rede, animações)
UI SystemUI Toolkit (UXML/USS)Nativo Unity 6Toda a interface do usuário (in-game e editor)
Procedural AnimationUnity Animation RiggingNativo / PackageCinemática Inversa (IK) para movimentação procedural do braço mecânico na visão micro e feedback de interações
Node Graph EditorNodeGraphProcessoropen-sourceEditor de vias metabólicas, configuração de genomas
SerializaçãoNewtonsoft Json.NET13.xSaves, genomas, configurações exportadas
Backend / CloudFirebase (Firestore + Functions + Auth)SDK UnityCaçadas selvagens (RNG server-side), registro de patentes
Design de Templates UIOpenDesign (open-source)Prototipação de UI exportada para UXML/USS
TestesUnity Test Framework + NUnitNativoTestes unitários e de integração da simulação genética
CI/CDGitHub Actions + GameCIBuild automatizado, testes, deploy
05

Arquitetura do Sistema

Camadas de abstração, fluxo de dados e separação de responsabilidades

Diagrama de Camadas

O sistema é dividido em 4 camadas verticais com dependência unidirecional: camadas superiores dependem das inferiores, nunca o contrário. A comunicação entre camadas ocorre via interfaces abstratas injetadas pelo VContainer.

Presentation
UI Toolkit Views R3 Bindings ScreenControllers HUD / Overlays Lab Camera Aquarium Camera
⬇ VContainer · DI · Interfaces
Domain (OOP)
GeneticsService OrganismService EconomyService ContractService PatentService MutationService MetabolicGraphService
⬇ C# Job System · Native Collections · Burst
Job System
NativeArrays IJobParallelFor BurstCompiler TranslationJob GrowthLSystemJob
⬇ Repository Pattern · Async I/O
Infrastructure
JsonSaveRepository FirebaseRepository ScriptableObject Configs EventBus (R3 Subjects) AssetLoader (Addressables)
⚡ Regra de Ouro das Dependências Nenhuma classe das camadas Domain/Jobs/Infrastructure importa namespaces de UnityEngine.UI, UnityEngine.UIElements ou possui referências a MonoBehaviour. Toda interação com a cena passa pela camada Presentation via thin wrappers.

Estrutura de Pastas do Projeto

Assets/ └── _Project/ ← tudo dentro de _Project (evita conflito com packages) ├── Art/ │ ├── Materials/ ← URP Materials + ShaderGraph │ ├── Shaders/ ← custom ShaderGraph (.shadergraph) │ ├── Textures/ │ ├── VFX/ ← VFX Graph (.vfx) │ └── Animations/ ├── Audio/ ├── Config/ ← ScriptableObjects (dados de config) │ ├── Genetics/ │ ├── Organisms/ │ ├── Biomes/ │ └── Economy/ ├── Prefabs/ ├── Scenes/ ├── UI/ ← UXML templates + USS stylesheets │ ├── Screens/ │ ├── Components/ │ └── Themes/ └── Scripts/ ├── Core/ ← Lógica de domínio — Pure C# puro, zero UnityEngine │ ├── Genetics/ │ │ ├── Models/ ← Genome, Codon, Protein, MetabolicPath │ │ ├── Services/ ← GeneticsService, TranslationService │ │ └── Interfaces/ ← IGeneticsService, ITranslationService │ ├── Organisms/ │ │ ├── Models/ ← Organism, Phenotype, GrowthParameters │ │ ├── Services/ │ │ └── Interfaces/ │ ├── Economy/ │ ├── Contracts/ │ └── Shared/ ← ValueObjects, Enums, Extensions, Result<T> ├── Jobs/ ← C# Job System + Burst — alta performance │ ├── Translation/ ← TranslateGenomeJob (IJobParallelFor) │ ├── Growth/ ← GrowthLSystemJob [BurstCompile] │ └── Shared/ ← NativeArray helpers, JobScheduler ├── Infrastructure/ │ ├── Persistence/ ← JsonSaveRepository, ISaveRepository │ ├── Cloud/ ← FirebaseRepository, ICloudRepository │ └── EventBus/ ← R3 Subject<T> channels globais ├── Presentation/ │ ├── Lab/ │ │ ├── LabScreenController.cs │ │ └── LabScreenView.cs │ ├── Aquarium/ │ ├── Sequencer/ │ └── Shared/ ← BaseView, BaseController, ViewModelBase ├── Runtime/ ← MonoBehaviours APENAS para interagir com a cena │ ├── Lab/ ← LabLayoutMonoBehaviour.cs │ ├── Aquarium/ ← OrganismRendererMonoBehaviour.cs │ └── Camera/ ← CameraRigMonoBehaviour.cs └── Editor/ ← Custom Unity Editor Tools ├── NodeGraphs/ ← NodeGraphProcessor graphs (vias metabólicas, DNA) ├── Inspectors/ ← Custom PropertyDrawers e Custom Inspectors └── Windows/ ← EditorWindows customizadas
06

Padrões de Código

SOLID, regras de MonoBehaviour e convenções do projeto

Princípios SOLID Aplicados

S
Single Responsibility
Cada classe tem uma única razão para mudar. GeneticsService só traduz genes. MutationService só aplica mutações. Nunca os dois na mesma classe.
O
Open/Closed
Novos biomas, vias metabólicas e contratos são adicionados via ScriptableObjects e interfaces, sem modificar código existente. Extensão por dados, não por herança.
L
Liskov Substitution
Implementações de IOrganismRenderer (3D, 2D fallback, debug) são totalmente intercambiáveis. Testes usam mocks que substituem implementações reais sem quebrar contratos.
I
Interface Segregation
Interfaces são finas e focadas: IReadable<T>, IWritable<T>, IDeletable em vez de um IRepository<T> monolítico com métodos não usados.
D
Dependency Inversion
Toda dependência é injetada via VContainer. Nenhuma classe instancia suas dependências com new nem usa FindObjectOfType. Acoplamento apenas com abstrações.

Regras de MonoBehaviour

🚫 Proibido em MonoBehaviours Lógica de negócio, cálculos genéticos, acesso a repositórios, estado de UI, regras de contrato, qualquer serviço injetável. MonoBehaviours NÃO conhecem a camada de domínio diretamente — recebem comandos e disparam eventos.
✅ Permitido em MonoBehaviours Interagir com Transform, Renderer, Collider, Animator, Input do Unity. São thin wrappers que delegam para serviços de domínio. Máximo de 50 linhas como regra prática. Nenhum campo público sem [SerializeField].
C# Runtime/Aquarium/OrganismRendererMono.cs
// ✅ BOM — MonoBehaviour apenas como thin wrapper de rendering
public sealed class OrganismRendererMono : MonoBehaviour
{
    [SerializeField] private Renderer _renderer;
    [SerializeField] private Transform _root;

    private IOrganismRenderService _renderService;  // injetado via VContainer
    private CompositeDisposable _disposables = new();

    [Inject]
    public void Construct(IOrganismRenderService renderService)
        => _renderService = renderService;

    private void Start()
    {
        _renderService.OnPhenotypeChanged
            .Subscribe(ApplyPhenotype)
            .AddTo(_disposables);
    }

    private void ApplyPhenotype(Phenotype phenotype)
    {
        // apenas manipula componentes Unity — zero lógica de domínio aqui
        _renderer.material.SetColor("_BaseColor", phenotype.Color);
        _renderer.material.SetFloat("_EmissionIntensity", phenotype.LightEmission);
        _root.localScale = Vector3.one * phenotype.Scale;
    }

    private void OnDestroy() => _disposables.Dispose();
}

Outros Padrões Adotados

PadrãoOnde é UsadoBenefício
Result<T, TError>Retorno de todos os serviços de domínioSem exceções para flow control. Erros são valores explícitos.
RepositoryPersistência e CloudTroca de backend (JSON ↔ Firebase) sem alterar domínio
Command + Undo StackEdições de DNA no SequenciadorCtrl+Z nativo para todas as operações genéticas
FactoryCriação de Organismos e AquáriosLógica de construção separada, testável isoladamente
StrategyAlgoritmos de mutação e tradução genéticaDiferentes estratégias (Random, Directed, Frameshift) intercambiáveis
Observer via R3Toda comunicação entre camadasDesacoplamento total — publishers não conhecem subscribers
Spec / ValueObjectModelos de Genoma, Fenótipo, ContratoImutabilidade garante consistência nos Jobs paralelos e na simulação
07

Processamento de Alta Performance (Jobs)

Simulação genética de alta performance com Burst Compiler e Job System

Para evitar a complexidade do Unity ECS (DOTS) e as pontes custosas entre dados, o processamento de alto volume foi simplificado. A arquitetura de domínio mantém 100% da lógica em OOP tradicional e utiliza ativamente o C# Job System nativo com Burst Compiler apenas sob demanda para os pesados cálculos numéricos: tradução em massa de DNA, cálculos de mutação e morfogênese (L-System).

C# Job System & Burst Compiler

A separação foca no processamento orientado a dados. Classes do domínio (OOP) injetam arrays nativos nos jobs estruturados, agendam o processamento paralelo e colhem os resultados.

C# Core/Jobs/TranslateGenomeJob.cs
[BurstCompile]
public struct TranslateGenomeJob : IJobParallelFor
{
    [ReadOnly] public NativeArray<Nucleotide> Genome;
    public NativeArray<AminoAcid> Proteins;

    public void Execute(int index)
    {
        // Cálculo direto e otimizado com Burst, sem ECS overhead
        var codon = GetCodonAt(index);
        Proteins[index] = Translate(codon);
    }
}
08

Camada de Domínio (OOP)

Serviços de negócio, modelos imutáveis e interfaces abstratas

A camada de domínio é composta inteiramente de Pure C# classes — sem nenhuma dependência de UnityEngine. Isso garante testabilidade total com NUnit puro, reutilização em ambos os contextos (Unity e testes headless) e separação de concerns inviolável.

C# Core/Genetics/Models/Genome.cs
// ValueObject imutável — representa o estado do genoma no domínio OOP
public sealed record Genome
{
    public string    Id          { get; }
    public string    Nucleotides { get; }  // ex: "ATGCGATCGATCG..."
    public BiomeType OriginBiome { get; }
    public DateTime  CreatedAt   { get; }

    public uint ComputeChecksum()
        => Crc32.Compute(Encoding.ASCII.GetBytes(Nucleotides));

    public Genome WithMutation(int position, Nucleotide nucleotide)
        => this with { Nucleotides = ApplySubstitution(Nucleotides, position, nucleotide) };
}

// Result<T> — sem exceções para flow control
public readonly struct Result<T>
{
    public T       Value      { get; }
    public string  Error      { get; }
    public bool    IsSuccess  { get; }

    public static Result<T> Ok(T value) => new(true, value, null);
    public static Result<T> Fail(string error) => new(false, default, error);
}
C# Core/Genetics/Services/GeneticsService.cs
public sealed class GeneticsService : IGeneticsService
{
    private readonly ITranslationService  _translator;
    private readonly IMetabolicGraph      _metabolicGraph;

    public GeneticsService(   // injeção de dependência via VContainer
        ITranslationService translator,
        IMetabolicGraph     metabolicGraph)
    {
        _translator     = translator;
        _metabolicGraph = metabolicGraph;
    }

    public Result<Phenotype> ExpressGenome(Genome genome)
    {
        var proteins = _translator.Translate(genome);
        if (proteins.IsSuccess == false)
            return Result<Phenotype>.Fail(proteins.Error);

        var activePathways = _metabolicGraph.Resolve(proteins.Value);
        var phenotype      = PhenotypeBuilder.Build(activePathways);

        return Result<Phenotype>.Ok(phenotype);
    }
}
08A

Visual Rendering & Custom Shaders

Pipeline de renderização URP, custom shaders e rigging procedimental dos braços mecânicos

Dado o nível de fidelidade científica e o realismo estéril estilizado das referências visuais, o render pipeline (URP) utiliza passes de renderização customizados (Custom Render Passes) e shaders altamente otimizados para representar fluidos, vidros reflexivos e tecidos vivos.

Shaders Customizados (ShaderGraph URP)

1. Biorreator Glass Shader
Shader de dupla face (double-sided) com cálculo de refração física baseado no índice de refração do gel. Inclui especularidade metálica na base circular, reflexos de fresnel dinâmicos e condensação translúcida.
2. Nutritive Gel / Fluid Shader
Simulação volumétrica com absorção de luz cromática dependendo do bioma (fluidos rosa, azul ou dourado). Integra caustics de luz subaquáticas projetadas no fundo do cilindro e nas bancadas metálicas, além de um sistema de partículas leves suspensas para detritos orgânicos.
3. Vorg Organic SSS Shader
Shader para simular o tecido carnudo e translúcido do organismo disforme (corais e esponjas). Utiliza Subsurface Scattering (SSS) nativo do URP e expõe mapas de emissão bioluminescente que são modulados em tempo de execução via scripts (R3) baseados nas taxas metabólicas ativas.

Rigging Procedimental do Braço Robótico

Para evitar as limitações de animações baseadas em keyframes e permitir interações físicas precisas em qualquer ponto do aquário (independentemente de onde o organismo L-System cresça), o braço robótico é animado proceduralmente usando o pacote Unity Animation Rigging.

C# Runtime/Aquarium/RoboticArmMono.cs
// Rigging procedimental com cinemática inversa (IK) para feedback visual
public sealed class RoboticArmMono : MonoBehaviour
{
    [SerializeField] private TwoBoneIKConstraint _armConstraint;
    [SerializeField] private Transform _effectorTarget;
    [SerializeField] private ParticleSystem _injectorMist;
    [SerializeField] private LineRenderer _laserRenderer;

    public async UniTask PerformInjectionAsync(Vector3 fluidPosition, CancellationToken ct)
    {
        // Move proceduralmente a ponta da agulha até a superfície da água
        await MoveTargetToAsync(fluidPosition, 1.5f, ct);
        _injectorMist.Play();
        await UniTask.Delay(1000, cancellationToken: ct);
        await RetractArmAsync(ct);
    }

    public async UniTask PerformRadiationAsync(Vector3 targetPosition, CancellationToken ct)
    {
        await MoveTargetToAsync(targetPosition + Vector3.up * 0.5f, 1.0f, ct);
        _laserRenderer.enabled = true;
        // Ativa feixe UV e partículas de radiação
        await UniTask.Delay(2000, cancellationToken: ct);
        _laserRenderer.enabled = false;
        await RetractArmAsync(ct);
    }

    private async UniTask MoveTargetToAsync(Vector3 pos, float duration, CancellationToken ct) { /* Lerp do _effectorTarget.position */ }
    private async UniTask RetractArmAsync(CancellationToken ct) { /* Retorna _effectorTarget à pose inicial */ }
}

Transição Focal e Foco da Câmera

O CameraRigMonoBehaviour gerencia a transição cinemática entre a visão macro (isométrica) e a visão micro focada (foco no aquário ou no equipamento modular). O pipeline de pós-processamento ativa um efeito de Depth of Field (DoF) baseado em Bokeh para isolar o objeto focado e desfocar o cenário do laboratório ao fundo, evitando fadiga visual e reforçando o realismo de câmera microscópica/macroscópica.

09

Arquitetura de UI

UI Toolkit + R3 + VContainer — MVC com View completamente isolada

A UI segue o padrão Controller → ViewModel → View onde a View é 100% passiva — ela só reage a Observables e nunca acessa serviços de domínio diretamente. O R3 é o único canal de comunicação entre Controller/ViewModel e View.

Fluxo de Dados na UI

USER
Input / Evento
VIEW
Captura (UI Toolkit)
CTRL
ScreenController
SVC
Domain Service
VM
ViewModel (R3)
VIEW
Render (binding)
C# Presentation/Sequencer/SequencerViewModel.cs
public sealed class SequencerViewModel : IDisposable
{
    // Observable properties — a View se subscreve, nunca puxa
    public ReadOnlyReactiveProperty<string> NucleotideSequence { get; }
    public ReadOnlyReactiveProperty<bool>   IsSequencing       { get; }
    public Observable<ProteinData>          OnProteinDiscovered { get; }

    private readonly ReactiveProperty<string> _sequence    = new();
    private readonly ReactiveProperty<bool>   _isSequencing = new(false);
    private readonly Subject<ProteinData>     _proteinFound = new();
    private readonly CompositeDisposable     _disposables  = new();

    public SequencerViewModel(IGeneticsService genetics, Genome target)
    {
        NucleotideSequence = _sequence.ToReadOnlyReactiveProperty();
        IsSequencing       = _isSequencing.ToReadOnlyReactiveProperty();
        OnProteinDiscovered = _proteinFound;

        _sequence.Value = target.Nucleotides;
    }

    public async UniTaskVoid SequenceAsync(Genome genome, CancellationToken ct)
    {
        _isSequencing.Value = true;
        // ... lógica de sequenciamento com delay por upgrade de equipamento
        _isSequencing.Value = false;
    }

    public void Dispose() => _disposables.Dispose();
}
C# Presentation/Sequencer/SequencerView.cs
// View — 100% passiva, zero lógica de negócio, zero dependências de domínio
public sealed class SequencerView : IDisposable
{
    private readonly Label               _sequenceLabel;
    private readonly ProgressBar         _progressBar;
    private readonly CompositeDisposable _disposables = new();

    public SequencerView(VisualElement root)
    {
        _sequenceLabel = root.Q<Label>("sequence-label");
        _progressBar   = root.Q<ProgressBar>("progress-bar");
    }

    public void Bind(SequencerViewModel vm)
    {
        vm.NucleotideSequence
            .Subscribe(seq => _sequenceLabel.text = seq)
            .AddTo(_disposables);

        vm.IsSequencing
            .Subscribe(active => _progressBar.SetVisible(active))
            .AddTo(_disposables);

        vm.OnProteinDiscovered
            .Subscribe(PlayDiscoveryAnimation)
            .AddTo(_disposables);
    }

    private void PlayDiscoveryAnimation(ProteinData p) { /* USS animation class toggle */ }

    public void Dispose() => _disposables.Dispose();
}

VContainer — Injeção de Dependência

Todo o grafo de dependências é registrado em LifetimeScopes hierárquicos. Cada cena (Lab, Aquário, Sequenciador) tem seu próprio escopo, herdando os serviços globais do AppScope.

C# Infrastructure/DI/AppScope.cs
public sealed class AppScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        // ── Infrastructure ──────────────────────────────────────────
        builder.Register<ISaveRepository, JsonSaveRepository>(Lifetime.Singleton);
        builder.Register<ICloudRepository, FirebaseRepository>(Lifetime.Singleton);
        builder.Register<IEventBus, R3EventBus>(Lifetime.Singleton);

        // ── ECS Bridge ───────────────────────────────────────────────
        builder.Register<IGenomeBridge, GenomeBridge>(Lifetime.Singleton);

        // ── Domain Services ──────────────────────────────────────────
        builder.Register<ITranslationService, CodonTranslationService>(Lifetime.Singleton);
        builder.Register<IGeneticsService, GeneticsService>(Lifetime.Singleton);
        builder.Register<IMutationService, MutationService>(Lifetime.Singleton);
        builder.Register<IEconomyService, EconomyService>(Lifetime.Singleton);
        builder.Register<IPatentService, PatentService>(Lifetime.Singleton);
    }
}

// LifetimeScope por cena — herda AppScope
public sealed class SequencerScope : LifetimeScope
{
    protected override void Configure(IContainerBuilder builder)
    {
        builder.Register<SequencerViewModel>(Lifetime.Scoped);
        builder.RegisterComponentInHierarchy<SequencerController>();
    }
}
10

Serialização & Persistência

Saves locais, exportação de genomas e integridade de dados

O save do jogo é baseado em JSON legível (Newtonsoft Json.NET), garantindo debugabilidade e facilidade de manutenção. A complexidade interna do genoma torna o JSON inacessível para cheating prático — editar nucleotídeos fora do jogo quebra proteínas de forma imprevisível.

Estrutura do Save

JSON saves/slot_01.json (exemplo)
{
  "version": "1.0.0",
  "savedAt": "2025-11-01T14:32:00Z",
  "lab": {
    "funds": 14200,
    "aquariums": [
      {
        "id": "aq_01",
        "biome": "TROPICAL",
        "genomeCrc32": "a3f8c21d",  // checksum de integridade
        "nucleotides": "ATGCGATCGATCGTACGATCG..."
      }
    ]
  },
  "discoveredNodes": ["node_luciferase", "node_transport_mineral"],
  "patents": [
    {
      "pathId": "path_biolum_v1",
      "registeredAt": "2025-11-01T10:00:00Z",
      "genomeBase64": "QVRHQ0dBVENHQVRDR1RBQ0dBVENH..."
    }
  ]
}

Repository Pattern

C# Infrastructure/Persistence/JsonSaveRepository.cs
public sealed class JsonSaveRepository : ISaveRepository
{
    private static readonly JsonSerializerSettings _settings = new()
    {
        Converters        = { new NucleotideConverter() },
        Formatting        = Formatting.Indented,
        NullValueHandling = NullValueHandling.Ignore
    };

    public async UniTask<Result<SaveData>> LoadAsync(int slot, CancellationToken ct)
    {
        var path = GetSlotPath(slot);
        if (!File.Exists(path))
            return Result<SaveData>.Fail("Save not found");

        var json = await File.ReadAllTextAsync(path, ct);
        var data = JsonConvert.DeserializeObject<SaveData>(json, _settings);

        // valida integridade de cada genoma pelo CRC32
        foreach (var aq in data.Lab.Aquariums)
            if (!ValidateChecksum(aq))
                return Result<SaveData>.Fail($"Genome checksum mismatch: {aq.Id}");

        return Result<SaveData>.Ok(data);
    }
}
11

Editor Tools

Ferramentas de design de dados — configuração visual sem código

Toda a configuração do jogo — vias metabólicas, biomas, contratos, tabelas de tradução genética — é editada através de ferramentas visuais customizadas no Unity Editor. Designers e game designers nunca precisam editar JSON manualmente ou modificar código.

🕸️
Metabolic Pathway Editor
Node Graph (NodeGraphProcessor) para configurar redes de reações bioquímicas. Nós representam enzimas/proteínas, arestas representam fluxo de substrato. Exporta para ScriptableObject.
🧪
Codon Table Editor
Tabela visual interativa de mapeamento códon → aminoácido. Suporta genética padrão e genéticas alienígenas customizadas para biomas especiais.
🌍
Biome Designer
Editor de parâmetros de bioma (temperatura, pH, composição mineral, ciclo luminoso). Preview em tempo real do aquário gerado. Configura probabilidades de drop para Caçadas.
📋
Contract Builder
Editor de missões/contratos: define parâmetros fenotípicos alvo, recompensas em FP, dificuldade e prazo. Conecta a vias metabólicas via referência direta no grafo.
🔬
Genome Sandbox
Ferramenta de debugging de genoma no Editor. Cola uma sequência nucleotídica, aciona a simulação e exibe o fenótipo resultante e o mapa de proteínas em tempo real.
🎨
Phenotype Preview
Visualizador 3D do organismo baseado em parâmetros fenotípicos editados diretamente. Sincronizado com o Genome Sandbox para preview imediato de mutações.

NodeGraphProcessor — Metabolic Pathway Editor

O NodeGraphProcessor (open-source) é usado como base para o editor de vias metabólicas. Cada nó no grafo representa um processo bioquímico e é implementado como uma classe C# que herda de BaseNode.

C# Editor/NodeGraphs/Nodes/EnzymeNode.cs
[NodeMenuItem("Metabolism/Enzyme")]
public class EnzymeNode : BaseNode
{
    [Input("Substrate")]  public SubstrateData substrate;
    [Output("Product")]   public SubstrateData product;

    [SerializeField] public string  enzymeName;
    [SerializeField] public float   kineticRate;
    [SerializeField] public float   energyCost;   // ATP equivalentes
    [SerializeField] public string  requiredCodon; // códon que gera essa enzima

    public override string name => enzymeName;

    protected override void Process()
    {
        product = new SubstrateData
        {
            Id           = substrate.Id + "_processed",
            Concentration = substrate.Concentration * kineticRate
        };
    }
}
🔌 Exportação Automática Um NodeGraphProcessor custom processor converte o grafo finalizado em um MetabolicPathwaySO (ScriptableObject), que é então carregado em tempo de execução pelo MetabolicGraphService via Addressables. Designers salvam o grafo → o jogo carrega automaticamente.
12

Cloud, Anti-Cheat & Segurança

Arquitetura offline-first com integrações em nuvem para economia equilibrada

O jogo é primordialmente Offline-First: toda a simulação biológica, genética e de laboratório funciona completamente sem conexão. A nuvem é usada apenas para features onde o servidor precisa ser a fonte de verdade.

💻 Processamento Offline (Cliente)
  • ✓ Simulação biológica completa
  • ✓ Frameshift, translação proteica, vias metabólicas
  • ✓ Crescimento de organismos em aquários
  • ✓ Gerenciamento do laboratório e contratos locais
  • ✓ Save/Load completo via JSON local
☁️ Firebase (Nuvem)
  • 🎲 RNG server-side para Caçadas Selvagens (genomas por bioma)
  • 🔒 Validação estrutural de genomas no upload de patentes
  • 📦 Registro Mundial de Patentes (Firestore)
  • 💰 Cálculo de royalties server-side
  • 🔄 Mercado comunitário de genomas (strings Base64)

Anti-Cheat por Complexidade

O mecanismo principal de anti-cheat não é criptografia — é a própria complexidade biológica simulada:

Vetor de AtaqueDefesa Natural do Sistema
Editar nucleotídeos no save.json CRC32 checksum detecta alteração. Mesmo sem CRC, editar A→C em posição aleatória muda o códon, quebra a proteína e inviabiliza o organismo. A ferramenta de debugging do jogo é necessária para qualquer edição funcional.
Copiar genoma lendário de outro jogador Sistema Chave-Fechadura: proteínas do genoma externo têm baixa afinidade com enzimas nativas do hospedeiro. Inserção direta falha na simulação — é necessário trabalho real de adaptação.
Burlar RNG de Caçadas Selvagens RNG é executado em Firebase Functions (server-side). O cliente recebe apenas o genoma resultante, não a semente aleatória.
Registrar patentes (Anti-Plágio) As Firebase Functions (Node.js) atuam como "INPI Genético". Ao patentear uma via ou genoma de um Vorg, a Function avalia o pedido calculando a diferença genética (ex: Levenshtein distance ou alinhamento). Se não houver uma % mínima de diferença para patentes existentes, o registro é rejeitado para evitar plágio barato de genomas valiosos.
Injetar valores de FP no save Transações de FP que envolvem itens premium são validadas server-side. Saldo local é reconciliado contra log de eventos no Firestore.

Firebase Functions — Endpoints Principais

TypeScript firebase/functions/src/wildHunt.ts (exemplo)
export const generateWildGenome = onCall(async (request) => {
  const { biomeId, playerLevel } = request.data;

  // RNG server-side — cliente nunca acessa a semente
  const seed   = crypto.randomBytes(16).toString("hex");
  const rarity = rollRarity(playerLevel, seed);

  const genome = await buildGenomeForBiome({
    biomeId,
    rarity,
    seed,
    codonTable: await getCodonTableForBiome(biomeId)
  });

  return {
    nucleotides: genome.nucleotides,
    rarity:      rarity,
    checksum:    crc32(genome.nucleotides),   // validação pelo cliente
    expiresAt:   Date.now() + 3600000           // 1h para aceitar
  };
});
⚠️ Nota sobre Monetização O modelo de monetização ainda não foi definido. A arquitetura cloud (Firebase) está projetada para suportar tanto Premium (compra única) quanto modelos com economia online. As Firebase Functions para Caçadas Selvagens são o ponto de monetização mais natural, caso se opte por um sistema de premium currency para chamadas de caçada.