跳至主要內容
SheetForge

API 參考——公開介面

本頁列出產品組件中每一個公開型別。任何未列於此處的內容,依設計即為 internal——公開介面是刻意保持精簡的。

  • CoreSheetForge.Core + SheetForge.Core.Tooling):137 個公開型別(Core:131 個,Core.Tooling:6 個)。Core.Tooling 是僅限編輯器使用的一半,內含報告、推送規劃等匯入期服務——完全不會出貨進玩家組建。
  • Editor:53 個頂層公開型別,加上其公開的巢狀型別。
  • Runtime:7 個型別,加上產生的輸出。

這正是消費端模擬測試(不具 InternalsVisibleTo)據以編譯的介面。

偵測合約(並非型別):另一個素材也能透過 Editor 組件自我註冊的 SHEETFORGE scripting-define 符號,在編譯期偵測到 SheetForge 已安裝。它是一個 define,並非公開型別,因此不會列於下方的表格中——見外掛開發 ▸ 從另一個素材偵測 SheetForge。(與 SHEETFORGE_ADDRESSABLES 不同,後者是一個內部版本定義,僅標示 Addressables 套件是否存在。)

慣例說明:簽章皆為精簡表示( = 詳見原始碼中的 XML 檔案);「純粹」代表不使用 UnityEngine/不涉及 IO。


Core 組件(SheetForge.Core)——純 C#

不使用 UnityEngine、不涉及 IO、不涉及網路、不含任何領域知識。由編譯器強制執行:Core 不參照任何東西。

外掛註冊合約(SheetForge.Core.Plugins

型別種類角色與關鍵成員
ISheetForgePlugin介面領域外掛的基礎合約。string Name · RegisterEnums(EnumRegistry) · RegisterCellParsers(CellParserRegistry)
ISheetForgeValidatorPlugin介面驗證規則的選用附加元件。RegisterValidators(DomainValidatorRegistry)
ISheetForgeEdgePlugin介面邊宣告的選用附加元件。RegisterEdgeContributors(EdgeContributorRegistry)
ISheetForgeMarkerPlugin介面自訂結構標記的選用附加元件。RegisterStructuralMarkers(MarkerRegistry)
ISheetForgeTemplatePlugin介面「建立試算表」範本的選用附加元件。RegisterTemplates(TemplateRegistry)
ISheetForgeGraphPlugin介面為 Data Studio 註冊逐分頁畫布覆寫的選用附加元件。RegisterGraphShapes(GraphShapeRegistry)
ISheetForgeCodeRegistryPlugin介面程式碼所有的參照目標(鎖定的虛擬分頁)的選用附加元件。RegisterCodeRegistries(CodeRegistryCatalog)
ISheetForgeThemePlugin介面視窗色彩預設集的選用附加元件。RegisterThemes(ThemeRegistry)
ISheetForgeStudioPlugin介面宣告式編寫介面(動作、面板、欄徽章、儲存格元件提示)的選用附加元件。RegisterStudioUi(StudioUiRegistry)。位於 Core 而非 Editor,因此單一次註冊能同時繪製於 UIToolkit 編輯器與瀏覽器兩端
ISheetForgeStringsPlugin介面依語言註冊套件自身 UI 字串的選用附加元件。RegisterStrings(StringOverlayRegistry)。取代已淘汰的 Editor 端 ISheetForgeLocPlugin / PluginLocRegistry 組合,該組合只能觸及編輯器
ISheetForgePipelinePlugin介面註冊管線觀察者的選用附加元件。RegisterPipelineObservers(PipelineObserverRegistry)

組合與相容性(SheetForge.Core.Plugins

發現方式依主機而異——編輯器中是 Unity 的 TypeCache,網頁上則是瀏覽器的已上傳組件掃描。發現之後的一切(實體化、排序、隔離與相容性關卡)都是同一個共用的 Core 功能,這正是讓兩個主機不會逐插槽走偏的關鍵。

型別種類角色與關鍵成員
PluginComposition靜態類別唯一的組裝路徑。每個型別一個實體,並轉型為它實作的每一項合約。兩個成員與診斷區分方式詳列於表格下方
PluginSetsealed 類別組裝完成的結果——十二個插槽Enums · Parsers · Validators · EdgeContributors · Markers · Templates · GraphShapes · CodeRegistries · Themes · Strings · StudioUi · PipelineObservers。一個新插槽只要加進這裡,就能同時觸及兩個主機
SheetForgePluginCompatAttributesealed 屬性(組件層級)[assembly: SheetForgePluginCompat(SheetForgePluginFormat.Current, MinHostVersion = "…", PluginVersion = "…")]int FormatVersion · string MinHostVersion(數字化的點號比對;null/空白 = 無需求) · string PluginVersion(僅供顯示,絕不參與比對)。讀取時無需實體化任何東西,且以每個組件為單位判斷——被拒絕的組件會失去全部註冊內容,而非半載入。缺席 = 世代 Minimum,無主機需求
SheetForgePluginFormat靜態類別世代常數:const int Current · const int Minimum。只有在外掛格式本身被替換時才會變動——單純的新增式成長,不會使這個數字移動

PluginComposition——兩個成員:

  • IReadOnlyList<Type> ContractTypes——發現時的篩選條件。其順序是固定的,因為它決定了診斷訊息出現的順序。
  • PluginSet Compose(IReadOnlyList<Type> candidateTypes, string hostVersion, ErrorCollector errors, ICollection<string> failures, Func<string,bool> isProductKey = null)——組裝呼叫本身。

兩種問題會被分開處理。註冊衝突與相容性拒絕會成為 errors 中的結構化診斷;實作缺陷——建構失敗、拋出例外的回呼——則會成為 failures 中的英文句子,傳入 null 則會捨棄它們。

尾端的 isProductKey 判斷式,正是字串疊加層「外掛不得覆寫產品鍵值」這條規則得以在 Core 完全看不到語言表的情況下被強制執行的方式:規則存放於此,主機只提供素材。省略該判斷式,就只會跳過這一條規則。

註冊表(SheetForge.Core.Model / .Validation / .Edges

型別角色與關鍵成員
EnumRegistryEnum 名稱 → CLR 型別(供程式碼產生使用)。Register<TEnum>() · Register(name, memberNames) · TryGetMembers · TryGetClrTypeName · TryGetClrAssemblyName · RegisteredEnumNames。另外三個成員詳列於表格下方
CellParserRegistry型別名稱 → 儲存格剖析器(開放封閉)。重複註冊會拋出例外。Register(ICellValueParser) · TryGet · TryGetCustomRenderer · RegisteredTypeNames · RegisterWrapper(ICellWrapperType) · TryGetWrapper · RegisteredWrapperNames(wrapper 型別)
DomainValidatorRegistry僅供附加的驗證器清單,順序會被保留。Register(IDomainValidator) · Validators
EdgeContributorRegistry僅供附加的貢獻者清單,順序會被保留。Register(IEdgeContributor) · Contributors
MarkerRegistry標記名稱(不含 @)→ 自訂結構標記。與內建標記(SheetSyntax.ReservedMarkers@name/@type/@desc/@overlap/@style/@enum/@loc)衝突/重複/無效識別碼皆會拋出例外。Register(IStructuralMarkerDefinition) · TryGet · IsEmpty · RegisteredMarkerNames · AppendMarkerTokens
TemplateRegistry「建立試算表」範本鍵值 → 範本。空白/重複鍵值、空白顯示名稱、零分頁、空白分頁 TSV 皆會拋出例外。Register(DataTemplate) · TryGet · Templates · IsEmpty

EnumRegistry——三個成員詳情:

  • EnumRegistry(EnumRegistry parent)——一個會透讀至父項、且只會註冊到自己身上的子登錄。父登錄承載整個網域重新載入期間、由外掛註冊的 CLR enum,子登錄則承載本次匯入中由試算表定義的 enum,因此一次匯入絕不會變動共用快取。註冊一個父登錄已經擁有的名稱會拋出例外,而不是遮蔽它。
  • Contains(name)——先查自己、再查父項,採 Ordinal 比對。
  • SetClrTypeName(name, fullTypeName)——在僅有字串的註冊之後補上 CLR 名稱;組件名稱維持空白,因為該型別此時尚不存在。

「建立試算表」範本(SheetForge.Core.Model

型別角色與關鍵成員
DataTemplate一個外掛註冊的範本:string Key(登錄用識別碼) · string DisplayName(外掛自有的文字) · IReadOnlyList<DataTemplateTab> Tabs(一個或多個)
DataTemplateTab範本中的一個分頁:string TabName · string Tsv(一份完整、標準化的 TSV——標記列加上範例資料)

自訂儲存格型別(SheetForge.Core.Model

型別角色與關鍵成員
ICellValueParser剖析單一純量儲存格。失敗 = 蒐集進 context.Errors 並回傳 false(絕不拋出例外)。string TypeName · bool TryParse(CellParseContext, string, out object)
ICustomCellType選用的程式碼產生/往返流程輔助工具。Type ValueType · bool TryRender(object, out string text, out string reason)
IReferencingCellType一項選用能力,已註冊的 ICellValueParser 也可以額外實作它,讓深埋在自己記法中的鍵值獲得完整的 RecordId@Tab 待遇——完整性檢查+候選建議、能保留負載內容的鍵值重新命名傳播、圖形邊與連接埠、 選取器、孤兒偵測、匯出下拉選單規則。透過轉型已註冊的剖析器來發現(無需另外註冊)。bool TryGetTokenKey(elementText, out key) · string MakeToken(key) · bool TryRetargetToken(elementText, newKey, out newText) · bool TryRemoveToken(elementText, key, out newText)(回傳空字串 = 該元素消失) · bool TryRewriteKeys(elementText, IReadOnlyDictionary<string,string> renames, out newText)。一次呼叫 = 一個元素(整個儲存格,或一個以 ; 分隔的元素),因此負載內容不得包含 ;@target 必須指向一個真正的試算表分頁(否則為 UnknownTargetTab)。絕不拋出例外——falsenull 代表「無法解讀」,改寫時必須保留殘留內容
IRefBearingValue上述介面在數值端的另一半,由已剖析的數值實作:IEnumerable<string> ReferencedKeys(宣告順序 = 診斷與候選建議預算的順序;null/空白項目會被跳過)。掃描器會讀取此介面;上方的文字掛勾則負責改寫儲存格。兩者缺一不可——已剖析的數值無法還原作者的原始記法,而文字若未經讀取也就無法被驗證
ICellWrapperType一種泛型 wrapper 數值結構 MyWrapper<T>(例如 Pair<int> = 1~2)——wrapper 負責外層語法,Core 則遞迴剖析內部型別。string Name · bool TrySplit(string, out IReadOnlyList<string> pieces, out string reason) · string JoinCanonical(IReadOnlyList<string>) · Type OpenClrType · object Assemble(IReadOnlyList<object>, Type closed) · bool TryDisassemble(object, out IReadOnlyList<object>, out string reason)
WrapperValue一個 wrapper 儲存格經剖析後的 IR——帶有 wrapper 策略,並公開內部的 CellValue(因此內部的參照會通過驗證、鍵值/分頁重新命名,以及匯出)。ICellWrapperType Wrapper · IReadOnlyList<CellValue> Inner
IStructuralMarkerDefinition一個自訂的 @marker 列(逐欄的值,逐欄驗證——是 @overlap 的一般化版本)。string MarkerName(不含 @) · string Description · void ValidateCell(MarkerCellContext)
MarkerCellContext一次標記儲存格驗證呼叫。string MarkerName · string RawText · string FieldName · CellCoordinate Coordinate · void Reject(string reason, string suggestion = null)(→ MarkerCellInvalid
CellParseContext一次剖析呼叫的內容。TypeToken Type · CellCoordinate Coordinate · ErrorCollector Errors · EnumRegistry Enums

試算表文法常數(SheetForge.Core.Model

讀寫儲存格文字的外掛套件,遵循與匯入器完全相同的文法——拆分清單儲存格、組成 @type 字串、檢查某個名稱是否已被使用。

這些常數正是該文法唯一的真實來源,因此外掛套件永遠不必自行重新宣告一次分隔符:複製下來的字元會在文法變動的那天悄悄失準。這些清單都是以唯讀方式對外提供的,因此不論外掛套件做什麼,都無法更動文法本身。它們所表達的記法完整記載於試算表語法頁面——這些常數正是通往該文法的程式化介面。

型別種類角色
SheetSyntax靜態類別以常數形式呈現的試算表文法,依下方分組整理

標記

  • CommentPrefix#)· MarkerPrefix@)。
  • 每個內建標記列各對應一個常數:NameMarker · TypeMarker · DescMarker · OverlapMarker · StyleMarker · EnumMarker · LocMarker
  • RequiredMarkers ——每份試算表都必須具備的那三個。
  • ReservedMarkers ——所有內建名稱。為自訂標記命名之前,請先查看這份清單:衝突會在註冊時被拒絕。

分隔符

  • ListSeparator;)——用在清單元素之間。
  • EntrySeparator,)、FieldSeparator:)、SectionSeparator|)、KeyTimeSeparator@)——這些是單一值內部的層級,這也是為什麼 ; 絕不會出現在某個值自己的文字之中。
  • StyleKeyValueSeparator=)——用於 @style 儲存格內部。

@type 記法

  • OptionalSuffix?)· DefaultSeparator=)· TargetSeparator@,如 RecordId@Tab 中那樣)。
  • ListTypeName · ListOpenList<)· ListClose>)。

