Pular para o conteúdo
SheetForge

Fontes, Exportação e Envio

Existem três caminhos de gravação, cada um com um alvo diferente:

  • reflect grava a preparação da autoria na origem.
  • Exportação grava valores do SO do bake de volta nos arquivos de planilha.
  • Push grava valores do SO do bake na planilha do Google ao vivo, célula por célula.

Origens de importação

A origem de importação é uma escolha de primeira classe no asset de configurações. Cada origem declara sua própria capacidade de autoria (CanAuthor):

OrigemO que ela lêAutoria (gravação de volta)
LocalFileUma pasta de arquivos .tsv / .csv / .xlsx (apenas filhos imediatos; um arquivo = uma aba, workbooks xlsx contribuem com suas planilhas internas)Completa — reflect, edição de estrutura, renomeação de chave/aba
GoogleSheet · SheetsApiUma planilha privada/compartilhada via autenticação JWT de conta de serviço (guia de configuração)Completa — gravações cirúrgicas de célula, reescrita de estrutura, Push
GoogleSheet · ExportUrlUma planilha compartilhada por link, via sua URL de exportação — nenhuma autenticação necessáriaSomente leitura (CanAuthor = false) — Push/reflect/edição de estrutura/exclusão ficam desabilitados, com uma explicação
Provedores personalizadosQualquer coisa que um plugin registre (ISheetSourceProvider — DB, REST, formatos internos)Escolha do provedor, via sua flag CanAuthor

