From 58a5995364b429a605076d45a0ced2e6906a8567 Mon Sep 17 00:00:00 2001 From: Ziyi Zhang Date: Wed, 23 Sep 2026 10:54:45 -0400 Subject: [PATCH] feat: restore the asset-transformer-toolkit skill for toolkit 4.0 --- skills/asset-transformer-toolkit/SKILL.md | 39 +++ .../api-docs/rule-api.md | 154 ++++++++++++ .../api-docs/ruleblock-api.md | 37 +++ .../api-docs/ruleset-api.md | 138 +++++++++++ .../references/create-importer.md | 121 ++++++++++ .../references/lods.md | 61 +++++ .../references/rulesets-and-actions.md | 227 ++++++++++++++++++ 7 files changed, 777 insertions(+) create mode 100644 skills/asset-transformer-toolkit/SKILL.md create mode 100644 skills/asset-transformer-toolkit/api-docs/rule-api.md create mode 100644 skills/asset-transformer-toolkit/api-docs/ruleblock-api.md create mode 100644 skills/asset-transformer-toolkit/api-docs/ruleset-api.md create mode 100644 skills/asset-transformer-toolkit/references/create-importer.md create mode 100644 skills/asset-transformer-toolkit/references/lods.md create mode 100644 skills/asset-transformer-toolkit/references/rulesets-and-actions.md diff --git a/skills/asset-transformer-toolkit/SKILL.md b/skills/asset-transformer-toolkit/SKILL.md new file mode 100644 index 0000000..67ea2a3 --- /dev/null +++ b/skills/asset-transformer-toolkit/SKILL.md @@ -0,0 +1,39 @@ +--- +name: asset-transformer-toolkit +description: >- + Imports 3D models and point clouds with Asset Transformer Toolkit (formerly Pixyz), and creates, + edits, and runs RuleSets, Actions, and LODs. Use for Pixyz or Asset Transformer imports, RuleSets, + or ImporterScriptableObjects. Requires toolkit 4.0+. +required_packages: + com.unity.industry.toolkit: ">=4.0.0" +--- +### Before you start: check the package version +This skill needs Asset Transformer Toolkit 4.0.0 or later (`com.unity.industry.toolkit`). Earlier versions don't have the `ATTAssistantUtilities` API every workflow below relies on. + +1. Read the resolved version of `com.unity.industry.toolkit` from `Packages/packages-lock.json` (fall back to `Packages/manifest.json`). +2. **Not installed:** tell the user this workflow needs Asset Transformer Toolkit 4.0 or later, which is an entitled Unity package they may need access to through their Unity plan, and stop. Don't add it to the manifest yourself. +3. **Installed below 4.0.0:** tell the user which version you found and that 4.0 or later is required, and ask before upgrading. Don't fall back to older APIs, raw C# against internal types, or reflection. +4. **4.0.0 or later:** continue. + +### API Reference +Tool functions are provided by `Unity.Pixyz.Plugin4Unity.Editor.AI.ATTAssistantUtilities`. They are documented inline in each reference file below alongside the classes they operate on. + +### Technical Notes +Pixyz Plugin is the former name of Asset Transformer Toolkit. Prefer using the term 'Asset Transformer Toolkit' when addressing the user, unless the user is using the term 'Pixyz' +Most classes and code are in the Unity.Pixyz.Plugin4Unity.Editor assembly. +Asset Transformer Toolkit is NOT the same thing as Asset Transformer Studio/Pixyz Studio. NEVER rely on information about Asset Transformer Studio. + +### Importers +Asset Transformer Toolkit can import 3D file from outside the project. +When modifying Importers, NEVER assume it should be immediately followed by a reimport. The import process can be very long, so it must only be launched when the user requests it. +Modify fields in Importers using the ScriptableObject API. NEVER use reflection to access or modify Importer fields — reflection is not available. +To create a Pixyz/Asset Transformer Toolkit Importer for importing a file, or to reimport a model using an existing ImporterScriptableObject, read [references/create-importer](references/create-importer.md) + +### RuleSets and Actions +Read [references/rulesets-and-actions](references/rulesets-and-actions.md) +Read [api-docs/ruleset-api](api-docs/ruleset-api.md) when the RuleSet API is needed. +Read [api-docs/rule-api](api-docs/rule-api.md) when the Rule API is needed. +Read [api-docs/ruleblock-api](api-docs/ruleblock-api.md) when the RuleBlock API is needed, including `ActionBase.Id` for constructing `RuleBlock` instances. + +### Levels of Detail +Read [references/lods](references/lods.md) diff --git a/skills/asset-transformer-toolkit/api-docs/rule-api.md b/skills/asset-transformer-toolkit/api-docs/rule-api.md new file mode 100644 index 0000000..8c0fa7d --- /dev/null +++ b/skills/asset-transformer-toolkit/api-docs/rule-api.md @@ -0,0 +1,154 @@ +## Contents +- [Rule constructors](#rule-constructors) — `Rule()` +- [Rule methods](#rule-methods) — `GetBlock`, `GetBlockIndex`, `RemoveBlockAt`, `RemoveBlock`, `AppendBlock`, `InsertBlock`, `IsLastBlock` +- [Rule properties](#rule-properties) — `Name`, `IsEnabled`, `BlocksCount`, `Blocks` + +--- + +## Rule constructors + +The Rule API reference contains the following constructors. + +### `Rule()` + +This constructor creates an empty Rule with no blocks. + +```csharp +public Rule() +``` + +## Rule methods + +The Rule API reference contains the following methods. + +### `GetBlock` + +This method retrieves the `RuleBlock` at the specified index. + +```csharp +public RuleBlock GetBlock(int i) +``` + +`GetBlock` accepts the following parameter. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `i` | int | required | Zero-based index of the block to retrieve. | + +This method returns the `RuleBlock` at the given index. + +### `GetBlockIndex` + +This method returns the index of the given `RuleBlock` within the Rule. + +```csharp +public int GetBlockIndex(RuleBlock block) +``` + +`GetBlockIndex` accepts the following parameter. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `block` | RuleBlock | required | The `RuleBlock` whose index to find. | + +This method returns an `int` index, or `-1` if the block is not found. + +### `RemoveBlockAt` + +This method removes the `RuleBlock` at the specified index. + +```csharp +public void RemoveBlockAt(int index) +``` + +`RemoveBlockAt` accepts the following parameter. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `index` | int | required | Zero-based index of the block to remove. | + +### `RemoveBlock` + +This method removes a specific `RuleBlock` instance from the Rule. + +```csharp +public void RemoveBlock(RuleBlock block) +``` + +`RemoveBlock` accepts the following parameter. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `block` | RuleBlock | required | The `RuleBlock` instance to remove. | + +### `AppendBlock` + +This method adds a `RuleBlock` to the end of the Rule and sets its back-reference to this Rule. + +```csharp +public void AppendBlock(RuleBlock block) +``` + +`AppendBlock` accepts the following parameter. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `block` | RuleBlock | required | The `RuleBlock` instance to append. | + +### `InsertBlock` + +This method inserts a `RuleBlock` at the specified index, shifting subsequent blocks down. If `index` is beyond the last position, the block is appended instead. + +```csharp +public void InsertBlock(RuleBlock block, int index) +``` + +`InsertBlock` accepts the following parameters. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `block` | RuleBlock | required | The `RuleBlock` instance to insert. | +| `index` | int | required | Zero-based position at which to insert the block. | + +## Rule properties + +The Rule API reference contains the following properties. + +### `Name` + +```csharp +public string Name { get; set; } +``` + +The display name of the Rule. Setting this property notifies the UI. + +> **Note:** C# property names are case-sensitive. Use `Name` (capital N) — `name` does not exist and will not compile. + +```csharp +rule.Name = "My Rule"; +string ruleName = rule.Name; +``` + +### `IsEnabled` + +```csharp +public bool IsEnabled { get; set; } +``` + +Controls whether the Rule is active within its RuleSet. When `false`, the Rule is skipped during execution. Setting this property notifies the UI. + +### `BlocksCount` + +```csharp +public int BlocksCount { get; } +``` + +The number of `RuleBlock` instances currently in the Rule. + +### `Blocks` + +```csharp +public IEnumerable Blocks { get; } +``` + +An enumerable over all `RuleBlock` instances in the Rule, in execution order. diff --git a/skills/asset-transformer-toolkit/api-docs/ruleblock-api.md b/skills/asset-transformer-toolkit/api-docs/ruleblock-api.md new file mode 100644 index 0000000..97cf80a --- /dev/null +++ b/skills/asset-transformer-toolkit/api-docs/ruleblock-api.md @@ -0,0 +1,37 @@ +## ActionBase properties + +### `Id` + +```csharp +public abstract int Id { get; } +``` + +A unique integer identifier for an action type. Pass this to the `RuleBlock(int actionId)` constructor. + +## RuleBlock constructors + +The RuleBlock API reference contains the following constructors. + +### `RuleBlock(int actionId)` + +This constructor creates a RuleBlock that will execute the action identified by `actionId`. The action instance is created lazily on first access. + +```csharp +public RuleBlock(int actionId) +``` + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `actionId` | int | required | The ID of the action this RuleBlock will trigger. Use `ActionBase.Id` to obtain this value from an action instance. | + +## RuleBlock properties + +The RuleBlock API reference contains the following properties. + +### `IsEnabled` + +```csharp +public bool IsEnabled { get; set; } +``` + +Controls whether this block is active within its Rule. When `false`, the block is skipped during execution. diff --git a/skills/asset-transformer-toolkit/api-docs/ruleset-api.md b/skills/asset-transformer-toolkit/api-docs/ruleset-api.md new file mode 100644 index 0000000..fbc40ee --- /dev/null +++ b/skills/asset-transformer-toolkit/api-docs/ruleset-api.md @@ -0,0 +1,138 @@ +## Contents +- [RuleSet methods](#ruleset-methods) — `GetRule`, `GetRuleIndex`, `RemoveRuleAt`, `RemoveRule`, `InsertRule`, `AppendRule`, `IsValid` +- [RuleSet properties](#ruleset-properties) — `RulesCount` +- [RuleSet utility functions](#ruleset-utility-functions) — `RunRuleSet` + +--- + +## RuleSet methods + +The RuleSet API reference contains the following methods. + +### `GetRule` + +This method retrieves the `Rule` at the specified index. + +```csharp +public Rule GetRule(int i) +``` + +`GetRule` accepts the following parameter. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `i` | int | required | Zero-based index of the rule to retrieve. | + +This method returns the `Rule` at the given index. + +### `GetRuleIndex` + +This method returns the index of the given `Rule` within the RuleSet. Returns `-1` and logs an error if the RuleSet is currently running. + +```csharp +public int GetRuleIndex(Rule rule) +``` + +`GetRuleIndex` accepts the following parameter. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `rule` | Rule | required | The `Rule` whose index to find. | + +This method returns an `int` index, or `-1` if the RuleSet is running or the rule is not found. + +### `RemoveRuleAt` + +This method removes the rule at the specified index. Has no effect and logs an error if the RuleSet is currently running. + +```csharp +public void RemoveRuleAt(int index) +``` + +`RemoveRuleAt` accepts the following parameter. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `index` | int | required | Zero-based index of the rule to remove. | + +### `RemoveRule` + +This method removes a specific `Rule` instance from the RuleSet. Has no effect and logs an error if the RuleSet is currently running. + +```csharp +public void RemoveRule(Rule rule) +``` + +`RemoveRule` accepts the following parameter. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `rule` | Rule | required | The `Rule` instance to remove. | + +### `InsertRule` + +This method inserts a `Rule` at the specified index, shifting subsequent rules down. Has no effect and logs an error if the RuleSet is currently running. + +```csharp +public void InsertRule(int index, Rule rule, bool notify) +``` + +`InsertRule` accepts the following parameters. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `index` | int | required | Zero-based position at which to insert the rule. | +| `rule` | Rule | required | The `Rule` instance to insert. | +| `notify` | bool | required | When `true`, notifies the UI that the RuleSet has changed. | + +### `AppendRule` + +This method adds a `Rule` to the end of the RuleSet. Has no effect and logs an error if the RuleSet is currently running. + +```csharp +public void AppendRule(Rule rule) +``` + +`AppendRule` accepts the following parameter. + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `rule` | Rule | required | The `Rule` instance to append. | + +### `IsValid` + +This method validates that every enabled action in the RuleSet has valid input. It skips disabled rules. + +```csharp +public bool IsValid() +``` + +This method accepts no parameters. It returns `true` if all enabled actions pass validation, or `false` if any action reports an error. + +## RuleSet properties + +The RuleSet API reference contains the following properties. + +### `RulesCount` + +```csharp +public int RulesCount { get; } +``` + +The number of `Rule` instances currently in the RuleSet. + +## RuleSet utility functions + +The following functions are from `Unity.Pixyz.Plugin4Unity.Editor.AI.ATTAssistantUtilities`. + +### `RunRuleSet` + +This function executes all rules in a RuleSet asset against the current scene selection, or the entire scene if nothing is selected. + +```csharp +public static void RunRuleSet(string rulesetPath) +``` + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `rulesetPath` | string | required | Project-relative path to the RuleSet asset to run. | diff --git a/skills/asset-transformer-toolkit/references/create-importer.md b/skills/asset-transformer-toolkit/references/create-importer.md new file mode 100644 index 0000000..f0342d7 --- /dev/null +++ b/skills/asset-transformer-toolkit/references/create-importer.md @@ -0,0 +1,121 @@ +## Contents +- [Workflow steps](#workflow) — Pre-Flight, Create Importer, Configure Importer, Import +- [Importer utility functions](#importer-utility-functions) — `EnsureImporterSaveFolder`, `GetImporterTypes`, `GetImporterProperties`, `CreateImporter`, `CanImportFile`, `ImportFile` + +--- + +If a new Importer does not need to be created, skip to Step 3 + +### Step 1: Pre-Flight +- Check whether an importer asset already exists for this file. If it does, skip to Step 3. +- Verify the file to be imported exists. +- Verify the file type is supported by Pixyz/Asset Transformer Toolkit using `ATTAssistantUtilities.CanImportFile()`. +- Check what kind of file (eg. point cloud, CAD) is it. Find the Importer type that would best match it. + +### Step 2: Create Importer +- Create the appropriate Importer asset with the path to the file to be imported. The path must be relative to the Application.dataPath. +- If there are issues, fix and revalidate. Do not exceed 3 iterations. +Do not continue if this step cannot be completed successfully. + +### Step 3: Configure Importer +- If requested, change the importer's settings. +- If requested, assign the requested RuleSet to the Importer. +- If requested, make changes to the LOD generation. +Continue only if asked to also import the file. The import process can be very long, so NEVER assume you must import the file unless it was requested. + +### Step 4: Import +- Start the asynchronous import using `ATTAssistantUtilities.ImportFile()`. +- Report whether the import process started successfully. Remind the user this is a background process. + +## Importer utility functions + +The following functions are from `Unity.Pixyz.Plugin4Unity.Editor.AI.ATTAssistantUtilities`. + +### `EnsureImporterSaveFolder` + +Returns the project-relative asset save folder configured in Asset Transformer Toolkit Project Settings, creating it if it does not already exist. Use this as the destination path when creating a new `ImporterScriptableObject` asset. + +```csharp +public static string EnsureImporterSaveFolder() +``` + +Returns a `string` such as `"Assets/3DModels"`. + +### `GetImporterTypes` + +Returns the names of all `ImporterScriptableObject` types available in the project, including user-defined importers. Always call this before creating or referencing an importer type — never assume a type exists. + +```csharp +public static string[] GetImporterTypes() +``` + +Returns a `string[]` of unqualified type names (e.g. `"CADImporterScriptableObject"`). + +### `GetImporterProperties` + +Returns the public serialized fields of an `ImporterScriptableObject` type by name, including fields from intermediate base classes. Use this to discover what settings are available on any importer type — concrete importer classes may be internal or user-defined. + +```csharp +public static ImporterPropertyInfo[] GetImporterProperties(string typeName) +``` + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `typeName` | string | required | Unqualified type name as returned by `GetImporterTypes()`. | + +Returns an `ImporterPropertyInfo[]`. Each entry has the following fields: + +| Field | Type | Description | +|-------|------|-------------| +| `Name` | string | Human-readable property name. | +| `Type` | string | Unqualified type name of the field. | +| `SerializedPropertyPath` | string | The exact string to pass to `SerializedObject.FindProperty`. For auto-properties declared with `[field: SerializeField]`, this differs from `Name` (e.g. `k__BackingField`). Always use this field — never construct the path from `Name` yourself. | + +### `CreateImporter` + +Creates a new `ImporterScriptableObject` asset for the given file. Call `GetImporterTypes()` first to confirm the type name — never assume or invent one. Use `EnsureImporterSaveFolder()` to get the correct save path. + +```csharp +public static string CreateImporter(string filePath, string typeName, string savePath) +``` + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `filePath` | string | required | Absolute system path to the 3D file the importer will reference. | +| `typeName` | string | required | Unqualified importer type name as returned by `GetImporterTypes()`. | +| `savePath` | string | required | Project-relative folder path where the importer asset will be saved. | + +Returns a `string` with the project-relative path to the created asset (e.g. `"Assets/3DModels/MyModel.asset"`). Pass this path to `ImportFile` to trigger import. + +### `CanImportFile` + +Checks whether the Asset Transformer Toolkit supports a file format. Call this before `ImportFile` to avoid runtime errors. Throws if no file exists at `filePath`. + +```csharp +public static bool CanImportFile(string filePath) +``` + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `filePath` | string | required | Absolute system path to the 3D file to check. | + +Returns `true` if the file format is supported, `false` otherwise. + +### `ImportFile` + +Triggers import or re-import using an existing `ImporterScriptableObject` asset. Requires an `ImporterScriptableObject` to already exist at `importerPath`. + +```csharp +public static void ImportFile(string importerPath) +``` + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `importerPath` | string | required | Project-relative path to the `ImporterScriptableObject` asset. | + +### Technical Notes +- Because import is an asynchronous process, the imported files may not yet exist in the project by the time the prompt finishes execution. +- The imported model will always be saved to the same directory that the ImporterScriptableObject lives in. +- Importers are designed to be extended. Check which Importer types exist in the project using `ATTAssistantUtilities.GetImporterTypes()` instead of making assumptions like a point cloud file always maps to the PointCloudImporterScriptableObject. +- Only one import should be processing at a time. +- When creating a new ImporterScriptableObject, save it under the folder returned by `ATTAssistantUtilities.EnsureImporterSaveFolder()`. This reflects the user-configured save folder from Project Settings and defaults to `"Assets/3DModels"`. diff --git a/skills/asset-transformer-toolkit/references/lods.md b/skills/asset-transformer-toolkit/references/lods.md new file mode 100644 index 0000000..9e4a768 --- /dev/null +++ b/skills/asset-transformer-toolkit/references/lods.md @@ -0,0 +1,61 @@ +Choose a path depending on the task. + +### Path A: CADImporterScriptableObject +Choose this path if working with an object that is or inherits from CADImporterScriptableObject. +- Identify the types of LODs available in the project. Choose the one(s) most appropriate for your case. +- Find the LODGenerator property in the Importer. +- Execute the requested task. +- Verify the number of rules present in the Generator does not exceed 7. + +### Path B: Scene Object +Choose this path when asked to work with a scene asset directly. +- Add a UnityEngine.PixyzPlugin4Unity.Components.LODGeneratorComponent script to the GameObject if one doesn't exist anywhere in the hierarchy. +- Execute the given task. + +### Path C: PointCloudImporter +Choose this path when working with a PointCloudImporterScriptableObject object. +- The PointCloudImporter only permits enabling/disabling LOD generation and setting the number of LODs to be generated. Other actions like choosing the type of LODRule to apply is unsupported. +- Models imported by the PointCloudImporter will not have a LODGeneratorComponent script attached to them. +- If the task is permitted, execute it. + +### Path D: Other Importer +Choose this path if working with a different importer type. +- This is a user defined importer and not part of the base Asset Transformer Toolkit package. Precise instructions cannot be provided. +- Attempt to perform the requested task, but do not exceed three iterations. +- If the task cannot be performed successfully, inform the user working with this object is not currently supported by Assistant. + +## LOD utility functions + +The following functions are from `Unity.Pixyz.Plugin4Unity.Editor.AI.ATTAssistantUtilities`. + +### `GetLODRules` + +Returns all available `LODRule` implementations and their parameters. Use this before constructing or modifying a LOD configuration to discover valid types. + +```csharp +public static LODRuleDescription[] GetLODRules() +``` + +Returns a `LODRuleDescription[]`, each containing the type name, assembly-qualified name, and parameter list. + +### `LODRuleDescription` + +| Field | Type | Description | +|-------|------|-------------| +| `Name` | string | Unqualified class name of the LODRule type. | +| `QualifiedName` | string | Assembly-qualified name, suitable for `Type.GetType`. | +| `Parameters` | `LODParameterInfo[]` | Configurable properties on this LODRule type. | + +### `LODParameterInfo` + +| Field | Type | Description | +|-------|------|-------------| +| `Name` | string | Property name. | +| `Type` | string | Property type name. | + +### Technical Notes +- The user will need to refresh the Inspector to see changes applied by Assistant. +- In an Importer's settings for LOD generation, the number of LODs set to generate does not include LOD0. There will always be one more LOD than the setting says. For example, setting the PointCloudImporter's NumberofLODs setting to 1 will result in the model having two LODs: LOD0 and LOD1. +- While Unity supports up to 8 LODs including LOD0, the PointCloudImporter is a special case that only supports 7. +- With the exception of models imported by the PointCloudImporter, models that were imported with LODs will have a LODGeneratorComponent script. +- LODs have nothing to do with RuleSets and Actions. RuleSets and Actions will NOT help with any LOD-related task. diff --git a/skills/asset-transformer-toolkit/references/rulesets-and-actions.md b/skills/asset-transformer-toolkit/references/rulesets-and-actions.md new file mode 100644 index 0000000..834f21a --- /dev/null +++ b/skills/asset-transformer-toolkit/references/rulesets-and-actions.md @@ -0,0 +1,227 @@ +## Contents +- [Actions](#actions) +- [RuleSets](#rulesets) + - Description + - Modifying RuleSets + - Creating RuleSets + - Setting Action Parameters + - Running RuleSets + - Validation Checklist +- [Action utility functions](#action-utility-functions) — `GetActionsList`, `GetActionDefinitions`, `SetActionParameter` +- [Action utility output types](#action-utility-output-types) — `ActionInfo`, `ActionDefinition`, `ActionParameterInfo`, `EnumInfo` + +--- + +## Actions + +Actions are classes derived from UnityEditor.PixyzPlugin4Unity.Actions.ActionBase that execute a task on a list of input objects. +It is expected that users will create additional Action classes to extend the Actions available in the base package. + +## RuleSets + +### Description +RuleSets are a SerializedObject containing a list of Rule instances, which contain a list of Action instances. RuleSets are used to ensure a set of Actions are executed in a specific order. +RuleSets are derived from ScriptableObject and must end with the '.asset' extension. +RuleSets support conversion to json. This will include information about the Actions they contain. + +### Modifying RuleSets + +#### Step 1: Load RuleSet +- Use AssetDatabase.LoadAssetAtPath to load the asset from memory. + +#### Step 2: Construct the script +- Read the API reference for the RuleSet class. Also read the API reference for the Rule and RuleBlock classes if required. +- Construct a script using the APIs from those files, to run as C# in a live Editor. Here is an + example that adds a Decimate Action to a RuleSet: + +```csharp +using UnityEngine; +using UnityEditor; +using UnityEditor.PixyzPlugin4Unity.RuleEngine; + +string path = "Assets/Rulesets/OptimizationRuleSet.asset"; +RuleSet ruleSet = AssetDatabase.LoadAssetAtPath(path); + +if (ruleSet == null) + throw new System.Exception($"RuleSet not found at {path}"); + +Undo.RecordObject(ruleSet, "Add Decimate action"); + +if (ruleSet.RulesCount == 0) + throw new System.Exception($"No rules found in RuleSet {path}"); + +Rule rule = ruleSet.GetRule(0); + +// Decimate Action ID is 277054868 +RuleBlock decimateBlock = new RuleBlock(277054868); + +rule.AppendBlock(decimateBlock); + +EditorUtility.SetDirty(ruleSet); +AssetDatabase.SaveAssets(); + +return $"Added Decimate action to {path} (Rule index 0)"; +``` + +A proper script for modifying a RuleSet has the following traits: +- Does not use the ScriptableObject API (this bypasses necessary event triggers). + +#### Step 3: Validation +- Run the script as C# in a live Editor. +- Validate the RuleSet against the validation checklist. + + +### Creating RuleSets + +#### Step 1: Create RuleSet +- Create the UnityEditor.PixyzPlugin4Unity.RuleEngine.RuleSet asset. +Continue to Step 2 if actions need to be added to the RuleSet. If not, add the GetContextGameObjects action and jump to Step 3. + +#### Step 2: Add Actions + +**Preflight** +- Ensure the RuleSet exists. +- Choose the combination of Actions that will best perform the requested procedure. NEVER create new Actions without explicit permission. Instead, use the Actions returned by `GetActionsList`. +- Divide Actions into Rules based on the GameObject they need to act upon. Each Rule initially executes on every GameObject unless the input is narrowed with a Filter action. Example: If only lights need to be disabled and only meshes with >10000 vertices need to be decimated, two rules will be needed as this is two different groups of GameObjects. + +**Adding Rules** +- Check whether the existing Rule(s) in the RuleSet is just the GetContextGameObjects action. If it is, append the group of actions to it rather than creating a new Rule. +- If a new Rule needs to be created, add it to the RuleSet. +- Add Actions to the Rules. +- Set action parameters if required — see Setting Action Parameters below. + +**Technical Notes** +- All Actions derive from the ActionBase class. +- Actions are located in the UnityEditor.PixyzPlugin4Unity.Actions namespace. + +#### Step 3: Validation +- Validate the RuleSet logic using the validation checklist. + + +### Setting Action Parameters + +#### Step 1: Gather data +- Gather any missing information needed to call `ATTAssistantUtilities.SetActionParameter`. If you need to retrieve a GlobalObjectId, first read the GlobalObjectId class to choose the correct function to call. +- Call `ATTAssistantUtilities.SetActionParameter` to set the parameter. +- If the result is false and not an exception, retry a maximum of three times. +- Follow a path based on the result. + +#### Path A: AITypeSecurityException +Follow these steps if `ATTAssistantUtilities.SetActionParameter` threw an AITypeSecurityException. +- Inform the user the parameter cannot be set programmatically for security reasons. +- Advise the user to manually set the parameter and what value to set it to. + +#### Path B: Exception +Follow these steps if `ATTAssistantUtilities.SetActionParameter` threw any other exception. +- Warn the user the property was unable to be set. +- Advise the user to manually set the parameter and what value to set it to. + +#### Path C: Success +Perform these steps if `ATTAssistantUtilities.SetActionParameter` returned true. +- If the property was set to a scene GameObject, NEVER validate it because it is not persistent. INSTEAD warn the user the property value is temporary and will be lost. +- Report the success to the user. + +#### Path D: Failure +Perform this step if `ATTAssistantUtilities.SetActionParameter` always returns false. +- Report the failure to the user and advise them to set the parameter manually. Tell them what the property should be set to. + +All paths are exclusive. + +**Technical Notes** +- For the Decimate action specifically, if mesh quality is going to be set to a preset, the Criterion parameter must also be set to Quality. +- Prefer using presets when possible rather than individually setting each value. +- If a preset is used, avoid changing values the preset changed unless requested otherwise. + +**Safety & Constraints** +1. **One-Strike Rule**: If `ATTAssistantUtilities.SetActionParameter` throws an AITypeSecurityException, you MUST TERMINATE the task immediately. Do NOT use raw C# execution, reflection, or any other method to bypass this. Follow the steps in Path A as your final actions. + + +### Running RuleSets +Use `ATTAssistantUtilities.RunRuleSet()` instead of the RuleSet's public API to run a RuleSet. +Only one RuleSet must be running at a time. +When running a RuleSet, remind the user it is a background task/asynchronous. + + +### Validation Checklist +- The first Action in each Rule is GetContextGameObjects or RunRules. +- If the RunRules Action is in a Rule, it is the only Action. +- Each Rule has at least one Action. + + +## Action utility functions + +The following functions are from `Unity.Pixyz.Plugin4Unity.Editor.AI.ATTAssistantUtilities`. + +### `GetActionsList` + +Returns all Rule Engine actions available in the project, including user-defined actions. Use this when you do not already know an action's ID. Pass the returned IDs to `GetActionDefinitions` to inspect parameters. + +```csharp +public static ActionInfo[] GetActionsList() +``` + +Returns an `ActionInfo[]` containing the name, tooltip, and ID of every available action. + +### `GetActionDefinitions` + +Returns parameter definitions for one or more actions by unqualified class name (e.g. `"Decimate"`, not `"UnityEditor.PixyzPlugin4Unity.Actions.Decimate"`). Use this before `SetActionParameter` to obtain correct parameter names and types. Throws if an action class name is not found. + +```csharp +public static ActionDefinition[] GetActionDefinitions(string[] actionClassNames) +``` + +Returns an `ActionDefinition[]`, each containing the action ID and its full parameter list. + +### `SetActionParameter` + +Sets a `UserParameter` field value on an action within a RuleSet. Use `GetActionDefinitions` first to obtain the correct parameter name. Returns `false` if the field was not found. + +```csharp +public static bool SetActionParameter(string ruleSetPath, int ruleIndex, int ruleblockIndex, string parameterName, string value) +``` + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------| +| `ruleSetPath` | string | required | Project-relative path to the RuleSet asset. | +| `ruleIndex` | int | required | Zero-based index of the rule containing the action. | +| `ruleblockIndex` | int | required | Zero-based index of the action block within the rule. | +| `parameterName` | string | required | The `ParameterPath` value from `GetActionDefinitions`. Must not be fully qualified. | +| `value` | string | required | String representation of the value to set. For Unity assets or scene objects, provide a `GlobalObjectId` string. For `LayerMask`, use layer names separated by `\|`. | + +Returns `true` if the parameter was set and the RuleSet saved, `false` if the field was not found. + +## Action utility output types + +### `ActionInfo` + +| Field | Type | Description | +|-------|------|-------------| +| `Name` | string | Fully qualified class name of the action. | +| `Description` | string | Tooltip text describing what the action does. | +| `ID` | int | Unique integer ID. Pass to `GetActionDefinitions` or use as `RuleBlock` action ID. | + +### `ActionDefinition` + +| Field | Type | Description | +|-------|------|-------------| +| `ID` | int | Unique integer ID of the action. | +| `Parameters` | `ActionParameterInfo[]` | All configurable `UserParameter` fields on the action. | + +### `ActionParameterInfo` + +| Field | Type | Description | +|-------|------|-------------| +| `Name` | string | Immediate field name. | +| `ParameterPath` | string | Full dot-separated path to pass as `parameterName` to `SetActionParameter` (e.g. `"advancedParametersQuality.surfacicTolerance"`). | +| `Type` | string | Fully qualified type name of the field. | +| `Description` | string | Tooltip describing the parameter. | +| `IsConditional` | bool | `true` if this parameter is only visible under certain conditions. | +| `PossibleEnumValues` | `EnumInfo[]` | Valid values if the parameter is an enum type. | +| `NestedParameters` | `ActionParameterInfo[]` | Child parameters for struct fields. | + +### `EnumInfo` + +| Field | Type | Description | +|-------|------|-------------| +| `Label` | string | Name of the enum value. | +| `Value` | Int64 | Underlying integer value of the enum member. |