Package Manager
Unity Package Manager (upm) é uma ferramenta muito interessante que nos permite modularizar e organizar melhor nossos projetos. Está com o editor Unity3D desde a versão 2017.2, mas na versão 2018.1 que ganha a interface e fica realmente integrado, como é apresentado neste post oficial.
Particularmente, utlizo o Package Manager extensivamente para modularizar e organizar melhor os meus próprios projetos; podendo atualizar e reutilizar projetos chave. Por exemplo, um package “util” que é utilizado e melhorado em vários projetos diferentes. Ou um package “SaveSystem” que pode ser reutilizado em qualquer projeto Unity.
O package manager tem diferentes utilidades, desde gerenciar as features básicas da Unity, importar outros packages da asset store ou diretamente de um projeto GIT a partir de um repositório qualquer – e esse é foco desse post. Vamos ver o passo-a-passo de como utilizar o Unity Package Manager para integrar com um projeto open source Git. E, como bonus, a utilizar o Gitlab CI para automatizar a publicação e atualização do pacote.
Resumo
- Crie e versione o projeto “pacote” (localmente ou remotamente)
- Crie uma pasta dentro de “Assets” que será o pacote em si.
- Adicione o arquivo package.json e crie um “Assembly Definition” nesta pasta
- Opcionalmente, se utilizar LFS, adicione “.gitattributes” na pasta do pacote criada
Projeto e versionamento
Crie um novo projeto normalmente. Esse será nosso projeto “pacote“. Vamos usar um projeto chamado “UnityUtils” como exemplo.
Git init
Utilizaremos o GIT para versionar o projeto e o gitlab como repositório. Instale a versão mais recente do git no seu computador e faça uma conta no gitlab.com. O git tem vários clientes (softwares que utilizam o git de forma visual) disponíveis na página oficial. Podemos utilizar qualquer um dos clientes que sentir mais confortável ou diretamente por linha de comando. Neste tutorial utilizarei os comandos git puro, através do console/bash que acompanha o software. Clique com o botão direito e escolha “Git Bash”, isso abrirá um console diretamente na pasta selecionada.
Para iniciar o repositório git, utilizamos o comando “git init”. Esse comando monta a estrutura Git e inicializa um branch chamado “master“.
> git init
Git Ignore
A partir de agora podemos adicionar arquivos para o versionamento. Contudo não queremos adicionar todos os arquivos do diretório. Alguns arquivos são temporários, locais ou podem/devem ser recriados pela própria Unity ou IDE. Para ignorar e não adicionar esses arquivos utilizamos um arquivo chamado .gitignore (um arquivo de texto, com ponto na frente e sem extensão). Existem vários modelos desse tipo de arquivo para versionar corretamente os projetos da unity. Eu gosto do seguinte modelo, que pode ser encontrado/baixado aqui. Adicione o arquivo à raiz do projeto.
[Se o projeto for utilizar arquivos grandes, pode ser uma boa ideia configurar o LFS (large file system), aqui tem um arquivo de configuração .gitattributes. Quando trabalhar com LFS é necessário adicionar o arquivo .gitattributes também à raiz do pacote (não somente na raiz do projeto) – para que o Git/Unity, quando estiver resolvendo o pacote, saiba quais tipos de arquivo precisam ser tratados como LFS. Os detalhes do LFS não serão abordados nesse tutorial]
#.gitignore
#
######################
## Project Specific ##
######################
# put here some project specific
# files that can or should be ignored
###############################
## Unity's folders and files ##
###############################
Assets.meta
[Ll]ogs/
[Aa]ssets/AssetStoreTools*
[Bb]uild/
[Bb]uilds/
[Ll]ibrary/
[Ll]ocal[Cc]ache/
[Tt]emp/
[Oo]bj/
[Uu]nityGenerated/
sysinfo.txt
############################
## Autogenerated projects ##
############################
Assets/Plugins/Editor/JetBrains*
[Ee]xportedObj/
*.csproj
*.csproj.meta
*.sln
*.suo
*.userprefs
*.pidb
*.pidb.meta
*.unityproj
.vs
.idea
#########################
## Miscellaneous files ##
#########################
*.swp
Thumbs.db
Thumbs.db.meta
*.blend1
*.blend1.meta
Git Commit
Agora podemos adicionar nossos arquivos e fazer nosso primeiro commit. Os comandos à seguir adicionam os arquivos para o commit e fazem um commit com a mensage “first commit”:
> git add .
> git commit -m "first commit"
Agora, crie um projeto no gitlab. Vou chamar, por exemplo, de “upackage-tutorial“. Na página inicial o próprio gitlab dará dicas de como proceder com o primeiro commit – Se for utilizar SSH, é necessário adicionar a chave pública no gitlab. Também é possível utilizar HTTPS.
Git push
Nós devemos, basicamente, configurar nosso nome e adicionar um “remote” chamado origin com nossa url:
> git config --global user.name "Matheus"
> git config --global user.email "seuemail@provedor.com"
> git remote add origin git@gitlab.com:username/projectname.git
ou
> git remote add origin https://gitlab.com/username/projectname.git
> git push -u origin master
Nosso projeto ainda não é um pacote, mas já está versionado com GIT e pronto para o próximo passo. Crie um outro projeto em um outro local – esse utilizará nosso pacote – vamos chamar de “Teste“. Este novo projeto não precisa ser versionado (mas é sempre uma boa ideia versionar todos os nossos projetos).
Package
Agora que temos o nosso projeto “UnityUtils” criado e versionado, vamos criar o conteúdo do “Package”. Em geral o seu projeto terá vários arquivos, cenas e diversos testes que não são interessantes para o pacote em si. Eu, particularmente, gosto de adicionar uma pasta com o nome da empresa ou do projeto onde os arquivos fundamentais estarão e que será considerada o “pacote” de fato. Por exemplo, nosso pacote será a pasta “UnityUtils”:
Desta forma podemos, posteriormente, adicionar outras pastas que não farão parte do pacote; como por exemplo “Tests” ou “Examples”
Assembly Definition e package.json
Transformar essa pasta em “package” não é difícil. Ela precisa conter um arquivo package.json e um assembly definition. O Json é um manifesto definindo pelo menos o nome do pacote, uma descrição, a versão e a partir de qual unity ele é suportado. Obs.: o nome do pacote segue uma convenção (começa com “com”, o nome da empresa e o nome do pacote) e tem outros detalhes que podem ser averiguados no manual.
{
"name":"com.matheus.unityutils",
"displayName":"Matheus Unity Utils",
"version": "1.0.0",
"unity": "2018.4",
"description": "Unity utility toolkit"
}
Agora crie o assembly definition e nomei-o.
Está pronto o nosso pacote! Ele já pode ser utilizado em outros projetos!
Apesar do pacote estar pronto, ele está disponível somente localmente. Para utilizar ele a partir de qualquer lugar, devemos fazer um commit e um “push especial”.
> git add .
> git commit -m "package files"
> git push
Com esses comandos mandamos ao servidor nossas modificações. Nada de especial. A seguinte linha publicará o pacote que utilizaremos no Unity Package Manager:
> git subtree push --prefix Assets/UnityUtils origin upm --squash
Esse comando fará um novo “branch” no repositório, chamado “upm” a partir da pasta “Assets/UnityUtils”, nossa pasta pacote.
Como será um comando bastante utilizado, podemos adicioná-lo à um arquivo “deploy.sh”. Um arquivo de texto contendo aquela linha de comando unicamente. Agora sempre que “deploy.sh” for executado, o pacote será “publicado”
Utilizando o Pacote
No projeto “Test” vamos utilizar este pacote. Para isso abra o arquivo “manifest.json”, que está dentro da pasta “Packages” (pasta irmã de “Assets”, não é filha). Adicione, no manifesto, o nosso pacote como dependência. A referencia pode ser local, no sistema de arquivo do computador, ou remota pelo nosso repositório na nuvem:
- Localmente:
"com.unityutils": "file:/workspace/utils/Assets/UnityUtils"
- Remotamente
"com.unityutils": "https://gitlab.com/z3r0_th/unity-utils.git#upm"
Salve a edição. O arquivo manifest.json deveria ficar parecido com isso:
Quando abrir a Unity3D com o manifesto modificado, a Unity irá clonar o projeto para a pasta Library\PackageCache E o projeto ficará visível na pasta “Packages” dentro da unity
Editor Assembler
Uma observação válida de se fazer é que o Assembly adicionado no pacote tem alguns perks a se levar em consideração. Um deles é que é necessário adicionar um Assembly definition para a pasta “Editor”, caso tenha uma. A definição desse Assembly é um pouco diferente, já que precisamos avisar o compilador, que este será um código somente para o Editor:
Note que, se temos referencias a scripts que estão em outras pastas, com outras definições de assembly, precisamos referenciar na lista “Assembly Definition References”; caso contrário teremos erros de compilação infomando que não foi possível encontrar classes e referencias.
Bonus: Gitlab CI
CI significa “Continuos Integration” e quer dizer que podemos automatizar a publicação através do nosso sistema de versionamento utilizando alguns serviços, regras e arquivos. O gitlab oferece algumas featuers e vamos utilizá-las para automatizar o processo de “deploy” do nosso pacote. Queremos que, quando fizermos um “push” para o nosso branch “master”, nosso projeto faça um push/deploy para nosso branch “upm” que é utilizado na unity. Crie um arquivo chamado “.gitlab-ci.yml” e adicione o seguinte texto, modificando para sua necessidade (troque o nome da pasta no comando git subtree split –prefix Assets/UnityUtils -b upm –squash, basicamente):
stages:
- deploy
Unity-Package:
stage: deploy
only:
- master
before_script:
- 'which ssh-agent || ( apt-get update -y && apt-get install openssh-client -y )'
- 'git-lfs version || ( apt-get update -y && apt-get install git-lfs )'
- eval $(ssh-agent -s)
- echo "${SSH_PRIVATE_KEY}" | tr -d '\r' | ssh-add - > /dev/null
- mkdir -p ~/.ssh
- chmod 700 ~/.ssh
- git config --global user.email "gitlabci@gitlab.com"
- git config --global user.name "Git lab ci"
- gitlab_hostname=$(echo "${CI_REPOSITORY_URL}" | sed -e 's|https\?://gitlab-ci-token:.@||g' | sed -e 's|/.||g')
- ssh-keyscan "${gitlab_hostname}" >> ~/.ssh/known_hosts
- chmod 644 ~/.ssh/known_hosts
script:
- url_host=$(echo "${CI_REPOSITORY_URL}" | sed -e 's|https\?://gitlab-ci-token:.*@|ssh://git@|g')
- git branch
- git subtree split --prefix Assets/UnityUtils -b upm --squash
- git checkout upm --force
- git remote set-url --push origin "${url_host}"
- git push origin -u --force upm
Também devemos adicionar uma variável no CI do git lab. Acesse as configurações do projeto:
Devemos criar um par de chave ssh que será nosso “publicador”. Crie uma nova chave ssh. Siga o passo-a-passo que os repositórios fornecem, como este da atlassian ou este do gitlab. Caso já tenha feito uma chave ssh, é importante fazer backup ou, melhor ainda, gerar a chave em outro path.
Adicione uma variavel secreta para o projeto, chamada “SSH_PRIVATE_KEY”. O “value” deve ser a chave privada que acabamos de criar.
A chave pública deverá ser adicionada como um “deploy key”, que pode ser encontrado em “repositórios”