> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/contributor/contributor-pt/runtime-da-scene/componentes/component-creation.md).

# Criação de Componentes

Para criar novos componentes, precisamos fazer algumas coisas antes de começar a codificá-los no renderer. Há um guia passo a passo que você precisa seguir. Vou listar todos os passos e, em seguida, você pode seguir cada passo com uma explicação mais longa.

1. Crie a definição proto em [@dcl/protocol](https://github.com/decentraland/protocol)
2. Gere o novo código proto TypeScript no [js-sdk-toolchain](https://github.com/decentraland/js-sdk-toolchain)
3. Crie um teste para `js-sdk-toolchain`
4. Gere o novo código proto C# no projeto
5. Codifique o novo componente
6. Garanta que o componente siga a convenção

## Crie a definição proto em [@dcl/protocol](https://github.com/decentraland/protocol)

Para criar uma definição, você deve ir para este repositório: <https://github.com/decentraland/protocol>

1. Crie a definição proto nesta pasta: <https://github.com/decentraland/protocol/tree/main/ecs/components>
2. Crie um PR com as novas alterações

> ***NOTA:*** Após criar o PR, um Bot do GitHub comentará com o link do pacote para testar o PR. Você pode usar esse link para testar nas etapas seguintes

Coisas a ter em conta

* Estamos usando proto 3, então toda a definição do proto deve compilar com sua [syntax](https://developers.google.com/protocol-buffers/docs/proto3/)
* Temos alguns tipos comuns que não podem ser recriados
* O proto deve ter a definição básica
* Você deve adicionar o seguinte código para enumerar o componente

```
import "common/id.proto";
option (ecs_component_id) = 1100;
```

Exemplo de .proto

```
syntax = "proto3";

import "common/id.proto";
option (ecs_component_id) = 1020;

message PBAudioSource {
  optional bool playing = 1;
  optional float volume = 2; // default=1.0f
  optional bool loop = 3;
  optional float pitch = 4; // default=1.0f
  string audio_clip_url = 5;
}
```

## Gere o novo código proto TypeScript no [js-sdk-toolchain](https://github.com/decentraland/js-sdk-toolchain)

Baixe o seguinte repositório: <https://github.com/decentraland/js-sdk-toolchain>

Dentro dele, navegue para `packages/dcl/ecs` (`https://github.com/decentraland/js-sdk-toolchain/tree/main/packages/%40dcl/ecs`)

E lá, você pode executar

```
npm install @dcl/protocol@next
```

Ou o comando gerado pelo Bot do GitHub no seu PR do @dcl/protocol (isso deve ser temporário para testar os PRs).

Então execute os seguintes comandos na raiz do `js-sdk-toolchain` project:

```
make install
make build
```

E envie (push) o código gerado.

## Gere o novo código proto C# no projeto

Para gerar o código C#, precisamos ir para o `protocol-gen` caminho na raiz do `@decentraland/unity-renderer` repositório. E executar os seguintes comandos:

```
npm install
npm run build-components
```

Para atualizar para a versão mais recente do `@dcl/protocol` (main branch), devemos atualizar usando

```
npm install @dcl/protocol@next
npm run build-components
```

Para testar um PR, podemos usar uma URL gerada pelo Bot do GitHub no `@dcl/protocol` PR: Exemplo:

```
npm install "https://sdk-team-cdn.decentraland.org/@dcl/protocol/branch//dcl-protocol-1.0.0-3143233696.commit-45f1290.tgz"
npm run build-components
```

Após mesclar o PR do @dcl/protocol, devemos usar o `@dcl/protocol@next` e gerar o código.

## Codifique o novo componente

Agora é hora de implementar a funcionalidade do novo componente.

Os componentes têm cinco partes essenciais.

* ComponentID O ID que o componente usará. Deve ser único e gerado a partir da definição proto
* Model Este é o modelo do componente. Esses são os dados que usaremos para manipular o componente. Ele foi gerado automaticamente com a geração do proto e tem o mesmo nome do arquivo proto com um PB na frente. Por exemplo, se você tiver um `BoxShape.proto` definition a classe gerada do modelo será `PBBoxShape`
* Component Handler O component handler gerenciará toda a funcionalidade do componente. Nesta classe você deve implementar o `IECSComponentHandler<ModelClass>` (ModelClass é o modelo. É uma classe gerada a partir do proto, o nome será PB + nome do arquivo .proto). Esta interface tem 3 métodos que são importantes implementar para criar um componente

```
        void OnComponentCreated(IParcelScene scene, IDCLEntity entity);
        void OnComponentRemoved(IParcelScene scene, IDCLEntity entity);
        void OnComponentModelUpdated(IParcelScene scene, IDCLEntity entity, ModelType model);
```

* Serializer Cada componente é responsável por implementar sua serialização e desserialização do componente. Este serializer deve ser capaz de serializar/desserializar para um array de bytes
* Register Isto registrará o componente no sistema, conectando-o ao sistema. Este registro irá registrar o componente na factory e no component writer

O design dos componentes evita herança, então incentivamos o uso de funções puras tanto quanto possível

Para criá-los, devemos seguir os próximos passos

1. Crie a pasta do componente e a assembly. Temos todos os componentes sob a seguinte pasta `DCLPlugins/ECS7/ECSComponents`. Você precisa criar uma pasta e uma nova assembly que conterá o componente
2. Na nova assembly, você deve referenciar a seguinte `DCL.ECSComponents.Data`. Isso referenciará o novo modelo do componente que você acabou de atualizar
3. Você deve criar o component handler com toda a lógica (Dê uma olhada em `ECSBoxShapeComponentHandler.cs` como exemplo)
4. Você deve criar a classe serializer (provavelmente você pode copiá-la de outra classe e adaptar ao seu)
5. Você deve criar a classe register

```sh
   public static class AudioSourceSerializer
    {
        public static byte[] Serialize(PBAudioSource model)
        {
            int size = model.CalculateSize();
            byte[] buffer = new byte[size];
            CodedOutputStream output = new CodedOutputStream(buffer);
            model.WriteTo(output);
            return buffer;
        }

        public static PBAudioSource Deserialize(object data)
        {
            return PBAudioSource.Parser.ParseFrom((byte[])data);
        }
    }
```

6. Adicione o novo register ao `ECS7ComponentsComposer` class com seu ID correspondente

```sh
   public class ECS7ComponentsComposer : IDisposable
    {
        private readonly TransformRegister transformRegister;
        private readonly SphereShapeRegister sphereShapeRegister;
        private readonly BoxShapeRegister boxShapeRegister;
        private readonly PlaneShapeRegister planeShapeRegister;
        private readonly CylinderShapeRegister cylinderShapeRegister;
        private readonly AudioStreamRegister audioStreamRegister;
        private readonly AudioSourceRegister audioSourceRegister;

        public ECS7ComponentsComposer(ECSComponentsFactory componentsFactory, IECSComponentWriter componentsWriter)
        {
            transformRegister = new TransformRegister(ComponentID.TRANSFORM, componentsFactory, componentsWriter);
            sphereShapeRegister = new SphereShapeRegister(ComponentID.SPHERE_SHAPE, componentsFactory, componentsWriter);
            boxShapeRegister = new BoxShapeRegister(ComponentID.BOX_SHAPE, componentsFactory, componentsWriter);
            planeShapeRegister = new PlaneShapeRegister(ComponentID.PLANE_SHAPE, componentsFactory, componentsWriter);
            cylinderShapeRegister = new CylinderShapeRegister(ComponentID.CYLINDER_SHAPE, componentsFactory, componentsWriter);
            audioStreamRegister = new AudioStreamRegister(ComponentID.AUDIO_STREAM, componentsFactory, componentsWriter);
            audioSourceRegister = new AudioSourceRegister(ComponentID.AUDIO_SOURCE, componentsFactory, componentsWriter);
        }

        public void Dispose()
        {
            transformRegister.Dispose();
            sphereShapeRegister.Dispose();
            boxShapeRegister.Dispose();
            planeShapeRegister.Dispose();
            cylinderShapeRegister.Dispose();
            audioStreamRegister.Dispose();
            audioSourceRegister.Dispose();
        }
    }
```

E agora você tem seu componente adicionado e funcionando!

## Garanta que o componente siga a convenção

Há uma lista de verificação que precisamos ter em conta ao desenvolver novos componentes; esta parte tenta resumi-las.

* Unit test Todos os componentes devem incluir unit tests que cubram sua funcionalidade, dispose e a serialização/desserialização pelo menos para garantir que o componente funcionará
* Leve em conta o que acontece quando o componente não está dentro da cena (Verifique `SceneBoundariesChecker` classe para mais informações)
* Se o componente renderiza algo no world, ele deve adicionar a informação renderizável ao data store, dessa forma adicionamos a informação do renderer à cena para que conte para o limite
* Se o componente renderiza algo no world, ele deve adicionar o `MeshesInfo` à entidade
* Deve ser o mais performático possível. Este código será executado muitas vezes, então precisamos garantir que tudo funcione o mais suavemente possível
* Deve funcionar com `Hot reload` no modo preview. Se você codificou o `OnComponentRemoved` corretamente, isso funcionará automaticamente, mas o hot reload é uma forma de testar que tudo funciona bem com o dispose do componente
* Se o componente usa um recurso, você deve implementar o gerenciamento de recursos com um `AssetPromiseKeeper`. O componente deve notificar o `AssetPromiseKeeper` quando o recurso é usado e quando não é mais usado


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.decentraland.org/contributor/contributor-pt/runtime-da-scene/componentes/component-creation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