Notas:

  • ExportUrl exige um mapa de gid (nome da aba → valor #gid=). Uma URL de exportação sem gid retorna silenciosamente apenas a primeira aba, então o mapa é obrigatório (GoogleSheetGidMapMissing, gids duplicados são rejeitados). O modo SheetsApi descobre as abas automaticamente e não precisa de mapa.
  • O leitor/gravador de xlsx embutido é OOXML escrito à mão (apenas System.IO.Compression + System.Xml — sem NPOI/ClosedXML, zero código de terceiros), então ele não adiciona nenhuma DLL que possa colidir com outros assets do seu projeto. É um único codec, compartilhado: o mesmo leitor roda no editor da Unity e — compilado para WebAssembly — no aplicativo web, então os dois hosts não podem discordar sobre uma célula. É intencionalmente minimalista e honesto sobre isso — apenas valores, sem recálculo:
    • Uma célula de fórmula contribui com o valor em cache no arquivo. Uma fórmula sem valor em cache, e uma célula de erro (#REF!, #DIV/0!), são rejeitadas (UnsupportedXlsxCell) — salve o workbook uma vez no Excel para colocar os valores em cache, ou materialize as fórmulas.
    • Uma célula com formato de data é lida como a sua data, renderizada yyyy-MM-dd — tanto o tipo de célula ISO quanto um número simples cujo estilo é um formato de data, com os sistemas de data de 1900 e de 1904 ambos respeitados — em vez do número de série bruto que o arquivo armazena. Outros formatos numéricos, células mescladas e gráficos não são importados.
    • Essas interpretações — valores de fórmula em cache, datas como texto de exibição, formatação ignorada — são a política fixa do leitor nos dois hosts, e o diálogo de importação do aplicativo web nomeia adicionalmente as que realmente aconteceram em uma nota "Como esta pasta de trabalho foi lida".
    • Uma tabulação ou quebra de linha dentro de uma célula é rejeitada (UnsupportedCellCharacter) — use ; para listas.
    • Códigos de tipo de célula que o leitor não reconhece são lidos como seu texto bruto armazenado, e não rejeitados.
  • Arquivos locais precisam ser Unicode. Um BOM UTF-8 ou um BOM UTF-16 (LE ou BE) é respeitado; sem um BOM, o arquivo é decodificado como UTF-8 estrito. Uma codificação legada de byte único, como CP949 ou Shift-JIS, é rejeitada (UnsupportedEncoding), não adivinhada — um palpite decodificaria de forma diferente em máquinas diferentes e corromperia os dados silenciosamente. Regrave o arquivo como UTF-8.
  • Uma origem pode retornar saída parcial — um arquivo quebrado não descarta as abas legíveis; os problemas chegam como diagnósticos.
  • Provedores de origem personalizados são descobertos automaticamente e aparecem no mesmo dropdown de configurações — veja Autoria de Plugins.
  • O studio avisa quando a origem seguiu em frente sem você. Ao focar a janela — ou sob demanda pelo menu ⋯ — o studio relê a origem e a compara com o snapshot da sua última importação, mostrando um selo apenas quando os dados realmente diferem: uma planilha apenas regravada ou meramente reformatada permanece quieta, porque a comparação é sobre conteúdo, não timestamps. Clicar no selo oferece executar a importação; nada faz polling em um timer, nada importa sozinho, e estar offline ou não autorizado simplesmente significa nenhum selo. Funciona da mesma forma para todo tipo de origem — arquivos locais, planilhas de URL de exportação e a Sheets API igualmente.

Exportação — a metade de retorno do round-trip

⋯ ▸ Executar Exportação na barra de ferramentas do Data Studio grava os valores do SO do bake de volta nos arquivos de planilha.

  • A estrutura vem do baseline, os valores vêm dos SOs. A Exportação troca os valores atuais no snapshot de baseline da estrutura da sua planilha — linhas de marcador, ordem de colunas, comentários e texto escrito por humanos são preservados 100%.
  • Round-trip semântico de valor: a normalização 1.01 é permitida (valor idêntico); floats usam o formato de round-trip mais curto; sempre decimal com ..
  • Formatos: Tsv / Csv / Xlsx / Json / MatchSource (cada aba retorna ao formato do qual foi importada; origem Google ou desconhecida recorre a Tsv). Json é um formato somente de saída, feito para máquinas em vez de planilhas: um arquivo por aba, registros como objetos, int / float / bool como números e booleanos JSON de verdade, e todo outro valor — referências, listas, cores, curvas, tipos personalizados — no texto de célula canônico exato que a planilha guarda, para que um servidor ou uma ferramenta externa consiga consumir os dados do jogo sem fazer parsing do texto da planilha. JSON não é uma origem de importação, e um arquivo JSON não carrega nenhuma estrutura de planilha para fazer o round-trip — a planilha continua canônica. TSV e CSV gravam um arquivo por aba; Xlsx grava toda aba exportada em um único workbook (SheetForge.xlsx), cada aba como sua própria planilha, na ordem das abas — um workbook é o formato feito para guardar várias planilhas, e mantê-las juntas também é o que permite que os dropdowns de referência apontem entre planilhas (abaixo). Sob MatchSource, as abas de origem xlsx se reúnem naquele único workbook, enquanto as outras voltam para os seus próprios arquivos. Um nome de planilha que as regras do workbook não conseguem guardar (longo demais, ou um caractere proibido) é ajustado e relatado pelo nome — nunca renomeado silenciosamente.
  • A atualidade é imposta: exportar com um bake desatualizado depois de uma mudança de esquema falha com ExportSchemaMismatch (o SchemaFingerprint do bake precisa corresponder ao do baseline) — execute uma importação primeiro.
  • Referências de asset são exportadas de volta como o texto de endereço que a planilha usa — a chave, ou parent[sub] para um sub-asset; o grupo é o da coluna — nunca como GUIDs. Colunas tipadas (AssetRef@Group<Type>) fazem o round-trip da mesma forma. Valores Color, AnimationCurve e Gradient voltam na sua forma de texto canônica (veja Sintaxe da Planilha); uma curva sem chaves é exportada como uma célula vazia, e uma cor é limitada a 0…1 (sem HDR).

Push — gravação de volta em nível de célula para Planilhas do Google

⋯ ▸ Push para Planilha do Google na barra de ferramentas do Data Studio envia os valores do SO do bake para a planilha ao vivo, célula por célula. O item fica desabilitado, com o motivo explicado, a menos que a origem ativa seja Planilha do Google no modo API. É projetado para nunca corromper uma planilha ao vivo que outra pessoa está editando.

Três garantias decorrem dessa cadeia:

  • Nada é enviado sem a sua aprovação de um plano em nível de célula.
  • Uma célula que mudou na planilha ao vivo depois da sua importação é ignorada, nunca sobrescrita.
  • Uma exclusão de linha só é enviada quando a planilha ao vivo ainda mostra essa chave exatamente naquela linha — qualquer coisa que tenha se alterado é ignorada com um aviso, nunca adivinhada.

A cadeia de segurança, em ordem:

  1. Credenciais do SheetsApi são obrigatórias — o Push no modo ExportUrl é recusado antes de qualquer chamada de rede (GooglePushRequiresSheetsApi).
  2. Uma coluna-chave é obrigatória para cada aba enviada por Push — o Push relocaliza cada linha pela chave na planilha ao vivo, então ele consegue detectar uma linha que se moveu e ignorar essa gravação com segurança (nunca enviando para a linha errada). Uma aba sem chave com alterações é recusada (PushKeylessTabUnsupported).
  3. Plano + aprovação: um diff em nível de célula (baseline vs SO atual) é calculado como um plano — gravações, inclusões, exclusões de linha. O plano é mostrado para aprovação explícita antes que qualquer coisa seja enviada; as exclusões ficam em sua própria seção, cada uma identificada pela chave que vai desaparecer. Rejeitar = zero células enviadas.
  4. Nova busca ao vivo antes do envio: imediatamente antes de enviar, a planilha ao vivo é buscada novamente e comparada. Células em conflito são ignoradas, não sobrescritas (relatadas como avisos):
    • PushConflictCellChanged — um terceiro editou essa célula.
    • PushConflictRowMoved — a chave foi encontrada em uma linha diferente da que a sua importação viu, então a gravação é ignorada (nunca enviada para a linha errada). Reimporte para ressincronizar, depois faça o Push novamente.
    • PushConflictRowMissing — a linha foi excluída externamente.
    • PushConflictDuplicateLiveKey / PushConflictAppendKeyExists — alvos ambíguos.
  5. Exclusões de linha são comparadas por chave antes de serem enviadas. Um registro que você excluiu só é removido da planilha ao vivo depois que a busca anterior ao envio confirma que sua chave ainda está exatamente na linha que sua importação viu: uma linha que já sumiu conta como concluída (um novo Push não exclui nada duas vezes), e uma chave encontrada em uma linha diferente — a planilha se alterou — é ignorada com um aviso, nunca excluída por posição. As exclusões são enviadas por último, de baixo para cima dentro de cada aba, então remoções anteriores não conseguem deslocar as coordenadas das posteriores. Uma origem que não consegue excluir linhas (um provedor personalizado sem essa capacidade) recorre honestamente ao comportamento antigo: a exclusão é relatada e a linha ao vivo é deixada para você remover.

Depois de um Push, verifique as contagens de aplicadas/ignoradas do relatório; se células foram ignoradas, reimporte para reconciliar e faça o Push novamente.

Alterações de estrutura no Google

Edições de estrutura (colunas, marcadores, reordenação, renomeações) em uma origem Google reescrevem a aba de destino inteira — com uma checagem de diff ao vivo primeiro, e aprovação explícita antes de sobrescrever qualquer coisa que tenha mudado na planilha depois da sua última importação. Edições de valor permanecem cirúrgicas (por célula); somente a estrutura usa o caminho de reescrita.

Registros do Addressables feitos por um reflect

Soltar um asset em uma célula AssetRef@Group no Data Studio, ou escolher um a partir do projeto, pode preparar uma alteração no projeto, além da planilha: adicionar o asset ao grupo, movê-lo de outro grupo, ou criar o grupo. Esses registros fazem parte do reflect e rodam em um lugar fixo da cadeia — o mesmo lugar para uma pasta local, uma planilha do Google e um provedor de origem personalizado:

  1. O pre-flight valida o estado projetado inteiro com os registros preparados contados como presentes, então uma célula que aponta para um asset ainda não registrado não é um erro.
  2. A planilha é gravada. Se a gravação for cancelada ou falhar, nada abaixo roda: as configurações do Addressables permanecem intocadas e os registros continuam preparados para a próxima tentativa. Um reflect que não conseguiu gravar nenhuma aba porque toda aba tocada foi ignorada (por exemplo, quando apenas abas baseadas em workbook foram tocadas) também não os executa. Um reflect que não tem absolutamente nada para gravar na planilha — a única alteração preparada é um registro — executa-os e reimporta; nenhuma outra edição preparada é confirmada por essa passagem, então ela permanece desfazível.
  3. Os registros rodam, em ordem: os grupos são criados primeiro (com os BundledAssetGroupSchema e ContentUpdateGroupSchema padrão), depois as entradas são adicionadas ou movidas e recebem o seu endereço, e as configurações são salvas uma única vez. Cada item é reverificado imediatamente antes de rodar e é ignorado em vez de forçado quando o asset foi excluído nesse meio-tempo, quando o endereço agora está ocupado por um asset diferente naquele grupo, quando o grupo não pôde ser criado ou encontrado, e quando nenhuma célula mais referencia o endereço (um registro nunca cria uma entrada que nada aponta para, e um grupo cujas entradas foram todas ignoradas também não é criado). Se o projeto ainda não tem um asset de configurações do Addressables, um é criado para esse fim.
  4. A lista preparada é limpa — aplicados e ignorados igualmente — e a reimportação automática vem em seguida, então o bake vê as novas entradas. Um registro ignorado é, portanto, relatado honestamente naquela reimportação como UnknownAssetKey na célula que precisava dele.

O Console traz uma linha por resultado — Addressables: 'address' → group 'Group' para cada item aplicado, Addressables: skipped 'address' (reason) como um aviso para cada um ignorado — e uma linha de resumo Addressables: N registered, M skipped. Para uma origem de pasta local, o diálogo de conclusão do reflect termina com essa mesma linha de resumo.

Colunas cujas escolhas são finitas ganham uma regra de validação de dados anexada à planilha, então a pessoa editando na Planilha do Google ou no Excel escolhe de uma lista em vez de ter que lembrar a grafia. Nada precisa ser ativado: as regras são computadas em toda Exportação, Push e gravação de volta da autoria, e aplicadas onde quer que o alvo consiga carregá-las.

ColunaRegra
Escalar Enum<T>Uma lista fixa dos membros daquele enum.
Escalar de referência (RecordId@Tab, e um tipo personalizado com paridade de referência — §4.4a)Um intervalo sobre a coluna-chave da aba de destino, deixado em aberto, então registros adicionados à aba de destino entram na lista por conta própria.
List<>, colunas wrapper, a própria coluna-chaveNenhuma regra — uma célula ali guarda vários valores, ou não há alvo para listar.
  • Orientação, nunca imposição. Toda regra é não estrita (Google strict:false, xlsx showErrorMessage="0"): um valor fora da lista é sinalizado com um marcador de aviso, mas ainda assim aceito. Uma rejeição rígida quebraria o fluxo comum de "grave a referência agora, defina o registro depois", e entraria em conflito com as próprias sugestões de correspondência mais próxima da importação.
  • As regras são metadado de exibição, não valores. Elas nunca aparecem em uma célula, então o round-trip não é afetado, e uma exportação sem regras é idêntica byte a byte a uma produzida antes disso existir.
  • Aplicadas independentemente dos valores. Anexar regras é uma etapa própria, e não um efeito colateral de gravar células — o fluxo mais comum (adicionar um membro de enum, sem mudar nenhum dado) envia zero células, então um efeito colateral nunca rodaria. É idempotente, então executar de novo não muda nada.
  • Uma falha é um aviso, não um Push falho. Se os valores saíram e só as regras não puderam ser anexadas, o Push ainda assim teve sucesso; execute-o novamente e apenas as regras são reaplicadas.

O que cada formato consegue carregar:

AlvoMecanismoNotas
Planilha do Google (Push / gravação de volta)setDataValidation, agrupado em uma única requisiçãoOs dois tipos de regra. O intervalo de referência omite sua linha final, então ele acompanha a aba de destino conforme ela cresce.
xlsx (Exportação)dataValidations depois dos dados da planilhaOs dois tipos de regra. Como a exportação é um único workbook, um intervalo de referência aponta para a coluna-chave da planilha de destino dentro do mesmo arquivo, em aberto pela planilha abaixo — o mesmo significado que o intervalo do Google tem. Uma regra ainda é ignorada, e nomeada no aviso, em três casos honestos: um membro de lista contendo uma vírgula (o separador embutido a dividiria), uma lista embutida acima do limite de 255 caracteres da especificação (a lista inteira entre aspas é o que o formato limita), e um intervalo cuja aba de destino não está no workbook.
TSV / CSV (Exportação)Texto simples não tem onde colocá-las.
JSON (Exportação)Um arquivo de dados, não uma planilha — não há nenhuma célula à qual anexar um dropdown.

Qualquer coisa deixada de fora é relatada honestamente como um único aviso DropdownNotSupportedByFormat por execução — nomeando toda coluna afetada, então a resposta para "por que há dropdowns no Google, mas não no meu arquivo?" está no relatório, e não é um mistério. É um aviso, e não um erro, porque os próprios valores foram exportados por completo; só a conveniência de edição está ausente.

O mapa de gid

Usado somente no modo ExportUrl. Cada entrada mapeia um nome de aba ao valor #gid= da planilha (visível na URL do navegador quando a aba está selecionada). O inspetor de configurações mostra o mapa apenas quando ele é relevante.

Você não precisa copiar esses números do navegador um de cada vez. O inspetor do asset de configurações tem uma seção Google Sheets que preenche o mapa para você.

  • No modo ExportUrl, Preencher gid automaticamente a partir do ao vivo lê a lista de abas da planilha ao vivo e reescreve o mapa inteiro a partir dela, depois salva o asset de configurações.
  • No modo SheetsApi, o mesmo painel oferece, em vez disso, Buscar lista de abas ao vivo, que apenas mostra as abas que a planilha tem no momento. Esse modo descobre os gids por conta própria e não precisa de mapa algum.

Uma ressalva: o preenchimento automático conversa com a API do Sheets, então precisa de uma chave de conta de serviço configurada, mesmo que a própria importação por ExportUrl não precise. Sem uma, ele para e avisa isso, em vez de gravar um mapa parcialmente preenchido.

Hook de verificação de atualização do build — um bake desatualizado falha o build

Antes de cada build, um hook de pré-build verifica três coisas para cada tipo de Database gerado versionado:

  • (i) o SO do bake existe;
  • (ii) o fingerprint do seu esquema corresponde ao baseline;
  • (iii) o seu registro no Addressables existe.

Qualquer falha aborta o build com uma frase acionável (por exemplo, "abra Tools/SheetForge/Data Studio, pressione ↓ Pull from source, depois faça o build"). É isso que torna seguro o fato de "SOs do bake serem gitignored": uma máquina clonada ou de CI não consegue publicar um cache vazio.

Páginas relacionadas