O Kernel de Autoria — Construindo uma Segunda Superfície de Autoria
Avançado. Para autores de asset/ferramentas que querem construir sua própria UI de autoria (por exemplo, um canvas de grafo de nós) em cima do motor do SheetForge. Equipes de jogo que usam o Data Studio não precisam desta página.
A janela de autoria não é o motor. O Data Studio — e o app web ao seu lado — são consumidores de um kernel de autoria agnóstico de janela.
Tudo que eles fazem (preparação, validação, orquestração do reflect, limites de undo, reimportação) é conduzido através de tipos públicos que uma terceira superfície pode conduzir igualmente bem. Duas superfícies já fazem isso, o que é a prova prática de que essa costura é real, não aspiracional.
Antes de construir uma superfície inteira, veja se um ponto de extensão já cobre a necessidade. Um plugin pode adicionar verbos, painéis, selos e widgets de célula à janela distribuída sem possuir uma janela própria, descritos como dado para que sejam renderizados no editor e no navegador — veja Autoria de Plugins §4.16. Esta página é para o caso em que você quer o seu próprio canvas.
Um assembly de teste de simulação de consumidor (SheetForge.Tests.Consumer, sem acesso via InternalsVisibleTo ao Core ou ao Editor) implementa uma superfície de autoria virtual de ponta a ponta apenas contra a API pública. Se qualquer membro necessário fosse internal, esse assembly falharia ao compilar (CS0122) — por isso ele serve como a especificação executável da superfície descrita abaixo.
O motor de três objetos
┌─────────────────────┐ ┌──────────────────────────┐ ┌───────────────┐
│ AuthoringSession │────▶│ AuthoringDispatcher │────▶│ BaselineStore │
│ (staging state) │ │ .Reflect() │ │ (round-trip │
│ │ │ (the full cycle) │ │ snapshots) │
└─────────────────────┘ └────────────┬─────────────┘ └───────────────┘
│ binds
┌────────────▼─────────────┐
│ AuthoringDispatchCallbacks│
│ (view concerns — YOUR UI) │
└──────────────────────────┘AuthoringSession — o estado de preparação
Uma classe simples [Serializable] (deliberadamente não um ScriptableObject): mantenha-a em um campo [SerializeField] da sua EditorWindow e você ganha snapshots de Undo nativos da Unity e sobrevivência ao domain reload de graça — o mesmo mecanismo por trás do Ctrl+Z da janela de autoria.
Ela possui todo o estado preparado:
- edições de célula (
Edits), novas linhas (NewRows), operações de estrutura (StructOps); - reordenações por aba (
Reorders), renomeações de aba (TabRenames); - âncoras de baseline, edições isoladas.
Além desse estado, ela expõe a API de mutação/consulta:
SetStaged(...)— prepara uma edição de célula. Edições carregam um endereço lógico (aba · RecordId · campo); o ordinal físico da linha é um cache derivado, reresolvido pouco antes do reflect.ResolveBaselineEdits(provider)— reancora todas as edições em relação ao baseline atual. Edições resolvíveis prosseguem; os três casos não resolvíveis (renomeação externa / exclusão externa / conflito de chave) são movidos paraIsolatedEdits— excluídos do reflect, sinalizados, nunca descartados silenciosamente, nunca bloqueando a sessão.- Superfície de leitura do baseline:
TabNames,TryGetBaselineTable(tab, out SheetTable)— acesso a esquema tipado (TypeToken,@desc,@overlap) sem você mesmo tocar no parser. EffectiveStructOps()/PendingStructCount()— a visão composta e canônica das operações de estrutura.- Hooks de remapeamento (
RemapFieldName/RemapRecordId/RemapTab) mantêm o estado preparado coerente através de renomeações. LastProjectionResultarmazena em cache a projeção mais recente.
AuthoringDispatcher — a orquestração do reflect
var dispatcher = new AuthoringDispatcher(session, callbacks, baselineStore);
dispatcher.Reflect(); // the entire cycle, one callReflect() executa o ciclo inteiro, em ordem:
- validação prévia
- reflect por origem — gravações cirúrgicas para local, reescrita segura para Google, seu próprio alvo para provedores personalizados
- limpeza de estado retido
- o limite de confirmação
ClearUndo - reimportação automática com relatório
Além disso:
BuildProjectionResult()— uma projeção livre de efeitos colaterais do estado preparado atual como umImportResult(valida como se tivesse sido refletido). Use-a para selos de erro ao vivo.Session/Callbacks/Baselinespúblicos — provedores de origem personalizados os usam para montar seus alvos de reflect.
AuthoringDispatchCallbacks — o contrato da sua UI
Um pacote de 13 delegates gerais que o dispatcher chama para cada preocupação de visualização: ResolveSettings, diálogos de confirmação (ConfirmKeyRenames, ConfirmTabRenames, …), RenderReport (um Action<ImportReport> — tolerante a null, é apenas observacional), PushApprover, TriggerReimport, ClearUndo, Rebuild, e assim por diante.
Os 14 delegates de diálogo específicos das origens embutidas Local/Google vivem em um pacote opcional separado, o BuiltInSourceDialogs, que uma superfície externa ou provedor nunca precisa vincular.
A janela de autoria vincula padrões que exibem diálogos; o seu canvas vincula os seus próprios (ou no-ops). O motor nunca desenha a UI por conta própria.
Material de grafo
Para uma projeção "nó = registro, aresta = referência ∪ declaração":
ReferenceScanner(Core) — a única fonte da verdade para enumerar ocorrências de referência em todas as tabelas: escalares, elementos de lista, padrões explícitos. A mesma enumeração que o validador de referência usa, então o seu grafo e a validação concordam por construção.Scan(tables)/ScanTable/ScanField/IsReferenceField.IEdgeContributor/EdgeSpec/EdgeContributorRegistry(Core) — plugins de domínio declaram arestas que o scanner não consegue ver (dentro de valores de tipo personalizado, links de colunatype, arestas de registro com um registro de payload). Colete-as viaPluginRegistry.BuildEdgeContributorsdo Editor.ReferenceIndex/RecordEdge(Core) — o snapshot montado sobre o qual o próprio canvas do Data Studio roda:Build(...)funde as referências escaneadas com as arestas de contribuidor de uma vez, e entãoOutEdges/InEdges/InCountrespondem em O(1) por registro. Lista completa de membros na Referência da API.IRecordCanvasAugmenter/CanvasAugmentBuilder(Core) — o contrato de sobreposição por aba, caso você queira que pacotes de domínio estendam o seu canvas da mesma forma que estendem o do Studio (nós virtuais, arestas extras, dicas de camada e de exibição).ProjectionErrorMapper(Editor, puro) — mapeia a coordenada física de um erro de projeção (aba/linha/campo) para um endereço lógico (aba/RecordId/campo), para que você possa fixar selos de erro em nós em vez de números de linha.
Peças de apoio
| Tipo | Para que a sua superfície o usa |
|---|---|
ImportEvents | Dois barramentos, ambos contratos públicos. ImportCompleted (ImportCompletedArgs: Tabs · BakeFolder) dispara quando a cadeia automática rodou até o fim, passando pelo bake, então um assinante pode ler os assets cozidos. BaselineUpdated (BaselineUpdatedArgs: Tabs · Quarantined) dispara sempre que um snapshot de planilha foi salvo — incluindo uma execução que falhou na validação — que é o que uma superfície assina se quiser mostrar as planilhas com falha e deixar as pessoas corrigi-las. Inscreva-se nos dois se a sua visualização mostra planilhas e valores cozidos; cancele a inscrição simetricamente em OnDisable. |
IPipelineObserver | Se o que precisa saber é um plugin, e não uma janela, este é o caminho mais leve: registre um observador e receba um PipelineRunView imutável ao final de cada ciclo de importação, sem nenhuma dependência de editor — funciona também no host do navegador. Veja Autoria de Plugins §4.17. |
RecordIdMinter | Sugere ids para novos registros — detecção de prefixo + unificação segura contra colisão. Uma API de sugestão, deliberadamente não uma numeração automática. |
EphemeralSoApply | Pré-visualiza valores preparados nos SOs do bake temporariamente (a reimportação restaura). Aplica o subconjunto computável; retorna motivos de omissão para colunas pendentes e falhas de parsing. Nada na UI distribuída o aciona mais, então uma superfície que quer essa pré-visualização é dona do botão para isso. |
KeyRenamePlanner | Planeja renomeações de chave (3 estágios: extração / propagação / cirurgia), da mesma forma que a janela de autoria faz. As confirmações de renomeação de aba passam, em vez disso, pelo callback público ConfirmTabRenames. |
SourceProviderRegistry | Resolve o provedor de origem ativo da mesma forma que a UI de configurações faz. |
Regras fundamentais que o kernel impõe (e que você herda)
- A planilha permanece canônica — a sua superfície prepara e reflete; ela nunca grava SOs.
- Validar-depois-refletir —
Reflect()não grava nada se a validação prévia falhar. - Sem perda silenciosa — edições não resolvíveis se isolam com um motivo; confirmações passam pelos seus callbacks.
- O Undo se integra nativamente — mantenha a sessão em um campo serializado e registre snapshots de undo na sua janela;
ClearUndomarca o limite do reflect. - Agnóstico de domínio — o kernel contém zero vocabulário de domínio (testado por guarda). O seu domínio chega via os contratos de plugin, não via edições no kernel.
Páginas relacionadas
- Referência da API — assinaturas de tudo que é mencionado aqui
- Autoria de Plugins — os contratos que o seu domínio usa junto com o kernel
- Data Studio — o comportamento que a sua superfície replica ou substitui