API 參考——公開介面
本頁列出產品組件中每一個公開型別。任何未列於此處的內容,依設計即為 internal——公開介面是刻意保持精簡的。
- Core(
SheetForge.Core+SheetForge.Core.Tooling):137 個公開型別(Core:131 個,Core.Tooling:6 個)。Core.Tooling 是僅限編輯器使用的一半,內含報告、推送規劃等匯入期服務——完全不會出貨進玩家組建。 - Editor:53 個頂層公開型別,加上其公開的巢狀型別。
- Runtime:7 個型別,加上產生的輸出。
這正是消費端模擬測試(不具 InternalsVisibleTo)據以編譯的介面。
偵測合約(並非型別):另一個素材也能透過 Editor 組件自我註冊的
SHEETFORGEscripting-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 | 靜態類別 | 唯一的組裝路徑。每個型別一個實體,並轉型為它實作的每一項合約。兩個成員與診斷區分方式詳列於表格下方 |
PluginSet | sealed 類別 | 組裝完成的結果——十二個插槽:Enums · Parsers · Validators · EdgeContributors · Markers · Templates · GraphShapes · CodeRegistries · Themes · Strings · StudioUi · PipelineObservers。一個新插槽只要加進這裡,就能同時觸及兩個主機 |
SheetForgePluginCompatAttribute | sealed 屬性(組件層級) | [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)
| 型別 | 角色與關鍵成員 |
|---|---|
EnumRegistry | Enum 名稱 → 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)。絕不拋出例外——false/null 代表「無法解讀」,改寫時必須保留殘留內容 |
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·ListOpen(List<)·ListClose(>)。
型別名稱
- 每個內建名稱各對應一個常數:
IntTypeName·FloatTypeName·BoolTypeName·StringTypeName·RecordIdTypeName·IntIdTypeName·AssetRefTypeName·LocRefTypeName·ColorTypeName·AnimationCurveTypeName·GradientTypeName·EnumTypeName。 BuiltinScalarTypes與IsBuiltinScalarTypeName(name)——「這個名稱是否已經是內建的?」,會在某個剖析器以這個名稱註冊之前就先給出答案。StyleKeyNames(title、color)·LocReservedColumns(smart、comment)。
值
TrueCanonical/FalseCanonical——標準的bool文字。NumberCellStyles——讀取每個數值儲存格時所用的NumberStyles。千分位分隔符會被排除,文化特性(culture)永遠固定不變(invariant),因此某個地區習慣的小數點逗號會直接、明顯地失敗,而不是悄悄地把數值改掉。
領域驗證(SheetForge.Core.Validation)
| 型別 | 角色與關鍵成員 |
|---|---|
IDomainValidator | 跨欄/跨分頁規則。違規事項 → 以 DomainRuleViolation 的形式進入 ctx.Errors,並附上全部 4 個要素。string Name · Validate(DomainValidationContext) |
DomainValidationContext | Tables(分頁 → 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 / OptionLabels。new 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@Tab、IntId@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 宣告——記錄層級) |
ReferenceIndex | sealed 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 警告。身分歸屬於資料本身(虛擬節點若與相同鍵值的真實記錄衝突,會由真實記錄勝出);顯示提示則不受此規則約束 |
CanvasAugmentBuilder | sealed class | 這個寫入介面,僅有四件事可做——成員與規則詳列於表格下方 |
GraphShapeRegistry | sealed class | 分頁名稱 → 畫布覆寫。Register(tabName, IRecordCanvasAugmenter)(重複分頁/空白名稱/null 皆會拋出例外) · TryGet · IsEmpty |
GraphBuildContext | sealed class | 此覆寫的唯讀輸入資料。Tables(分頁 → SheetTable) · ReferenceIndex References · IReadOnlyList<CodeRegistrySource> CodeRegistries(空清單,絕不為 null)。沒有錯誤蒐集器——畫布是顯示用途,而非驗證 |
GraphSpecBuilder | sealed class | 圖形組裝輔助工具。建構子 (GraphBuildContext) · 靜態 NodeKey(tab, recordId)(連線所指向的唯一真實依據) · AddNode(GraphNodeSpec)(第一個 (Key, Column) 勝出) · AddWire(GraphWireSpec) · AddWire(fromKey, toKey, label, fromTab, fromRecordId, fieldName, isCyclic = false, cyclicNote = null)(此多載同時指名這條連結是寫在哪個儲存格中,這正是讓連線得以被編輯的關鍵) |
GraphSpec | sealed class | 畫布所繪製、組裝完成的結果——Nodes · Wires(組裝需經由建構工具完成;建構子為 internal) |
GraphNodeSpec | sealed class | 一個節點。Key · Tab · RecordId · Title · Subtitle · Category · CellCoordinate Address · Column / Row(畫布早已解算好的網格儲存格——此處只是承載,而非決定) · IsFocus(終點) · IsMissing · InCount · IsCyclic |
GraphWireSpec | sealed 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 / LightColors(IReadOnlyDictionary<ThemeColorSlot, uint>,於建構時複製) · TryGetColor(dark, slot, out rgb) · IsEmpty |
ThemeColorSlot | enum——一個預設集可以覆寫的 33 種顏色角色(表面、線條、文字、語意色彩、暫存標記、失敗狀態表面、遮罩、圖形)。顏色皆為 0xRRGGBB:Core 不參照任何引擎型別,半透明填色則是由插槽顏色加上一個固定的透明度推導而來。僅供附加。 |
一個預設集只會覆寫它所指名的插槽;其餘所有插槽都會維持產品預設值,因此即使日後新增更多插槽,既有的預設集依然有效。註冊本身絕不會套用該預設集——使用者需自行在 Preferences ▸ SheetForge ▸ Theme 中挑選。
宣告式編寫介面(SheetForge.Core.Studio)
一個外掛描述的是要顯示什麼——外殼是資料,判斷式與效果則是委派——各主機各自以自己的元件繪製它:編輯器用 UIToolkit,瀏覽器用 React。任何地方都不會出現版面配置數值。要說什麼是外掛的職責,怎麼擺放則是渲染器的職責。
這裡的每一個 enum 都僅供附加,因此隨著詞彙表成長,一項既有的註冊仍會維持原意。
| 型別 | 種類 | 角色與關鍵成員 |
|---|---|---|
StudioUiRegistry | sealed class | RegisterStudioUi 所填入的內容。AddAction(StudioActionDescriptor) · AddPanel(StudioPanelDescriptor) · AddColumnBadge(StudioColumnBadgeDescriptor) · AddCellEditorHint(StudioCellEditorHint) · Actions / Panels / ColumnBadges / CellEditorHints · IsEmpty |
StudioUiNode | sealed class | 一個已描述的片段,不可變,透過靜態工廠方法建構——工廠方法、可讀屬性與網址規則詳列於表格下方 |
StudioUiNodeKind | enum | 上述 13 種種類(Row … Link) |
StudioActionDescriptor | sealed class | 一個動作。Id(唯一) · LabelKey(一個 Loc 鍵值;未註冊則逐字顯示) · StudioActionPlacement Placement · Func<StudioSurfaceContext,bool> AppliesTo · Action<StudioSurfaceContext> Execute · ConfirmKey(選填——主機會先詢問這句話)。主機會在呼叫時重新檢查 AppliesTo,因此一個過時的選單項目會以一次誠實的無動作加上重繪來回應 |
StudioActionPlacement | enum | Inspector · RowContextMenu · TopbarMenu · ColumnHeaderMenu · CanvasNodeMenu。每個位置會填入不同的情境欄位——列的位置帶有該筆記錄,欄的位置帶有欄名稱,畫布的位置帶有該節點的記錄 |
StudioPanelDescriptor | sealed class | Studio 右側窗格中的一個面板。Id · TitleKey · Func<StudioSurfaceContext,StudioUiNode> Build——每個重新計算的時刻都會重建,因此它不持有任何狀態。沒有任何面板註冊時,該窗格完全不會被繪製 |
StudioColumnBadgeDescriptor | sealed class | 一個欄標頭旁的徽章。Func<StudioSurfaceContext,string,string,StudioUiNode> Provide(情境、分頁、欄位)——null 代表該欄上沒有任何內容 |
StudioCellEditorHint | sealed class | 「對這個型別使用這個內建元件」——挑選一種種類,而非自行提供一個。TypeName(一個精確的 CellParserRegistry 型別名稱;清單儲存格會依其元素名稱比對;wrapper 儲存格則保留標準文字,絕不會被比對) · StudioCellEditorArchetype Archetype · GetOptions(僅限下拉選單——Func<context, tab, field, IReadOnlyList<StudioCellOption>>) · SliderMin / SliderMax · ToggleTrueValue / ToggleFalseValue。四個建構子,每種素材形態各一個。會在一個已註冊的 IStudioCellEditorProvider 選擇拒絕之後、且在內建分支之前被查詢;一個套件的提示,會在下方所述的內建提示之前被查詢,因此在 Color、AnimationCurve 或 Gradient 之下註冊一個提示,會覆寫該型別的預設編輯器。一個元素提示為 ColorPicker、CurveEditor 或 GradientEditor 的 List<>,在兩個主機中都會變成晶片編輯器 |
StudioCellEditorArchetype | enum | Dropdown · MultilineText · Slider · Toggle · ColorPicker(儲存格文字為 #RRGGBB / #RRGGBBAA) · CurveEditor(儲存格文字=標準的 CurveValue 記法) · GradientEditor(儲存格文字=標準的 GradientValue 記法)。僅供附加——最新的兩個是 5 與 6 |
BuiltinCellEditorHints | 靜態類別 | Core 自身所宣告的三個提示——Color → ColorPicker、AnimationCurve → CurveEditor、Gradient → GradientEditor——與套件的提示走的是同一條路徑,因此編輯器與瀏覽器不可能為它們挑選出不同的元件。IReadOnlyList<StudioCellEditorHint> All(固定順序) · bool TryGet(typeName, out hint)(Ordinal 比對)。主機會優先查詢 StudioUiRegistry.CellEditorHints,再回退到這份對照表 |
StudioCellOption | sealed class | 一個下拉選單候選項——Value(寫入儲存格的標準文字) · Label(使用者所讀到的內容;預設等於 Value) |
StudioSurfaceContext | sealed 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)——僅限http/https。兩個主機共同詢問同一個判斷式,因此它們對於什麼是安全可開啟的,絕不會產生分歧。
外掛 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(側邊欄/圖形/檢閱器)使用的內容,並非供匯入驗證器使用。
| 型別 | 種類 | 角色與關鍵成員 |
|---|---|---|
CodeRegistryCatalog | sealed class | 註冊的根節點。Register(CodeRegistrySource)(null/空白分頁名稱/重複分頁名稱皆會拋出例外) · TryGet(tabName, out source) · Sources · IsEmpty |
CodeRegistrySource | sealed class | 一個鎖定的虛擬分頁。string TabName · IReadOnlyList<CodeRegistryEntry> Entries(註冊順序 = 顯示順序) |
CodeRegistryEntry | sealed class | 一個項目。string Key(參照可以指向的目標) · string Label · IReadOnlyList<string> Raises(null 會正規化為空清單)。Core 會將這三者皆視為不透明的字串 |
IR 讀取模型(SheetForge.Core.Model)
| 型別 | 角色與關鍵成員 |
|---|---|
SheetTable | 一個分頁的剖析輸出。SheetSchema Schema · IReadOnlyList<SheetRecord> Records |
SheetSchema | string 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(第一個語言欄——內嵌預覽讀取的、以及自動生成鍵值時寫入的那一欄) |
SheetRecord | int RowNumber(原始,從 1 開始)· Values(欄位 → CellValue)· TryGet · 索引子 |
FieldSchema | Name · 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,且該剖析器有實作 IReferencingCellType;ReferenceScanner.GetReferencedTab 是讀取此旗標的唯一判斷依據,這也是為什麼每個使用端都能在不變更簽章的情況下自動生效) · AssetTypeName(AssetRef@Group<Type> 中所寫的 <Type>;不受限時為 null;Core 只會儲存這個名稱——解析它是 IAssetTypeResolver 的職責——且它同樣會被標記在清單或 wrapper 內部的 AssetRef token 上)。建構子最後三個參數(innerToken、isCustomReference、assetTypeName)皆有預設值,因此既有呼叫仍能正常編譯,較早期的 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 的資源型別進行解析(沒有允許清單;元件與僅限編輯器使用的型別皆被排除) |
AssetTypeResolution | sealed class | 單一名稱的判定結果——RawName · AssetTypeResolutionStatus Status · FullName(CLR 完整名稱,巢狀型別以 + 表示;僅限 Resolved 與 NotReferenceable) · AssemblyName(產生的附屬組件必須參照的組件;組件定義型別會設定此值,引擎模組與未解析的名稱則為 null) · Candidates(絕不為 null:名稱有歧義時的候選型別,或名稱未知時的最接近候選建議)。工廠方法 Resolved(raw, fullName, assemblyName) · Unknown(raw, suggestions) · Ambiguous(raw, candidates) · NotReferenceable(raw, fullName, assemblyName) |
AssetTypeResolutionStatus | enum | Resolved · Unknown(不存在這個型別) · Ambiguous(短名稱與多個型別相符——請寫出完整名稱) · NotReferenceable(該型別位於像 Assembly-CSharp 這樣的預先定義組件中,產生的程式碼無法參照它) |
程式碼產生器會讀取管線所產生的已解析對照表,並為已解析的名稱輸出 AssetReferenceT<global::FullName>;一個在該對照表中找不到的名稱,絕不會被逐字輸出——該欄位會回退為 AssetReference,並蒐集一則 AssetTypeUnresolvedFallback 警告。已解析的完整名稱同樣會被納入結構描述指紋中。
視覺數值型別(SheetForge.Core.Model)
三種內建視覺型別的無引擎依賴數值模型。每一個都是不可變的、實作 IEquatable,並各自擁有自己的文字形式(TryParse / Render)——與試算表語法頁面所記載的記法相同——因此一個儲存顏色、曲線或漸層的外掛型別,可以直接重複使用它們,不必自創第二套記法。Editor 會將它們烘焙進 UnityEngine.Color / AnimationCurve / Gradient,並讀回它們;瀏覽器則透過下方的取樣器對它們取樣,而不必重新實作其中的數學運算。
| 型別 | 種類 | 角色與關鍵成員 |
|---|---|---|
ColorValue | readonly struct | 四個位元組 R · G · B · A · static Default(#00000000) · static TryParse(text, out value, out error)(接受 #RGB / #RGBA / #RRGGBB / #RRGGBBAA) · Render()(不透明時為大寫、六位數字) |
CurveValue | sealed class | Keys(依時間遞增排序) · PreWrap / PostWrap · static Empty(沒有任何關鍵影格——唯一沒有文字形式的狀態;Render() 會回傳 "") · static Create(keys, preWrap, postWrap)——唯一的建構路徑:依時間排序、拒絕重複的時間點,並套用 CurveTangentSolver,讓「模式優先」這件事從曲線誕生的那一刻起就成立 · static TryParse(2/4/7/8 欄位的關鍵影格,Once 會被接受為 ClampForever 的別名,切線可為 Infinity/-Infinity) · Render()(8 欄位的關鍵影格,只有在需要時才會加上包裹後綴) |
CurveKey | readonly struct | Time · Value · InTangent · OutTangent · InWeight · OutWeight · CurveWeightedMode WeightedMode · CurveTangentMode LeftMode / RightMode · bool Broken;一個十參數的建構子,本身不做任何正規化 |
CurveWrap | enum | ClampForever · Loop · PingPong · Default——依名稱對應 Unity 的包裹詞彙(對應到 WrapMode 數值的轉換工作屬於烘焙器) |
CurveTangentMode | enum | Free = 0 · Auto = 1 · Linear = 2 · Constant = 3 · ClampedAuto = 4——名稱與數值皆與 AnimationUtility.TangentMode 相同,因此烘焙器依名稱對應,絕不會直接碰觸 Unity 內部封裝的切線位元 |
CurveWeightedMode | [Flags] enum | None = 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 進行過比對驗證 |
GradientValue | sealed class | ColorKeys · AlphaKeys(各 1 到 8 個,依時間遞增排序) · GradientBlend Mode · GradientColorSpace ColorSpace · static Default(白色、完全不透明、Blend) · static Create(colorKeys, alphaKeys, mode, colorSpace)(驗證數量與 0…1 範圍,依 Unity 的方式將時間量化為 16 位元,並以穩定排序排列) · static TryParse(三或四個以 ` |
GradientColorKey | readonly struct | ColorValue Color(Alpha 會被忽略——Alpha 有自己專屬的關鍵影格) · float Time |
GradientAlphaKey | readonly struct | float Alpha · float Time |
GradientBlend | enum | Blend · Fixed · PerceptualBlend |
GradientColorSpace | enum | Uninitialized(未寫入時;讀取時視為 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 == null。Success · Registry · Diagnostics · SkippedTabs · EnumTabs(被讀取為 enum 定義試算表、因而絕不會被剖析為資料表的分頁——與 SkippedTabs(代表「尚無資料表寫入」)分開存放,讓報告中的略過數量維持真實;兩者皆屬於保留集合,會為那些分頁保留產生的程式碼、烘焙後的資源與位址) · 靜態 Succeeded / Failed |
ImportReport(.Reporting,組件為 SheetForge.Core.Tooling) | 報告渲染器的輸入——Timestamp · SourceDescription · TabCount · RecordCount · Success · Diagnostics · ErrorCount · WarningCount · SkippedTabCount(TabCount 之中,有多少是因為空白而被略過、而非真正被匯入的試算表——標頭會將其印出,避免分頁數量被誤認為「全數匯入」) |
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; @overlap與DomainRuleViolation;- enum 定義試算表——
EnumSheetMarkerConflict·DuplicateEnumName·EnumSheetEmptyColumn·InvalidEnumIdentifier·InvalidEnumUnderlyingType·InvalidEnumMemberValue; DropdownNotSupportedByFormat,這是一則警告而非錯誤;- 型別化資源參照——
UnknownAssetType·AmbiguousAssetType·AssetTypeNotReferenceable(每欄各一次,位於@type列上)、逐儲存格的AssetTypeMismatch,以及程式碼產生的警告AssetTypeUnresolvedFallback。
索引與工具程式(SheetForge.Core.Validation / .Model / .Parsing / .Unparse)
| 型別 | 角色與關鍵成員 |
|---|---|
TabKeyIndex | 一個分頁的鍵值資訊——字串鍵值欄,加上該分頁的 IntId 整數鍵值集合,因此 RecordId@Tab 與 IntId@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 種內建剖析器(int、float、bool、string、Enum、RecordId、AssetRef、IntId、LocRef、Color、AnimationCurve、Gradient)。 |
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 · gidMap(GidMapEntry { tabName, gid } 的清單)。Effective* 已解析屬性。 |
Loc(靜態) | 在地化的進入點。Tr(key) · TrContent(…) · Table · MenuRoot 常數。Tr 依序經過四個步驟解析:外掛註冊的字串(先目前語言,再退回英文——這項回退邏輯由疊加層本身負責,見 StringOverlayRegistry) → 內建對照表(先目前語言,再退回英文) → 鍵值本身。外掛字串恰好只有一條註冊通道,因此「哪一個註冊會勝出」絕不會成為一個問題 |
PluginRegistry(靜態) | 透過 TypeCache 偵測外掛,並將候選型別交給 PluginComposition.Compose。Build · 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)(當已有作業執行時回傳 false 且 scope = null;此範圍物件才是真正釋放鎖定的機制,第二次 Dispose 也無法釋放別人的執行) · string RenderReportText(ImportReport)(以目前編輯器語言呈現產品自己的句子,不寫入 Console)。完成語意詳列於表格下方 |
SheetForgeEditorInfo(靜態,命名空間 SheetForge.Editor) | Editor 組件的錨點——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——完成語意。 RunImport/RunPush 皆為射後不理。 其內部是 async void,因為編輯器主執行緒不能因網路 IO 而被阻塞,因此回傳並不代表完成——請訂閱 ImportEvents.ImportCompleted 以得知完成時機。RunExport/RunHealthCheck/RunLocalizationSync 則會同步完成——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 代表不新增任何內容) |
StudioGraphContext | sealed class | 唯讀:Tab 與 FocusRecordId(終點) · SheetRecord FocusRecord(未解析時為 null) · Tables · ReferenceIndex References · CodeRegistries。有兩個已退役的軸線,為了簽章相容性而保留,並標示為 [Obsolete]:ShapeId(永遠是 "record")與 ModeId(永遠是空白)。比對這兩者中的任何一個都能正常編譯,但絕不會為真——編譯器現在會直接告知這一點,而不是留下一個死路徑——請直接刪除該項檢查。沒有暫存介面——小工具僅供顯示(建構子為 internal:由視窗自行組裝) |
IStudioCellEditorProvider | 介面 | 為一個具名型別繪製一個網格儲存格。string TypeName(對應 CellParserRegistry 中的型別或 wrapper 名稱,採 Ordinal 比對;空白代表退出) · VisualElement CreateEditor(StudioCellEditorContext)——回傳 null 代表拒絕該儲存格,改由內建元件接手。若有兩者同時宣告同一個型別名稱,會出現警告,並保留最先找到的那一個 |
StudioCellEditorContext | sealed 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) |
StudioInspectorContext | sealed class | 讀取:Tab · RecordId · SheetRecord Record · Tables · References · CodeRegistries。經中介的變動操作:Action<string,string,string,string> StageCell · Action<IReadOnlyList<EdgeCellWrite>> StageCells,兩者詳情皆列於表格下方。服務:Action<string,int,string> FocusCell · Action RequestRebuild。AuthoringSession 刻意不被公開 |
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()——清除每次重新載入期間有效的探索快取,讓你的測試剛啟用的探針能夠被重新發現(與 PluginRegistry 及 SourceProviderRegistry 早已提供的相同禮遇;只是這個登錄表先前一直是例外)。已探索到的清單本身仍為 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)
| 型別 | 角色 |
|---|---|
IPushApprover | bool 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 |
AuthoringDispatchCallbacks | 13 個一般性、與視圖相關的委派方法 + IPushApprover——ResolveSettings · RenderReport(Action<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.Structure;StagedCellEdit/StagedNewRow 位於 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)。位址輔助方法皆為純字串,永遠都能編譯;LoadAsync 與 Release 僅在 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 位元支撐 IsEmpty。Id · IsEmpty。程式碼產生器會將一個 IntId@Tab 欄位輸出為 IntRef,而產生的 Database 上的 TryGet(IntRef) 則會使用它 |
LocRef(結構) | 烘焙後 SO 內部序列化的在地化參照——一個 LocRef@Tab 儲存格。Table(在地化分頁,也就是 StringTable 集合名稱) · Key · long KeyId(0 表示「尚未解析」:一次匯入烘焙出的是 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)。