型別名稱

  • 每個內建名稱各對應一個常數:IntTypeName · FloatTypeName · BoolTypeName · StringTypeName · RecordIdTypeName · IntIdTypeName · AssetRefTypeName · LocRefTypeName · ColorTypeName · AnimationCurveTypeName · GradientTypeName · EnumTypeName
  • BuiltinScalarTypesIsBuiltinScalarTypeName(name)——「這個名稱是否已經是內建的?」,會在某個剖析器以這個名稱註冊之前就先給出答案。
  • StyleKeyNamestitlecolor)· LocReservedColumnssmartcomment)。

  • TrueCanonical / FalseCanonical ——標準的 bool 文字。
  • NumberCellStyles ——讀取每個數值儲存格時所用的 NumberStyles。千分位分隔符會被排除,文化特性(culture)永遠固定不變(invariant),因此某個地區習慣的小數點逗號會直接、明顯地失敗,而不是悄悄地把數值改掉。

領域驗證(SheetForge.Core.Validation

型別角色與關鍵成員
IDomainValidator跨欄/跨分頁規則。違規事項 → 以 DomainRuleViolation 的形式進入 ctx.Errors,並附上全部 4 個要素。string Name · Validate(DomainValidationContext)
DomainValidationContextTables(分頁 → SheetTable) · KeyIndices · AssetKeys(null = 已略過) · Errors

邊介面縫隙(SheetForge.Core.Validation / .Edges

型別角色與關鍵成員
ReferenceScanner(靜態)列舉參照出現位置的唯一真實來源。Scan(tables) · ScanTable · ScanField · IsReferenceField(TypeToken),另外兩個參照判斷式詳列於表格下方
RefKeyKind(enum)一項參照比對的是字串(RecordId)鍵值空間,還是整數(IntId)鍵值空間。由 ReferenceScanner.GetReferenceKind 回傳;使用端依此分流。僅供附加
ReferenceOccurrence(結構)一次出現——Kind · FromTab · RowNumber · ColumnNumber · FieldName · TargetTab · TargetId · ToCoordinate()
ReferenceOccurrenceKind(enum)Scalar · ListElement · ExplicitDefault · WrapperElement · CustomElement(一個由 IRefBearingValue 從自己的記法中宣告出來的參照——座標為儲存格層級,因為內部的排列方式歸該型別所有)。僅供附加,因此既有的值仍維持原意
IEdgeContributor宣告掃描器看不到的邊。不提供診斷資訊。string Name · ContributeEdges(EdgeContributionContext, ICollection<EdgeSpec>)
EdgeSpec一條邊——FromTab/FromRecordId/ToTab/ToRecordId(+ 選填的 FieldName,記錄邊專用的 PayloadTab/PayloadRecordId,以及 Label
EdgeContributionContext唯讀的 Tables + KeyIndices(沒有錯誤蒐集器——邊不是驗證行為)
IAuthorableEdgeContributor一項選用能力IEdgeContributor 也可以額外實作它,讓自己的邊能在圖形畫布上被編輯。bool TryPlanConnect(EdgeAuthoringContext, fromTab, fromRecordId, toTab, toRecordId, out EdgeCellWrite) · bool TryPlanDisconnect(EdgeAuthoringContext, RecordEdge, out EdgeCellWrite)——false = 不會暫存任何內容,且該項功能會被停用並附上原因;兩者皆於 try/catch 中執行
IEdgeTokenEditor一項選用能力IEdgeContributor 也可以額外實作它,讓其 token 中的殘留部分(除鍵值以外的一切)能在連線檢閱器中被編輯。bool TryDescribeToken(EdgeAuthoringContext, RecordEdge, out EdgeTokenDescription) · bool TryPlanSetModifier(EdgeAuthoringContext, RecordEdge, string newModifier, out EdgeCellWrite)——兩者都讀取同一個儲存格(一條邊知道自己指向哪裡,但不知道自己今天是以什麼文字寫成的),false = 該列會被隱藏或誠實地停用;兩者皆於 try/catch 中執行
EdgeTokenDescription描述一個 token 是什麼,以及如何編輯其殘留部分——TokenText(要醒目標示的片段) · ModifierText · HasModifier · ModifierLabel · IsChoice · Options / OptionLabelsnew EdgeTokenDescription(tokenText) = 沒有殘留部分,因此不會繪製該列;當選項清單為空時,選擇型建構子會回退為自由文字
IBatchAuthorableEdgeContributor一項選用能力,是 IAuthorableEdgeContributor 的同層介面(並非繼承關係):將連結/取消連結的計畫表示為一份儲存格寫入的清單,適用於一個手勢必須同時變更多個成對儲存格的資料。bool TryPlanConnectMany(EdgeAuthoringContext, fromTab, fromRecordId, toTab, toRecordId, out IReadOnlyList<EdgeCellWrite>) · bool TryPlanDisconnectMany(EdgeAuthoringContext, RecordEdge, out IReadOnlyList<EdgeCellWrite>)——整份清單會以一個復原步驟暫存,要嘛全部成功、要嘛全部不執行;單數形式的貢獻者依然可以正常運作(作為後備方案),當一個類別同時實作兩者時,批次形式優先
IVirtualNodeFactory一項選用能力:並非新增一列試算表資料的畫布「建立」手勢。IReadOnlyList<VirtualNodeKind> KindsFor(EdgeAuthoringContext, tab, recordId)(每次組建選單時都會呼叫——請保持輕量) · bool TryPlanCreate(EdgeAuthoringContext, tab, recordId, VirtualNodeKind, out IReadOnlyList<EdgeCellWrite>)——false = 工作階段不受任何影響。一項計畫不能以同一手勢中剛建立的記錄為目標
VirtualNodeKind(結構)一種可建立的種類——Id(挑選時會原樣回傳) · Label(已翻譯好的選單文字;/ 代表巢狀子選單) · IsUsable。對 null 安全,對 default 也安全
IEdgeSlotDeclarer一項選用能力:一個(虛擬)節點無需有一條現存的邊即可開啟的連接埠。IReadOnlyList<DeclaredSlot> DeclareSlots(EdgeAuthoringContext, nodeTab, nodeRecordId)——已宣告的連接埠會加入連結選單、連接埠選取器,以及卡片自己的連接埠列;每次繪製都會被呼叫,因此實作必須輕量且不能有副作用
DeclaredSlot(結構)一個已宣告的連接埠——FieldName(同一節點內須唯一;必須與貢獻者所繪邊的 FieldName 相符,連線才能定錨) · TargetTab · IsList · IsUsable。對 null 安全,對 default 也安全
EdgeAuthoringContext規劃時的輸入資料——Tables + string CellText(tab, recordId, field),會回傳該儲存格目前的內容(baseline 加上暫存),因此同一手勢中連續建立的兩個連結能夠彼此看見對方
EdgeCellWrite(結構)這份計畫:TabName · RecordId · FieldName · NewRawText(空白 = 清除) · IsAddressable。以鍵值定址,而非列號

ReferenceScanner——兩個參照判斷式:

  • GetReferencedTab(TypeToken)——每個使用端都會問的單一判斷式:「這是不是參照、指向哪裡」。它能回答 RecordId@TabIntId@Tab(整數鍵值空間)、wrapper 內部,以及標記了 IsCustomReference 的自訂型別。這正是為什麼一次選用——對 IntId@Tab 而言,則是這個判斷式的一次擴展——就能將它們全部一併開啟。
  • GetReferenceKind(TypeToken)RefKeyKind——這項參照比對的是字串鍵值空間,還是整數鍵值空間,讓重新命名傳播、下拉選單與選取器能夠正確分流。
  • GetReferenceKind(TypeToken, tables)——具備資料表感知能力的多載版本。

一個核心參照會自行說明自己所屬的空間(RecordId / IntId)。一個參照型自訂型別沒有記法可以表達這一點——MyType@Tab 是唯一的寫法——因此它所屬的空間是從目標分頁自身的身分推導而來:RecordId 自我鍵值代表字串空間,單獨的 IntId 代表整數空間,未知的分頁或 null 的 tables 則回退為字串空間,這與僅有 token 的多載版本所給出的答案相同。正是這項推導,讓一個既有的 IReferencingCellType 實作,能夠在不改動一行程式碼的情況下,指向一個以 IntId 為鍵值的分頁。

參照圖形索引(SheetForge.Core.Edges

一份不可變的快照,將核心掃描到的參照與貢獻者所提供的邊合併為單一模型,並雙向建立索引。它只是顯示用的素材——絕不會產生任何診斷資訊(投影結果的 Diagnostics 才是問題的唯一真實來源)。

型別種類角色與關鍵成員
RecordEdge(結構)value一條邊。RecordEdgeOrigin Origin · FromTab · FromRecordId(欄位層級的邊為空白) · FieldName · RowNumber / ColumnNumber(從 1 開始;0 = 欄位/分頁層級) · ToTab · ToRecordId(即使無法解析,也是原本意圖指向的 id) · bool IsDangling(於組建時就固定) · Label · PayloadTab / PayloadRecordId(記錄邊)
RecordEdgeOrigin(enum)CoreReference(讀取自 RecordId@Tab 儲存格——具有座標) · Contributor(由 IEdgeContributor 宣告——記錄層級)
ReferenceIndexsealed class此快照。靜態 Build(tables, keyIndices, contributorEdges, codeRegistries, extraKeys = null)(後三者可為 null;extraKeys = 分頁 → 已存在但尚未剖析的鍵值,例如編寫介面剛暫存的列,因此指向它們的連結不會被畫成失效狀態) · AllEdges(具決定性的順序:來源分頁 Ordinal → 列 → 欄 → 出現方式) · OutEdges(tab, recordId) / InEdges(tab, recordId)(絕不為 null) · int InCount(tab, recordId) · bool TryGetRowKey(tab, rowNumber, out recordId) · DanglingEdges

Data Studio 記錄畫布(SheetForge.Core.Graphing

畫布會自行決定要繪製什麼:它會從你開啟的記錄(終點)出發,向外走訪參照索引,並以決定性的方式排列結果。外掛並不會取代這幅畫面——它只會在其上新增內容。全程皆為純粹的資料:欄位是網格儲存格,而非像素,顏色則是一個自由的 Category 字串,由視窗自行對應到調色盤。

型別種類角色與關鍵成員
IRecordCanvasAugmenter介面單一分頁的畫布覆寫,會在核心閉包組裝完成之後才被呼叫。Augment(GraphBuildContext, CanvasAugmentBuilder, string terminusTab, string terminusRecordId)。不新增任何內容,畫面就會維持核心原本的樣子;拋出的例外會被視窗攔截,並轉為一則英文的 Console 警告。身分歸屬於資料本身(虛擬節點若與相同鍵值的真實記錄衝突,會由真實記錄勝出);顯示提示則不受此規則約束
CanvasAugmentBuildersealed class這個寫入介面,僅有四件事可做——成員與規則詳列於表格下方
GraphShapeRegistrysealed class分頁名稱 → 畫布覆寫。Register(tabName, IRecordCanvasAugmenter)(重複分頁/空白名稱/null 皆會拋出例外) · TryGet · IsEmpty
GraphBuildContextsealed class此覆寫的唯讀輸入資料。Tables(分頁 → SheetTable) · ReferenceIndex References · IReadOnlyList<CodeRegistrySource> CodeRegistries(空清單,絕不為 null)。沒有錯誤蒐集器——畫布是顯示用途,而非驗證
GraphSpecBuildersealed class圖形組裝輔助工具。建構子 (GraphBuildContext) · 靜態 NodeKey(tab, recordId)(連線所指向的唯一真實依據) · AddNode(GraphNodeSpec)(第一個 (Key, Column) 勝出) · AddWire(GraphWireSpec) · AddWire(fromKey, toKey, label, fromTab, fromRecordId, fieldName, isCyclic = false, cyclicNote = null)(此多載同時指名這條連結是寫在哪個儲存格中,這正是讓連線得以被編輯的關鍵)
GraphSpecsealed class畫布所繪製、組裝完成的結果——Nodes · Wires(組裝需經由建構工具完成;建構子為 internal)
GraphNodeSpecsealed class一個節點。Key · Tab · RecordId · Title · Subtitle · Category · CellCoordinate Address · Column / Row(畫布早已解算好的網格儲存格——此處只是承載,而非決定) · IsFocus(終點) · IsMissing · InCount · IsCyclic
GraphWireSpecsealed class一條連線。FromKey · ToKey · Label · IsCyclic · CyclicNote,加上選填的所屬儲存格:FromTab · FromRecordId · FieldName · RecordEdge? SourceEdge(null = 純顯示用連線;畫布會因此表示它無法被編輯)。五個顯示用參數維持不變,因此既有呼叫仍能正常編譯並呈現相同結果
IAuthorableGraphShape介面一項選用能力IRecordCanvasAugmenter 也可以額外實作它。IReadOnlyList<string> CreatableTabs(GraphBuildContext, string tabName)——畫布可以在哪裡建立記錄(空清單 = 任何地方都不行)。若未實作,其預設行為詳列於表格下方

CanvasAugmentBuilder——寫入介面。 僅有四件事:

  • AddNode(tab, recordId, title = null, category = null) / AddNode(tab, recordId, title, category, CellCoordinate address)——為並非試算表記錄的身分(一個事件鍵值、一個程式碼原子)新增一個虛擬節點;分頁可以留空。
  • AddEdge(fromTab, fromRecordId, toTab, toRecordId, label = null, fieldName = null, fieldOnTarget = false, isCyclic = false, cyclicNote = null)——核心掃描器看不到的額外邊。指名 fieldName 代表這條連結是寫在哪個儲存格中,fieldOnTarget 代表該儲存格位於到達端而非出發端,循環相關的參數則會將一個迴圈標示為顯示用,並附上只有該領域才知道的說明。
  • SetLayer(tab, recordId, layer)——一個絕對圖層提示(0 = 最左側,負數則更靠左,其餘一切都會相應向右位移)。SetLayerRelative(tab, recordId, offset)——同樣的概念,但以終點為基準計數(−1 = 終點左邊一欄),並在任何提示移動它之前,就先對照終點欄位解析完畢。
  • SetSubtitle(tab, recordId, subtitle)——一個顯示提示,是唯一一項會套用到已存在的記錄、以及畫面外記錄(連結選取器會讀取這些)的內容。

鍵值為空的項目會被忽略;已蒐集的內容屬於內部實作,因為合併規則統一存放於單一位置。每一次功能擴充都是尾端追加的,因此針對舊版介面撰寫的覆寫,仍然能夠正常編譯。

IAuthorableGraphShape——若未實作,兩個預設行為:

  • 這項能力所取代的可建立分頁清單軸線——它同時也決定畫布是否會開啟、以及待處理列掃描的範圍——會依循結構描述、遞移地涵蓋從焦點分頁可以到達的每一個分頁。
  • 使用者實際看到的連結串聯,則是從畫面上目前已繪製的連接埠所指向的分頁開始。

兩者皆會排除程式碼註冊表的分頁,以及沒有鍵值欄的分頁。此方法回傳、但沒有任何已繪製連接埠接受的分頁,仍會留在連結串聯清單中並附上原因,而非直接消失,且視窗自身的把關機制依然會在其上額外套用。

色彩預設集(SheetForge.Core.Theming

型別角色與關鍵成員
ThemeRegistry預設集 id → 主題。空白 id、重複 id,以及兩個保留的內建 id 皆會拋出例外。Register(SheetForgeTheme) · TryGet · Themes · IsEmpty · IsBuiltInId(id) · BuiltInDefaultId · BuiltInHighContrastId
SheetForgeTheme一個色彩預設集。Id · DisplayName · DarkColors / LightColorsIReadOnlyDictionary<ThemeColorSlot, uint>,於建構時複製) · TryGetColor(dark, slot, out rgb) · IsEmpty
ThemeColorSlotenum——一個預設集可以覆寫的 33 種顏色角色(表面、線條、文字、語意色彩、暫存標記、失敗狀態表面、遮罩、圖形)。顏色皆為 0xRRGGBB:Core 不參照任何引擎型別,半透明填色則是由插槽顏色加上一個固定的透明度推導而來。僅供附加。

一個預設集只會覆寫它所指名的插槽;其餘所有插槽都會維持產品預設值,因此即使日後新增更多插槽,既有的預設集依然有效。註冊本身絕不會套用該預設集——使用者需自行在 Preferences ▸ SheetForge ▸ Theme 中挑選。

宣告式編寫介面(SheetForge.Core.Studio

一個外掛描述的是要顯示什麼——外殼是資料,判斷式與效果則是委派——各主機各自以自己的元件繪製它:編輯器用 UIToolkit,瀏覽器用 React。任何地方都不會出現版面配置數值。要說什麼是外掛的職責,怎麼擺放則是渲染器的職責。

這裡的每一個 enum 都僅供附加,因此隨著詞彙表成長,一項既有的註冊仍會維持原意。

型別種類角色與關鍵成員
StudioUiRegistrysealed classRegisterStudioUi 所填入的內容。AddAction(StudioActionDescriptor) · AddPanel(StudioPanelDescriptor) · AddColumnBadge(StudioColumnBadgeDescriptor) · AddCellEditorHint(StudioCellEditorHint) · Actions / Panels / ColumnBadges / CellEditorHints · IsEmpty
StudioUiNodesealed class一個已描述的片段,不可變,透過靜態工廠方法建構——工廠方法、可讀屬性與網址規則詳列於表格下方
StudioUiNodeKindenum上述 13 種種類(RowLink
StudioActionDescriptorsealed class一個動作。Id(唯一) · LabelKey(一個 Loc 鍵值;未註冊則逐字顯示) · StudioActionPlacement Placement · Func<StudioSurfaceContext,bool> AppliesTo · Action<StudioSurfaceContext> Execute · ConfirmKey(選填——主機會先詢問這句話)。主機會在呼叫時重新檢查 AppliesTo,因此一個過時的選單項目會以一次誠實的無動作加上重繪來回應
StudioActionPlacementenumInspector · RowContextMenu · TopbarMenu · ColumnHeaderMenu · CanvasNodeMenu。每個位置會填入不同的情境欄位——列的位置帶有該筆記錄,欄的位置帶有欄名稱,畫布的位置帶有該節點的記錄
StudioPanelDescriptorsealed classStudio 右側窗格中的一個面板。Id · TitleKey · Func<StudioSurfaceContext,StudioUiNode> Build——每個重新計算的時刻都會重建,因此它不持有任何狀態。沒有任何面板註冊時,該窗格完全不會被繪製
StudioColumnBadgeDescriptorsealed class一個欄標頭旁的徽章。Func<StudioSurfaceContext,string,string,StudioUiNode> Provide(情境、分頁、欄位)——null 代表該欄上沒有任何內容
StudioCellEditorHintsealed class「對這個型別使用這個內建元件」——挑選一種種類,而非自行提供一個。TypeName(一個精確的 CellParserRegistry 型別名稱;清單儲存格會依其元素名稱比對;wrapper 儲存格則保留標準文字,絕不會被比對) · StudioCellEditorArchetype Archetype · GetOptions(僅限下拉選單——Func<context, tab, field, IReadOnlyList<StudioCellOption>>) · SliderMin / SliderMax · ToggleTrueValue / ToggleFalseValue。四個建構子,每種素材形態各一個。會在一個已註冊的 IStudioCellEditorProvider 選擇拒絕之後、且在內建分支之前被查詢;一個套件的提示,會在下方所述的內建提示之前被查詢,因此在 ColorAnimationCurveGradient 之下註冊一個提示,會覆寫該型別的預設編輯器。一個元素提示為 ColorPickerCurveEditorGradientEditorList<>,在兩個主機中都會變成晶片編輯器
StudioCellEditorArchetypeenumDropdown · MultilineText · Slider · Toggle · ColorPicker(儲存格文字為 #RRGGBB / #RRGGBBAA) · CurveEditor(儲存格文字=標準的 CurveValue 記法) · GradientEditor(儲存格文字=標準的 GradientValue 記法)。僅供附加——最新的兩個是 56
BuiltinCellEditorHints靜態類別Core 自身所宣告的三個提示——ColorColorPickerAnimationCurveCurveEditorGradientGradientEditor——與套件的提示走的是同一條路徑,因此編輯器與瀏覽器不可能為它們挑選出不同的元件。IReadOnlyList<StudioCellEditorHint> All(固定順序) · bool TryGet(typeName, out hint)(Ordinal 比對)。主機會優先查詢 StudioUiRegistry.CellEditorHints,再回退到這份對照表
StudioCellOptionsealed class一個下拉選單候選項——Value(寫入儲存格的標準文字) · Label(使用者所讀到的內容;預設等於 Value
StudioSurfaceContextsealed class一個擴充功能唯一能看見並藉此行動的介面縫隙。讀取:Tables · ReferenceIndex References · CodeRegistries · Tab · RecordId · Field · ActionArgument(一個 Input 節點所提交的值)。經過中介的變動,且僅此而已:Action<string,string,string,string> StageCell · Action<IReadOnlyList<EdgeCellWrite>> StageCells(一個 Undo 步驟,全有或全無) · Action<string,string> FocusRecord · Action RequestRebuild。暫存會經過視窗自己的把關機制,因此唯讀來源、正在執行的管線,或以活頁簿為來源的分頁,都會附上原因將其封鎖(建構子為 internal:由主機自行組裝)

StudioUiNode——工廠方法、讀取屬性與網址規則:

  • 工廠方法: Row · Label · Chip · Badge · Button · Rule · Heading · KeyValue · Table(headerRow, rows) · List · Progress · Input · Link,加上 WithTooltip(text)——它回傳的是一個節點,而非變更此節點。
  • 讀取屬性: Kind · Text · Tooltip · ThemeColorSlot? Tone(絕不是寫死的顏色,因此會跟隨主題) · ActionId · Detail · Ratio · Url · Children
  • 靜態 bool IsAllowedUrl(url)——僅限 httphttps。兩個主機共同詢問同一個判斷式,因此它們對於什麼是安全可開啟的,絕不會產生分歧。

外掛 UI 字串(SheetForge.Core.Model

型別角色與關鍵成員
StringOverlayRegistry外掛註冊 UI 字串的收集器查詢疊加層;Loc.Tr(編輯器端)與 t()(瀏覽器端)會在查詢產品對照表之前先查詢它。Register(key, language, value) · Register(key, IReadOnlyDictionary<string,string> byLanguage) · bool TryGet(key, language, out value) · RegisteredKeys。語言比對方式與四種拒絕情況詳列於表格下方

StringOverlayRegistry——比對方式與拒絕情況。 language 為 IETF 代碼("en""ko""zh-Hans""pt-BR"……等),比對時不區分大小寫。查詢順序為要求的語言 → 英文 → 未命中,這項回退邏輯就存放於此處,因此兩個主機才能給出完全相同的答案。

四種註冊會被拒絕,且每一種都會記錄一則面向開發者的原因,而非靜默失敗:

  • 一個產品內建鍵值——疊加層可以新增鍵值,但絕不能覆寫產品自己的句子或選單路徑;
  • 另一個套件已經註冊過的鍵值+語言組合——先找到的勝出,否則安裝順序就會決定畫面內容;
  • 空白的鍵值或值;
  • 一個產品不認得的語言代碼,絕不會被併入英文。

管線觀察(SheetForge.Core.Plugins / .Model

型別角色與關鍵成員
IPipelineObserver唯讀通知。void OnImportCompleted(PipelineRunView view)——每一次明確的匯入循環各執行一次,於其結束時,無論成功或失敗。這裡刻意沒有提供任何可以修改數值或新增診斷的掛勾(那些分別屬於一個儲存格型別,以及 IDomainValidator),也沒有任何會在暫存預檢上執行的掛勾。一次拋出會被隔離,原因會被收集;匯入的輸出結果不受影響。未來的觀察點會以同層能力介面的形式抵達,透過轉型已註冊的觀察者來取得,因此今天寫成的實作仍會繼續正常編譯
PipelineObserverRegistry僅供附加的觀察者清單,順序會被保留。Register(IPipelineObserver) · Observers
PipelineRunView一個觀察者所收到的不可變快照——Success(驗證結果,亦即是否組裝出一個登錄庫;程式碼產生/烘焙的結果則從診斷資訊中讀取) · Tables(已剖析的分頁;在一次失敗的執行中,只有無法剖析的分頁會缺席,因為「不會有部分組裝的結果」是一條輸出規則,而非觀察規則) · Diagnostics(與報告所顯示的是同一份清單) · SkippedTabs · EnumTabs。集合皆於建構時複製,且建構子為 internal,因此絕不會有一個尚未組裝完成的快照被交給觀察者

程式碼註冊表(SheetForge.Core.Graphing

存放於程式碼中的參照目標,會以鎖定的虛擬分頁形式,呈現在編寫介面上。這是供 Data Studio(側邊欄/圖形/檢閱器)使用的內容,並非供匯入驗證器使用。

型別種類角色與關鍵成員
CodeRegistryCatalogsealed class註冊的根節點。Register(CodeRegistrySource)(null/空白分頁名稱/重複分頁名稱皆會拋出例外) · TryGet(tabName, out source) · Sources · IsEmpty
CodeRegistrySourcesealed class一個鎖定的虛擬分頁。string TabName · IReadOnlyList<CodeRegistryEntry> Entries(註冊順序 = 顯示順序)
CodeRegistryEntrysealed class一個項目。string Key(參照可以指向的目標) · string Label · IReadOnlyList<string> Raises(null 會正規化為空清單)。Core 會將這三者皆視為不透明的字串

IR 讀取模型(SheetForge.Core.Model

型別角色與關鍵成員
SheetTable一個分頁的剖析輸出。SheetSchema Schema · IReadOnlyList<SheetRecord> Records
SheetSchemastring TabName · Fields · TryGetField(name, out FieldSchema) · SheetStyle Style(此試算表的 @style 顯示中繼資料) · bool IsLocalizationSheet(存在 @loc 標記) · IReadOnlyList<LocaleColumn> LocaleColumns(依原始欄序排列的語言欄——在並非在地化試算表的試算表上為空,且永遠不會是 null) · TryGetLocaleColumn(localeCode, out LocaleColumn)(依代碼查找,不分大小寫) · TryGetSourceLocale(out LocaleColumn)(第一個語言欄;一個都沒有時為 false
SheetStyle@style 列的值——單一試算表的顯示中繼資料。string Title(側邊欄群組標籤) · string ColorHex(依書寫原樣的 #RRGGBB) · bool HasColor · 靜態 None(不套用樣式)。程式碼產生、烘焙與結構描述指紋皆絕不會讀取它
LocaleColumn(結構)一份在地化試算表中的一個語言欄——@loc 列在該欄寫下的內容。string Code(完全依書寫形式呈現的代碼;Core 驗證的是拼寫形狀,而非該語言是否真實存在) · string FieldName · int ColumnNumber(從 1 開始) · bool IsSource(第一個語言欄——內嵌預覽讀取的、以及自動生成鍵值時寫入的那一欄)
SheetRecordint RowNumber(原始,從 1 開始)· Values(欄位 → CellValue)· TryGet · 索引子
FieldSchemaName · TypeToken Type · Description · ColumnNumber · DefaultValue · AllowOverlap · IReadOnlyDictionary<string,string> MarkerValues(自訂標記名稱 → 該欄的儲存格文字)
TypeToken已剖析的 @type 儲存格。RawText · TypeName · TypeArgument · TargetName · IsList · IsOptional · HasExplicitDefault · DefaultValueText · AllowsEmptyCell · IsSelfKey · IsIntId(僅代表此分頁自身的整數鍵值;IntId@Tab 這種參照形式,則是透過 TargetName + ReferenceScanner.GetReferencedTab 讀取,與 RecordId@Tab 的方式相同) · TypeToken InnerToken / IsWrapper(wrapper 型別——遞迴式內部型別) · IsCustomReference(此欄為 MyType@Tab,且該剖析器有實作 IReferencingCellTypeReferenceScanner.GetReferencedTab 是讀取此旗標的唯一判斷依據,這也是為什麼每個使用端都能在不變更簽章的情況下自動生效) · AssetTypeNameAssetRef@Group<Type> 中所寫的 <Type>;不受限時為 null;Core 只會儲存這個名稱——解析它是 IAssetTypeResolver 的職責——且它同樣會被標記在清單或 wrapper 內部的 AssetRef token 上)。建構子最後三個參數(innerTokenisCustomReferenceassetTypeName)皆有預設值,因此既有呼叫仍能正常編譯,較早期的 8 參數與 10 參數建構子則以多載形式保留,因此已編譯完成的外掛組件不需要重新編譯就能繼續運作
CellValue(結構)一個具型別的儲存格值;沒有 null(IsDefaulted 標示已實體化的預設值)。object Value · IsDefaulted · AsList · 靜態 Of / Defaulted
RecordId(結構)一個鍵值(Ordinal 相等比較)。string Value · IsEmpty
RecordRefValue(結構)一個 RecordId@Tab 儲存格的值。TargetTab · Id
IntRefValue(結構)一個 IntId@Tab 儲存格的值——RecordRefValue 的整數鍵值版本。string TargetTab · int Id · bool IsEmpty · 靜態 Empty(tab)(一個指向空無一物的選填 IntId@Tab?
LocRefValue(結構)一個 LocRef@Tab 儲存格的值——RecordRefValue 的在地化版本,之所以保留為獨立型別,是為了讓消費端單看這個值就知道它指向一張字串表。string TargetTab · string Key · bool IsEmpty · 靜態 Empty(tab) · ReferencedKeys。它實作了 IRefBearingValue,因此參照掃描器對待它的方式與對待核心參照完全相同
AssetRefValue(結構)一個 AssetRef@Group 儲存格的值。Group · Key(子資源的鍵值為 parent[sub]
EnumValue(結構)一個 Enum<T> 儲存格的值(字串配對——CLR 轉換是烘焙階段的工作)。EnumName · MemberName

型別化資源參照(SheetForge.Core.Model

AssetRef@Group<Type> 中的 <Type> 是由主機負責解析的——Core 既不認識引擎,也不認識專案的組件——Core 只會對解析的結果進行判斷。這裡的一切都是純粹的資料。

型別種類角色與關鍵成員
IAssetTypeResolver介面AssetTypeResolution Resolve(string rawName)——輸入一個名稱,輸出一個判定結果;同一個名稱永遠會得到相同的答案(實作可以自行快取)。它會獨立於 AssetKeyIndex 被注入 ImportPipeline 中,因此即使專案尚未擁有 Addressables 設定,型別名稱依然能夠被解析;若沒有注入任何解析器(無頭模式、瀏覽器),型別名稱相關的診斷資訊就單純不會被產生。Editor 的實作會依專案已載入、衍生自 UnityEngine.Object 的資源型別進行解析(沒有允許清單;元件與僅限編輯器使用的型別皆被排除)
AssetTypeResolutionsealed class單一名稱的判定結果——RawName · AssetTypeResolutionStatus Status · FullName(CLR 完整名稱,巢狀型別以 + 表示;僅限 ResolvedNotReferenceable) · AssemblyName(產生的附屬組件必須參照的組件;組件定義型別會設定此值,引擎模組與未解析的名稱則為 null) · Candidates(絕不為 null:名稱有歧義時的候選型別,或名稱未知時的最接近候選建議)。工廠方法 Resolved(raw, fullName, assemblyName) · Unknown(raw, suggestions) · Ambiguous(raw, candidates) · NotReferenceable(raw, fullName, assemblyName)
AssetTypeResolutionStatusenumResolved · Unknown(不存在這個型別) · Ambiguous(短名稱與多個型別相符——請寫出完整名稱) · NotReferenceable(該型別位於像 Assembly-CSharp 這樣的預先定義組件中,產生的程式碼無法參照它)

程式碼產生器會讀取管線所產生的已解析對照表,並為已解析的名稱輸出 AssetReferenceT<global::FullName>;一個在該對照表中找不到的名稱,絕不會被逐字輸出——該欄位會回退為 AssetReference,並蒐集一則 AssetTypeUnresolvedFallback 警告。已解析的完整名稱同樣會被納入結構描述指紋中。

視覺數值型別(SheetForge.Core.Model

三種內建視覺型別的無引擎依賴數值模型。每一個都是不可變的、實作 IEquatable,並各自擁有自己的文字形式(TryParse / Render)——與試算表語法頁面所記載的記法相同——因此一個儲存顏色、曲線或漸層的外掛型別,可以直接重複使用它們,不必自創第二套記法。Editor 會將它們烘焙進 UnityEngine.Color / AnimationCurve / Gradient,並讀回它們;瀏覽器則透過下方的取樣器對它們取樣,而不必重新實作其中的數學運算。

型別種類角色與關鍵成員
ColorValuereadonly struct四個位元組 R · G · B · A · static Default#00000000) · static TryParse(text, out value, out error)(接受 #RGB / #RGBA / #RRGGBB / #RRGGBBAA) · Render()(不透明時為大寫、六位數字)
CurveValuesealed classKeys(依時間遞增排序) · PreWrap / PostWrap · static Empty(沒有任何關鍵影格——唯一沒有文字形式的狀態;Render() 會回傳 "") · static Create(keys, preWrap, postWrap)——唯一的建構路徑:依時間排序、拒絕重複的時間點,並套用 CurveTangentSolver,讓「模式優先」這件事從曲線誕生的那一刻起就成立 · static TryParse(2/4/7/8 欄位的關鍵影格,Once 會被接受為 ClampForever 的別名,切線可為 Infinity/-Infinity) · Render()(8 欄位的關鍵影格,只有在需要時才會加上包裹後綴)
CurveKeyreadonly structTime · Value · InTangent · OutTangent · InWeight · OutWeight · CurveWeightedMode WeightedMode · CurveTangentMode LeftMode / RightMode · bool Broken;一個十參數的建構子,本身不做任何正規化
CurveWrapenumClampForever · Loop · PingPong · Default——依名稱對應 Unity 的包裹詞彙(對應到 WrapMode 數值的轉換工作屬於烘焙器)
CurveTangentModeenumFree = 0 · Auto = 1 · Linear = 2 · Constant = 3 · ClampedAuto = 4——名稱與數值皆與 AnimationUtility.TangentMode 相同,因此烘焙器依名稱對應,絕不會直接碰觸 Unity 內部封裝的切線位元
CurveWeightedMode[Flags] enumNone = 0 · In = 1 · Out = 2 · Both = 3——代表一個關鍵影格的哪一側使用加權(貝茲)切線
CurveTangentSolver靜態類別CurveKey[] Apply(IReadOnlyList<CurveKey> sortedKeys)——依模式推算出切線數值,並依引擎的順序套用各個階段(Linear 各自處理自己那一側 → ClampedAuto 兩側一起處理 → Auto 兩側一起處理 → Constant 各自處理自己那一側),Free 的一側與權重則維持不動。CurveValue.Create 會呼叫它,因此呼叫端很少需要自行呼叫
CurveEvaluator靜態類別float Evaluate(CurveValue, float time) · float[] Sample(CurveValue, int count)count ≥ 2,從第一個關鍵影格到最後一個平均分佈取樣點)——關鍵影格之間採 Hermite 插值,權重旗標有設定的一側採加權貝茲插值,切線為無限值時維持定值,並在關鍵影格範圍之外套用四種包裹行為;已針對隨機曲線與 AnimationCurve.Evaluate 進行過比對驗證
GradientValuesealed classColorKeys · AlphaKeys(各 1 到 8 個,依時間遞增排序) · GradientBlend Mode · GradientColorSpace ColorSpace · static Default(白色、完全不透明、Blend) · static Create(colorKeys, alphaKeys, mode, colorSpace)(驗證數量與 0…1 範圍,依 Unity 的方式將時間量化為 16 位元,並以穩定排序排列) · static TryParse(三或四個以 `
GradientColorKeyreadonly structColorValue Color(Alpha 會被忽略——Alpha 有自己專屬的關鍵影格) · float Time
GradientAlphaKeyreadonly structfloat Alpha · float Time
GradientBlendenumBlend · Fixed · PerceptualBlend
GradientColorSpaceenumUninitialized(未寫入時;讀取時視為 Gamma) · Gamma · Linear——只有 PerceptualBlend 會受影響
GradientEvaluator靜態類別ColorValue Evaluate(GradientValue, float time) · ColorValue[] Sample(GradientValue, int count)——線性、階梯,或感知(Oklab)混合,Alpha 關鍵影格則獨立混合,再四捨五入為位元組;已針對隨機漸層與 Gradient.Evaluate 進行過比對驗證

錯誤與結果(SheetForge.Core.Model / .Reporting

型別角色與關鍵成員
ImportError結構化、與地區設定無關的錯誤。Code · Severity · Coordinate · ActualValue · Expected · Suggestion
ImportErrorCode(enum,105)完整的「為什麼」目錄——其涵蓋的家族詳列於表格下方。僅供附加——渲染器對照表是依成員值來對應的
ImportSeverity(enum)Error(阻擋輸出) · Warning
CellCoordinate(結構)分頁 · 從 1 開始的列 · 從 1 開始的欄 · 欄位;會計算試算表的欄字母。ForTab / ForRow 建構工廠
ErrorCollector蒐集一切的接收器。All · HasErrors · ErrorCount · Add
ImportResult管線輸出。不變條件:Success == false ⇔ Registry == nullSuccess · Registry · Diagnostics · SkippedTabs · EnumTabs(被讀取為 enum 定義試算表、因而絕不會被剖析為資料表的分頁——與 SkippedTabs(代表「尚無資料表寫入」)分開存放,讓報告中的略過數量維持真實;兩者皆屬於保留集合,會為那些分頁保留產生的程式碼、烘焙後的資源與位址) · 靜態 Succeeded / Failed
ImportReport.Reporting,組件為 SheetForge.Core.Tooling報告渲染器的輸入——Timestamp · SourceDescription · TabCount · RecordCount · Success · Diagnostics · ErrorCount · WarningCount · SkippedTabCountTabCount 之中,有多少是因為空白而被略過、而非真正被匯入的試算表——標頭會將其印出,避免分頁數量被誤認為「全數匯入」)
ImportReportText.Reporting,組件為 SheetForge.Core.Tooling,靜態)將一份報告渲染為產品自己人類可讀的字串,不會寫入任何 Console 內容,也不會附加跳轉連結或供機器讀取的座標行(那些屬於 Console 自己的慣例)。string Render(ImportReport report, IReadOnlyDictionary<string,string> languageTable = null, string operationName = null)——英文版本可省略對照表;若省略操作名稱,則會從同一份對照表中讀取,因此句子絕不會混雜兩種語言。編輯器端的呼叫端通常會需要 SheetForgeActions.RenderReportText(report),它會自動代入目前的編輯器語言(純組件無法讀取 EditorPrefs

ImportErrorCode——其涵蓋的家族:

  • 標記、結構描述、型別、儲存格、鍵值/參照,以及資源鍵值;
  • 來源/檔案、csv/xlsx、程式碼產生識別碼、addressables、baseline/匯出、Google/驗證/推送,以及範本;
  • 外掛——PluginRegistrationConflict,以及當一個組件的相容性宣告超出此主機所能讀取的範圍時的 PluginIncompatible
  • IntId——DuplicateIntId,以及 IntId@Tab 參照專用的 UnresolvedIntId · TargetTabHasNoIntId
  • @overlapDomainRuleViolation
  • enum 定義試算表——EnumSheetMarkerConflict · DuplicateEnumName · EnumSheetEmptyColumn · InvalidEnumIdentifier · InvalidEnumUnderlyingType · InvalidEnumMemberValue
  • DropdownNotSupportedByFormat,這是一則警告而非錯誤;
  • 型別化資源參照——UnknownAssetType · AmbiguousAssetType · AssetTypeNotReferenceable(每欄各一次,位於 @type 列上)、逐儲存格的 AssetTypeMismatch,以及程式碼產生的警告 AssetTypeUnresolvedFallback

索引與工具程式(SheetForge.Core.Validation / .Model / .Parsing / .Unparse

型別角色與關鍵成員
TabKeyIndex一個分頁的鍵值資訊——字串鍵值欄,加上該分頁的 IntId 整數鍵值集合,因此 RecordId@TabIntId@Tab 兩種參照都能依此解析。TabName · KeyField · HasKeyColumn · Keys · Contains(id)
KeyIndexBuilder(靜態)建構鍵值索引(字串鍵值與 IntId 整數鍵值集合,一次完成)、回報鍵值錯誤、驗證 IntId 欄。Build(SheetTable, ErrorCollector) · ValidateIntIdColumns
AssetKeyIndex群組 → 有效鍵值集合(由 Editor 從 Addressables 目錄填入,含子資源鍵值;注入 null = 略過資源驗證)。Register(group, keys) · HasGroup · HasKey · KeysOf · GroupNames,另外還有供 AssetRef@Group<Type> 使用的型別層:RegisterTyped(group, key, satisfiedTypeFullNames)(該鍵值加上它可被載入為的完整型別名稱閉包——包括它自身的型別、基底型別、介面,以及其子資源的型別;重複註冊會將閉包聯集起來) · HasTypeInfo(group, key) · SatisfiesType(group, key, typeFullName)。以純粹的 Register 註冊的鍵值沒有閉包,會被豁免於型別檢查之外,而不是判定為失敗
LocalizationCoverage(靜態)一份在地化試算表依語言計算的涵蓋率與孤兒鍵值。這是一項純粹的計算,它回傳清單而不是收集錯誤,因為未翻譯的儲存格與沒人使用的鍵值都是正常狀態,而非需要攔下的出口。IReadOnlyList<LocaleCoverage> Compute(SheetTable) · IReadOnlyList<string> FindOrphanKeys(locTabName, tables)(沒有任何地方指向的鍵值;此處刻意保守——掃描器認得的每一種參照形式都算作一次使用,因此仍在使用的翻譯永遠不會被稱為孤兒)
LocaleCoverage(sealed 類別)單一語言的涵蓋率。LocaleColumn Locale · int TotalKeys · int TranslatedKeys · IReadOnlyList<string> MissingKeys(依試算表的列序排列,永遠不會是 null) · bool IsComplete
TextSuggestion(靜態)最接近的候選建議(有界的 Levenshtein 演算法,具決定性)。FindNearest · Distance · DistanceWithin
BuiltinCellParsers(靜態)CreateDefaultRegistry()——12 種內建剖析器(intfloatboolstringEnumRecordIdAssetRefIntIdLocRefColorAnimationCurveGradient)。
CanonicalValueRenderer(靜態)數值 → 標準儲存格字串(匯出/推送)。TryRender(…)(會將 ColorValue / CurveValue / GradientValue 委派給它們自己的 Render();沒有任何關鍵影格的曲線會被渲染為空白儲存格) · RenderFloat(float)(最短往返格式)

推送計畫(SheetForge.Core.Unparse

之所以公開,是因為 IPushApprover.Approve(PushPlan) 會公開它們;屬於純粹的資料。

型別角色
PushPlan(組件為 SheetForge.Core.Tooling,以下三列亦同)整個傳送計畫。Tabs · HasWork
PushTabPlan單一分頁:Writes · Appends · Deletes(鍵值 + 列號;DeleteNotices 仍保留為僅含鍵值的檢視)
PlannedCellWrite一次儲存格寫入——座標、baseline 儲存格、新的值/文字、字串家族旗標
PlannedRowAppend一次列附加——完整的儲存格文字 + 字串家族欄位

Editor 組件(SheetForge.Editor

設定、在地化、組合(SheetForge.Editor.Pipeline / .Localization

型別角色與關鍵成員
SheetForgeSettings(SO)設定資源。欄位:sourceProviderId(唯一的來源選擇軸;空值 = 內建 LocalFile) · localFolderPath · bakeOutputFolder · generatedCodeFolder · generatedNamespace · exportFolderPath · exportFormat · spreadsheetId · googleAccessMode · serviceAccountKeyPath · gidMapGidMapEntry { tabName, gid } 的清單)。Effective* 已解析屬性。
Loc(靜態)在地化的進入點。Tr(key) · TrContent(…) · Table · MenuRoot 常數。Tr 依序經過四個步驟解析:外掛註冊的字串(先目前語言,再退回英文——這項回退邏輯由疊加層本身負責,見 StringOverlayRegistry) → 內建對照表(先目前語言,再退回英文) → 鍵值本身。外掛字串恰好只有一條註冊通道,因此「哪一個註冊會勝出」絕不會成為一個問題
PluginRegistry(靜態)透過 TypeCache 偵測外掛,並將候選型別交給 PluginComposition.ComposeBuild · BuildValidators · BuildEdgeContributors · BuildStructuralMarkers · BuildTemplates · BuildGraphShapes · BuildCodeRegistries · BuildThemes · BuildAll(整合套組) · InvalidateCache()(清除重新載入期間有效的快取——與 SourceProviderRegistry.InvalidateCache 相同的慣例;同時也會清除相容性關卡自己的快取,因此發現集合一旦改變就會被重新判斷)。套件組合與插槽隔離機制詳列於表格下方
ImportEvents(靜態)Editor 端的事件匯流排——一個公開合約:外部素材可以訂閱它。event Action<ImportCompletedArgs> ImportCompleted · RaiseImportCompleted(ImportCompletedArgs) 只會在一次匯入完整跑完烘焙時觸發,因此訂閱者可以讀取烘焙後的資源。event Action<BaselineUpdatedArgs> BaselineUpdated · RaiseBaselineUpdated(BaselineUpdatedArgs) 則會在每次試算表快照被儲存時觸發——包括驗證失敗的一次執行——這正是一個編寫介面在隔離匯入發生時用來重新整理畫面的方式。兩條軸線刻意不合併:一條代表「試算表變動了」,另一條代表「資源變動了」
BaselineUpdatedArgs(sealed)Baseline 儲存事件的負載。IReadOnlyList<string> Tabs(寫入這次快照的分頁) · bool Quarantined(這次剛儲存的快照,其驗證是否失敗)
SheetForgeActions(靜態)這個執行外觀——與選單點擊執行的是同一套週期,可從 CI 指令碼、建置掛勾,或你自己的按鈕呼叫。RunImport() · RunExport() · RunPush() · RunHealthCheck() · RunLocalizationSync()(每一個都會委派執行;設定解析、Addressables 把關、互斥鎖定、確認對話框、進度條,以及程式碼產生→編譯→烘焙的接續流程,全都留在產品內部) · bool IsBusy · bool TryBeginExclusiveScope(out IDisposable scope)(當已有作業執行時回傳 falsescope = null;此範圍物件才是真正釋放鎖定的機制,第二次 Dispose 也無法釋放別人的執行) · string RenderReportText(ImportReport)(以目前編輯器語言呈現產品自己的句子,不寫入 Console)。完成語意詳列於表格下方
SheetForgeEditorInfo(靜態,命名空間 SheetForge.EditorEditor 組件的錨點——const Version,是 SheetForgeRuntimeInfo 在編輯器端介面上的對應版本,供功能閘門判斷使用
ImportCompletedArgs(sealed)傳給訂閱者的完成事件負載。IReadOnlyList<string> Tabs(此次完成所烘焙的分頁) · string BakeFolder(Database SO 所在資料夾)。採用參數物件模式——未來新增欄位不會破壞事件簽章。
GoogleSheetAccessMode(enum)SheetsApi(需驗證,可寫入) · ExportUrl(不需驗證,唯讀
ExportFormat(enum)Tsv · Csv · Xlsx · Json · MatchSource

PluginRegistry——套件組合與插槽隔離。 其巢狀的 PluginBundle 公開了組裝完成的 PluginSet Set——這是十二個插槽的單一真實來源,也是一個新成長出來的插槽在不擴大 bundle 的情況下依然能被讀取的方式——並額外提供九個便利窗口:Enums · Parsers · Validators · EdgeContributors · Markers · Templates · GraphShapes · CodeRegistries · Themes。較早期的六參數與八參數建構子則以多載形式保留,並將較晚新增的註冊表預設為空——其行為與這些合約存在之前的版本完全相同。

隔離機制屬於 Core,而非此型別:若某個外掛在註冊時拋出例外,會被具名回報並跳過,其餘每一個插槽、以及其他每一個外掛,依然會照常註冊。

SheetForgeActions——完成語意。 RunImportRunPush 皆為射後不理。 其內部是 async void,因為編輯器主執行緒不能因網路 IO 而被阻塞,因此回傳並不代表完成——請訂閱 ImportEvents.ImportCompleted 以得知完成時機。RunExportRunHealthCheckRunLocalizationSync 則會同步完成——RunLocalizationSync 執行的正是匯入完成時所走的試算表 → StringTable 路徑,而在沒有 Unity Localization 套件時,它會顯示安裝提示,且不改變任何東西。

來源提供者介面縫隙(SheetForge.Editor.Sources

型別角色與關鍵成員
ISheetSourceProvider提供者合約。Id · DisplayNameKey · CreateTabSource(settings) · GetVisibility(settings) · CanAuthor(settings) · CreateReflectTarget(dispatcher, settings)
ISourceReflectTarget寫回目標。void Reflect()
SourceVisibility應顯示哪些設定欄位——5 個布林旗標
SourceProviderRegistry(靜態)偵測/解析。All · ResolveActive(SheetForgeSettings)ResolveActive(string providerId)(不需持有設定資源,直接依 id 解析) · TryGet · InvalidateCache
ITabSource擷取抽象介面。Description · Task<TabSourceResult> FetchAsync()
TabSourceResult分頁(名稱 → 原始 TSV)+ 診斷資訊 + 逐分頁格式;允許部分輸出。靜態 Create
TabSourceFormat(enum)Tsv · Csv · Xlsx · GoogleSheet

Data Studio 擴充點(SheetForge.Editor.Studio

因為會碰觸 UIElements/視窗狀態,這些合約位於 Editor 端——與 ISheetSourceProvider 屬於同一種合理的不對稱設計。全部四個合約皆透過 TypeCache 發現(無參數建構子;無需另外呼叫註冊),且皆於 try/catch 中呼叫。視窗本身(DataStudioWindow)為 internal

任何能以資料表達的內容,都應改用 Core 的 ISheetForgeStudioPlugin 詞彙表——它同樣會繪製於瀏覽器中。這些合約則是給描述所無法表達的內容使用的、無上限的逃生艙口。

最後四個項目並非合約,而是掛載元件可以使用的工具:

  • 視窗自身唯讀的外觀數值,讓元件能夠融入視窗的樣式;
  • 鍵值下拉選單,讓一個儲存格元件能以與內建儲存格相同的方式挑選鍵值;
  • 以及探索快取重置,讓你自己的測試能重新發現一個探針。
型別種類角色與關鍵成員
IStudioGraphWidget介面圖形畫布上方的一條領域專屬長條(Core 本身不出貨任何小工具)。bool AppliesTo(StudioGraphContext) · VisualElement Create(StudioGraphContext)(每次圖形重建都會重新建立——請勿保存任何狀態;null 代表不新增任何內容)
StudioGraphContextsealed class唯讀:TabFocusRecordId(終點) · SheetRecord FocusRecord(未解析時為 null) · Tables · ReferenceIndex References · CodeRegistries。有兩個已退役的軸線,為了簽章相容性而保留,並標示為 [Obsolete]ShapeId(永遠是 "record")與 ModeId(永遠是空白)。比對這兩者中的任何一個都能正常編譯,但絕不會為真——編譯器現在會直接告知這一點,而不是留下一個死路徑——請直接刪除該項檢查。沒有暫存介面——小工具僅供顯示(建構子為 internal:由視窗自行組裝)
IStudioCellEditorProvider介面為一個具名型別繪製一個網格儲存格。string TypeName(對應 CellParserRegistry 中的型別或 wrapper 名稱,採 Ordinal 比對;空白代表退出) · VisualElement CreateEditor(StudioCellEditorContext)——回傳 null 代表拒絕該儲存格,改由內建元件接手。若有兩者同時宣告同一個型別名稱,會出現警告,並保留最先找到的那一個
StudioCellEditorContextsealed class儲存格元件所取得的內容:Tab · FieldName · TypeToken Type · CurrentRawText(已套用暫存內容的標準文字) · Action<string> Commit(一次性的確定動作——自成一個復原步驟) · Action<string> CommitTyping(一連串的鍵盤輸入——同一儲存格內會被合併為一步) · Func<string,IReadOnlyList<string>> ReferenceKeys(與內建選取器所提供的候選鍵值相同)。兩種提交方式都會通過視窗的暫存把關機制(建構子為 internal:由視窗自行組裝)
IStudioInspectorAction介面節點檢閱器上的一個額外按鈕。string LabelKey(Loc 鍵值;未註冊 = 逐字顯示,空白 = 型別名稱) · bool AppliesTo(StudioInspectorContext) · void Execute(StudioInspectorContext)
StudioInspectorContextsealed class讀取:Tab · RecordId · SheetRecord Record · Tables · References · CodeRegistries。經中介的變動操作:Action<string,string,string,string> StageCell · Action<IReadOnlyList<EdgeCellWrite>> StageCells,兩者詳情皆列於表格下方。服務:Action<string,int,string> FocusCell · Action RequestRebuildAuthoringSession 刻意被公開
IStudioPanelProvider介面Studio 右側窗格中的任意 UIToolkit 面板——與描述式 StudioPanelDescriptor 並列的逃生艙口。string Id · string TitleKey · bool AppliesTo(StudioSurfaceContext) · VisualElement CreatePanel(StudioSurfaceContext)null 代表這個時刻不繪製任何內容)。以相同的 Id 註冊一個描述式面板,每個主機就會取用自己能繪製的那一個:編輯器偏好這一個,瀏覽器則繪製描述式的那一個——因此「瀏覽器能走多遠,編輯器裡就走多遠」不需要第二套合約。這個元件只存活一個重新計算的時刻,因此它不持有任何狀態
StudioPalette靜態類別視窗自身繪製時所使用的唯讀顏色、間距與型別數值,讓你掛載的元件能夠融入視窗,而不必自行寫死十六進位色碼。每個插槽都是在讀取當下才解析,因此小工具能免費跟隨亮度模式與色彩預設集變化。挑選數值(預設集、亮度、預設值)的邏輯仍為 internal——小工具只會跟隨調色盤,而不會重新繪製它。成員清單詳列於表格下方
StudioTheme靜態類別僅有四個成員:CategoryColor(category)(與視窗賦予該分類相同、具決定性的色調) · Np(text)(安全地內插進一段富文字標籤中) · Mono / ApplyMono(element)(等寬字型政策:僅限鍵值、位址與數字——等寬字型沒有中日韓字符)。此型別上的其餘內容皆為 internal
StudioKeyPicker靜態類別僅有一個成員:Show(Rect screenAnchor, string targetTab, IReadOnlyList<string> candidates, Action<string> picked, string acceptsLabel = null)——與內建參照儲存格所開啟的下拉選單相同,供需要深入自己記法內部取得鍵值的儲存格元件使用。它會從你提供的候選清單中挑選一個鍵值並回傳;建立記錄、將儲存格留白、對清單進行多重切換,以及詢問哪個連接埠要接收挑選結果,這些都是內建參照儲存格自己的規則,並不在此介面之列。picked 為必填參數(在任何視窗建立之前就會拋出 ArgumentNullException);若沒有候選項目、也沒有其他可提供的內容,它會改為記錄一則訊息,而不會開啟一個空清單。視窗型別本身仍為 internal
StudioPluginRegistry靜態類別僅有一個公開成員:InvalidateCache()——清除每次重新載入期間有效的探索快取,讓你的測試剛啟用的探針能夠被重新發現(與 PluginRegistrySourceProviderRegistry 早已提供的相同禮遇;只是這個登錄表先前一直是例外)。已探索到的清單本身仍為 internal:外部無法讀取或取代視窗即將掛載的內容

StudioInspectorContext——兩個暫存委派方法:

  • StageCell 接受分頁、記錄 id、欄位與標準原始文字。視窗會登錄該復原步驟、遞增投影世代,並暫存其邏輯位址。
  • StageCells 對必須一併變更的多個儲存格做相同的事:一個原生復原步驟,要嘛全部成功、要嘛全部不執行。只要其中一項無法暫存,整個工作階段就完全不受影響。

失敗的結果在畫面上皆為靜默,只有把關機制本身會自我說明。唯讀來源、已在執行中的管線,或活頁簿型分頁,會將原因寫入 Console。空清單、缺少分頁或欄位的寫入,以及解析不出任何列的記錄鍵值,則會不動聲色、什麼都不做。

StudioPalette——成員:

  • 33 個顏色插槽:Canvas · Panel · Band · Chrome · Surface · Chip · Selection · PendingCell · Line · LineSoft · GridLine · LineHover · Text · TextMuted · TextFaint · RefText · OnAccent · Accent · AccentDim · Warning · Danger · Ok · SheetTone · CodeTone · EditedCell · NewRowCell · NewRowLine · DangerChip · DangerPanel · Scrim · Wire · WireDot · GridDot
  • IsDark
  • 間距:SectionSpace · RowSpace · RuleHeight · ButtonHeight · PrimaryButtonHeight · GlyphWidth
  • 字型大小:HeadingFontSize · SectionFontSize · CaptionFontSize
  • FromRgb(uint) · ToHex(uint)

推送核准(SheetForge.Editor.Push

型別角色
IPushApproverbool Approve(PushPlan, string humanSummary) · bool ApproveStructureRewrite(string, bool hasLiveConflicts)——拒絕 = 不傳送任何內容
AutoPushApprover永遠核准(供測試/自動化使用)

編寫引擎(SheetForge.Editor.Structure / .Pipeline / .Export

型別角色與關鍵成員
AuthoringSession暫存狀態的持有者(可序列化——免費獲得 Undo 與重新載入後存續能力)。Edits · IsolatedEdits · NewRows · StructOps · Reorders · TabRenames · EnumMembers(暫存中、待新增至 enum 試算表的成員) · AssetRegistrations(暫存的 Addressables 註冊——屬於專案層級,因此不參與逐分頁的把關機制,但會計入反映的進入條件、捨棄,以及差異摘要) · HasAssetRegistrations · StageAssetRegistration(r)(相同的 guid、或建立群組時相同的群組,會直接原地取代——以最後一次意圖為準;沒有識別依據的註冊會被拒絕) · RemoveAssetRegistrationsWhere(predicate) · SetStaged · ResolveBaselineEdits · RemapFieldName/RecordId/Tab · StageTabRename · EffectiveStructOps · PendingStructCount · TabNames · TryGetBaselineTable · LastProjectionResult · ClearAll(也會一併清除這些註冊)
AuthoringDispatcher反映調度器。建構子 (session, callbacks, baselines) · Reflect() · BuildProjectionResult()(無副作用的投影查詢) · IReadOnlyDictionary<string,string> BuildProjectedTabs()(將同一份投影結果以逐分頁 TSV 的形式呈現——也就是一個寫回目標即將傳送的內容,可在不寫入的情況下預覽) · void FinalizeReflectSuccess(IReadOnlyList<string> writtenTabs, IReadOnlyList<TabRenameEntry> committedRenames = null)(一個來源自己的寫回流程必須抵達的終點:為它寫入的分頁進行保留狀態的清理、ClearUndo 邊界,以及自動重新匯入——內建路徑執行的正是同一段私有方法本體,因此外部提供者的收尾方式會與它們完全一致;空清單為無操作,暫存內容維持不變) · Session · Callbacks · Baselines
AuthoringDispatchCallbacks13 個一般性、與視圖相關的委派方法 + IPushApprover——ResolveSettings · RenderReportAction<ImportReport>,可容許 null) · TriggerReimport · ConfirmKeyRenames · ConfirmTabRenames(可容許 null) · ClearUndo · Rebuild · …… 內建 Local/Google 對話框委派方法則位於選用的 BuiltInSourceDialogs 套組中
BuiltInSourceDialogs內建 Local/Google 來源對話框委派方法的選用套組,共 14 個,與 AuthoringDispatchCallbacks 分離——外部提供者絕不需要它們。NotifyLocalDone 帶有五個引數;最後一個是供完成對話框使用的 Addressables 註冊摘要行(沒有任何暫存內容時為 null
BaselineStore.Export逐分頁的正規化 TSV baseline 快照

暫存數值型別(SheetForge.Editor.StructureStagedCellEditStagedNewRow 位於 SheetForge.Editor.Windows

型別角色
StagedCellEdit(結構)一項暫存編輯——TabName · RowOrdinal · FieldName · RawText · RecordId(邏輯鍵值)
StagedNewRow一列暫存的新列——TabName · FieldNames · CellTexts
StructureOp一項結構操作——Kind · 座標 · 文字 · Order 排列
StructureOpKind(enum)AddColumn · RemoveColumn · AddMarker · RemoveMarker · RemoveDataRow · ReorderColumns · ReorderDataRows · RenameColumn · EditColumnType · EditColumnDesc · SetColumnOverlap · SetSheetStyle
TabReorderEntry逐分頁的重新排序狀態——Tab · ColOrder · RowOrder
TabRenameEntry(結構)OldName · NewName
StagedEnumMember(結構)一項暫存的「將此成員新增至此 enum」操作——TabName(哪一份 enum 試算表;空白 = 全部搜尋) · EnumName · Member。屬於工作階段層級,而非 StructureOp——原因與分頁重新命名相同:一份 enum 試算表沒有資料表、沒有結構描述,也沒有鍵值欄,因此一項儲存格編輯的 (分頁, 記錄, 欄位) 位址,無法用來指名「此 enum 的下一個成員」。之所以公開,僅是因為 AuthoringSession.EnumMembers 本身是公開的(CS0050
StagedAssetRegistration(結構)一項對專案 Addressables 設定的暫存變更,由拖放或挑選一項資源到 AssetRef@Group 儲存格中所產生——StagedAssetRegistrationKind Kind · Guid(該資源;子資源會暫存其上層資源) · Group · FromGroup(僅限移動時使用) · Address(新項目為不含副檔名的檔案名稱;已註冊的資源則保留原有位址) · AssetPath(供顯示用)。工廠方法 Add(guid, group, address, assetPath) · Move(guid, fromGroup, group, address, assetPath) · CreateGroup(group)。會在試算表寫入成功後執行,然後被清除。之所以公開,僅是因為 AuthoringSession.AssetRegistrations 本身是公開的(CS0050),與 StagedEnumMember 相同
StagedAssetRegistrationKind(enum)Add · Move · CreateGroup
TabBaselineAnchor(結構)TabName · Fingerprint · RecordCount
IsolatedEdit一項重新錨定失敗的編輯——Edit · Reason
IsolationReason(enum)外部重新命名/外部刪除/鍵值衝突

編寫輔助工具(SheetForge.Editor.Windows / .Structure

型別角色
KeyRenamePlanner(靜態)鍵值重新命名 + 跨分頁傳播規劃。Plan(…) · 巢狀的 KeyRenamePlan · 同層結構 KeyRename
RecordIdMinter(靜態,純函式)Id 建議。Suggest · DetectCommonPrefix · Uniquify · StagedNewRowKeys
IntIdMinter(靜態,純函式)為一筆新記錄建議下一個 IntId——Suggest(existingIds)max + 1。這是與 RecordIdMinter 分開的一條軸線,且絕不會重複使用一個已刪除留下的空缺
ProjectionErrorMapper(靜態,純函式)錯誤座標 → 邏輯位址。TryMap(…) · 巢狀的 LogicalAddress
EphemeralSoApply(靜態)暫存數值的 SO 覆蓋層(暫時性)。Apply(…) · InvalidateIndex(…) · 巢狀的 Report / SkipReason / SkippedEdit

Runtime 組件(SheetForge.Runtime

autoReferenced——遊戲程式碼無需 asmdef 參照即可使用。

型別角色與關鍵成員
SheetForgeDatabases(靜態)執行期載入器——官方認可的載入路徑。const AddressPrefix = "SheetForge/" · AddressFor(tab) · LoadAsync(tab) · LoadAsync<TDatabase>(tab) · Release(handle) / Release<TDatabase>(db)。位址輔助方法皆為純字串,永遠都能編譯;LoadAsyncRelease 僅在 SHEETFORGE_ADDRESSABLES 之下才存在,這是在偵測到 com.unity.addressables 已安裝時才會開啟的版本定義——正是它讓產品能在沒有該套件的情況下依然編譯成功
DefinitionDatabase(抽象 SO)每個產生的逐分頁 Database 的基底類別。abstract TabName · abstract Count · virtual IReadOnlyList<object> RecordsUntyped · virtual InvalidateIndex()RecordsUntyped不需要知道其產生型別即可列舉一個已烘焙分頁的官方認可做法——過去,第二個烘焙端或是走訪每個分頁的檢閱器,都必須反射私有的 records 欄位,這會讓一個欄位名稱變成一份未宣告的合約,一旦程式碼產生器在某天重新命名它,就會靜默失效。請將此清單視為唯讀(試算表才是權威來源)。它預設為空清單,因此在此成員存在之前產生的程式碼依然能夠編譯並執行;重新匯入一次即可補上覆寫值
RecordRef(結構)烘焙後 SO 內部序列化的參照值(字串 id,於查詢時解析)。Id · IsEmpty
IntRef(結構)烘焙後 SO 內部序列化的整數鍵值參照值——RecordRef 對應 IntId@Tab 欄位的版本。由於 0 也是一個有效的 id,因此以一個 hasValue 位元支撐 IsEmptyId · IsEmpty。程式碼產生器會將一個 IntId@Tab 欄位輸出為 IntRef,而產生的 Database 上的 TryGet(IntRef) 則會使用它
LocRef(結構)烘焙後 SO 內部序列化的在地化參照——一個 LocRef@Tab 儲存格。Table(在地化分頁,也就是 StringTable 集合名稱) · Key · long KeyId0 表示「尚未解析」:一次匯入烘焙出的是 0,橋接會在表格同步之後填入真正的 id,因此參照能在鍵值被重新命名後存活) · IsEmpty。它永遠可以編譯——產生的程式碼與烘焙後的素材從不包含任何在地化套件的型別,正是這一點讓該套件保持選用
LocRefExtensions(靜態)只有一個成員:LocalizedString ToLocalizedString(this LocRef)——當 KeyId 不為 0 時依它指向,否則依鍵值名稱指向,而空的參照會轉換成空的 LocalizedString。它只有在安裝了 com.unity.localization 時才存在,位於版本定義 SHEETFORGE_LOCALIZATION 之下——與 Addressables 那一層中 SHEETFORGE_ADDRESSABLES 所用的安排相同
SheetForgeRuntimeInfo(靜態)const Version

產生的型別(模式——依專案而異,非隨附 API)

針對每個分頁 Foo,程式碼產生器會在你的 generatedNamespace 中產生:

public sealed partial class FooDefinition    // one strongly-typed field per column; @desc → doc/tooltip
public sealed partial class FooDatabase : DefinitionDatabase
{
    // TabName, Count, SchemaFingerprint, Records, RecordsUntyped override,
    // lazy _byId/_byIntId lookups, InvalidateIndex override
}

SheetForgeDatabases.LoadAsync<FooDatabase>("Foo") 載入。

兩個類別皆以 partial 產生,因此你可以在自己的檔案中新增衍生成員——一個計算屬性、一個介面實作、一個運算子——放在產生檔案的旁邊,並且每次重新匯入都不會將其覆寫掉。有一項邊界:不要在你的那一部分中新增序列化欄位。烘焙後的 ScriptableObject 每次匯入都會依照試算表重新建構,因此任何只存在於你那一部分的欄位,都會被還原為其預設值——如果一個值屬於資料的一部分,它就應該存放在某個欄位中。(partial 關鍵字並不會影響 SchemaFingerprint,後者僅依結構描述本身計算,因此將這些類別改為 partial,並不會使任何一份既有的烘焙結果失效。)


其他組件

  • SheetForge.Setup——不具相依性、用於處理 Addressables 缺失情況的啟動組件。沒有公開 API(全部為 internal;它的存在只是為了顯示一個指引視窗)。

  • SheetForge.PluginDemo(一個合併後的 asmdef +一個 Demo.Editor asmdef;內容命名空間仍維持為 SheetForge.Skills)——參考範例套件,並非產品 API。它包含:

    • SkillsPlugin(七種外掛介面——基礎、驗證器、邊、範本、畫布、程式碼註冊表、主題);
    • Modifier + ModifierCellParser(自訂儲存格型別)、ModifierStatEdgeContributor(邊貢獻者);
    • ExamplePipelineAugmenter / ExampleReactiveAugmenter(畫布覆寫)、ExampleCodeAtoms_Refs 程式碼註冊表);
    • ExampleStudioUi(宣告式動作、面板、欄徽章與儲存格元件提示)、ExampleImportObserver(管線觀察者);
    • ExampleStageStripWidget / ExampleInspectorAction / ExampleStudioPanel(Data Studio 的 Editor 擴充點,以公開調色盤繪製而成)、ExampleLocStrings(以兩種語言註冊這些標籤——放在主要組件中,因此瀏覽器也同樣會顯示它們);
    • 一個組件層級的 SheetForgePluginCompat 宣告;
    • SkillRunner(使用端執行期程式),以及位於預設命名空間 SheetForge.Generated 中產生的 Example* 型別(隔離方式是 Example* 前綴,而非獨立命名空間)。

    不含外掛的 SheetForge.CoreDemo 範例則出貨時 asmdef(會編譯進 Assembly-CSharp)。

相關頁面