{"id":13662394,"url":"https://github.com/GieziJo/ScriptableObjectVariant","last_synced_at":"2025-04-25T10:31:07.520Z","repository":{"id":37233863,"uuid":"331452069","full_name":"GieziJo/ScriptableObjectVariant","owner":"GieziJo","description":"Unity Odin editor helper which permits to set a \"SOVariant\" attribute to a ScriptableObject and override, or not, certain fields (similar to prefab variants but for scriptable objects).","archived":false,"fork":false,"pushed_at":"2024-01-05T15:30:15.000Z","size":476,"stargazers_count":51,"open_issues_count":8,"forks_count":4,"subscribers_count":2,"default_branch":"master","last_synced_at":"2024-08-02T05:13:54.292Z","etag":null,"topics":["inspector","odin-inspector","scriptableobject","unity3d"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/GieziJo.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2021-01-20T22:43:18.000Z","updated_at":"2024-07-16T02:45:29.000Z","dependencies_parsed_at":"2024-01-05T16:45:43.711Z","dependency_job_id":null,"html_url":"https://github.com/GieziJo/ScriptableObjectVariant","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GieziJo%2FScriptableObjectVariant","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GieziJo%2FScriptableObjectVariant/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GieziJo%2FScriptableObjectVariant/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/GieziJo%2FScriptableObjectVariant/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/GieziJo","download_url":"https://codeload.github.com/GieziJo/ScriptableObjectVariant/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":223996570,"owners_count":17238330,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["inspector","odin-inspector","scriptableobject","unity3d"],"created_at":"2024-08-02T05:01:57.488Z","updated_at":"2024-11-10T18:30:18.705Z","avatar_url":"https://github.com/GieziJo.png","language":"C#","funding_links":[],"categories":["C\\#","Code and Component Generation"],"sub_categories":[],"readme":"[![Releases](https://img.shields.io/github/release/GieziJo/ScriptableObjectVariant.svg)](https://github.com/GieziJo/ScriptableObjectVariant/releases/latest)\n[![openupm](https://img.shields.io/npm/v/ch.giezi.tools.scriptableobjectvariant?label=openupm\u0026registry_uri=https://package.openupm.com)](https://openupm.com/packages/ch.giezi.tools.scriptableobjectvariant/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-brightgreen.svg)](https://github.com/GieziJo/ScriptableObjectVariant/blob/master/LICENSE.txt)\n[![twitter](https://img.shields.io/twitter/follow/JoGiezi?style=social)](https://twitter.com/JoGiezi)\n\n# Scriptable Object Variant for Unity (Scriptable Object Data Overrider)\n## Description\nAdds a field to any scriptable object tagged with the `[SOVariant]` attribute that lets you select an original SO (parent) and override selected fields in the child object.\n\nWhen changing values in the original, values are automagically propagated to the children.\n\n\u003cimg src=\"https://raw.githubusercontent.com/GieziJo/ScriptableObjectVariant/assets/ScriptableObjectOverrideDemo.gif\" width=\"100%\"\u003e\n\n## Usage\nAdd the tag `[SOVariant]` before the class header of any ScriptableObject class you want to be overridable, i.e. to be able to create a variant of.\n\nExample:\n```csharp\nusing Giezi.Tools;\n\n[SOVariant]\n[CreateAssetMenu(fileName = \"TestScriptable\", menuName = \"Create new TestScriptable\")]\npublic class TestScriptable : ScriptableObject\n{\n    [SerializeField] private float myFloat = 3L;\n    [SerializeField] private GameObject myGameObject;\n    [SerializeField] private int myInt;\n    [SerializeField] private TestScriptable myTestScriptable;\n}\n```\n\n### Create Scriptable Object Variant from context menu\n\n![Context Menu](https://raw.githubusercontent.com/GieziJo/ScriptableObjectVariant/assets/ContextMenuExample.png)\n\nIn Unity, you can right click any scriptable object tagged `SOVariant` to create a variant of this object (`Create \u003e Create SO Variant`).\nThe new object will have the selected object as parent.\n\n### Advanced usage in Editor Script\nA helper script has been implemented (`SOVariantHelper.cs`) which allows you to changed parents, override states and values from within other editor scripts.\n\nSet a new parent:\n```csharp\nScriptableObject target = AssetDatabase.LoadAssetAtPath\u003cScriptableObject\u003e(\"Assets/Tests/child.asset\");\nScriptableObject parent = AssetDatabase.LoadAssetAtPath\u003cScriptableObject\u003e(\"Assets/Tests/parent.asset\");\n        \nSOVariantHelper\u003cScriptableObject\u003e.SetParent(target, parent);\n```\n\nSet a field overridable:\n```csharp\nScriptableObject target = AssetDatabase.LoadAssetAtPath\u003cScriptableObject\u003e(\"Assets/Tests/child.asset\");\n        \nSOVariantHelper\u003cScriptableObject\u003e.ChangeFieldOverrideState(target, \"MyFloat\", true);\n```\n\nSet a new value of a field (automatically propagates to children):\n```csharp\nScriptableObject target = AssetDatabase.LoadAssetAtPath\u003cScriptableObject\u003e(\"Assets/Tests/child.asset\");\n        \nSOVariantHelper\u003cScriptableObject\u003e.ChangeFieldValue(target, \"MyFloat\", 45f);\n```\n\nSet a filed to be overridden and set new value (automatically propagates to children):\n```csharp\nScriptableObject target = AssetDatabase.LoadAssetAtPath\u003cScriptableObject\u003e(\"Assets/Tests/child.asset\");\n        \nSOVariantHelper\u003cScriptableObject\u003e.SetFieldOverrideAndSetValue(target, \"MyFloat\", 45f);\n```\n\nSet a parent and set new overridden value (automatically propagates to children):\n```csharp\nScriptableObject target = AssetDatabase.LoadAssetAtPath\u003cScriptableObject\u003e(\"Assets/Tests/child.asset\");\nScriptableObject parent = AssetDatabase.LoadAssetAtPath\u003cScriptableObject\u003e(\"Assets/Tests/parent.asset\");\n    \nSOVariantHelper\u003cScriptableObject\u003e.SetParentOverrideValue(target, parent, \"MyFloat\", 45f);\n```\n\nSet a parent and set new overridden values (automatically propagates to children):\n```csharp\nScriptableObject target = AssetDatabase.LoadAssetAtPath\u003cScriptableObject\u003e(\"Assets/Tests/child.asset\");\nScriptableObject parent = AssetDatabase.LoadAssetAtPath\u003cScriptableObject\u003e(\"Assets/Tests/parent.asset\");\n    \nSOVariantHelper\u003cScriptableObject\u003e.SetParentOverrideValues(target, parent, new Dictionary\u003cstring, object\u003e(){{\"MyFloat\", 45f},{\"MyInt\", 12}});\n```\n\n\n## Implementation\nThe visual interface is implemented in [Odin](odininspector.com/)'s [`OdinPropertyProcessor`](https://odininspector.com/tutorials/using-property-resolvers-and-attribute-processors/custom-property-processors).\nThe data with the parent and the overriden fields is kept serialized inside the asset's metadata, set in unity with `AssetImporter.GetAtPath(AssetDatabase.GetAssetPath(targetObject)).userData`.\n\n## Installation\n\u003e Requires [Odin](odininspector.com/) to be installed before adding the package\n### Using Unity's package manager\nAdd the line\n```\n\"ch.giezi.tools.scriptableobjectvariant\": \"https://github.com/GieziJo/ScriptableObjectVariant.git#master\"\n```\nto the file `Packages/manifest.json` under `dependencies`, or in the `Package Manager` add the link [`https://github.com/GieziJo/ScriptableObjectVariant.git#master`](https://github.com/GieziJo/ScriptableObjectVariant.git#master) under `+ -\u003e \"Add package from git URL...`.\n\n### Using OpenUPM\nThe package is available on [OpenUPM](https://openupm.com/packages/ch.giezi.tools.scriptableobjectvariant/).\nOpenUPM packages can be installed in different ways:\n- via [OpenUPM CLI](https://github.com/openupm/openupm-cli): `openupm add ch.giezi.tools.scriptableobjectvariant`\n- by downloading the [`.unitypackage`](https://package-installer.glitch.me/v1/installer/OpenUPM/ch.giezi.tools.scriptableobjectvariant?registry=https%3A%2F%2Fpackage.openupm.com) and adding it to your project with `Assets \u003e Import Package \u003e Custom Package...`.\n\nthe package will be added as a scoped registry, which you can inspect under `Project Settings \u003e Package Manager \u003e OpenUPM`.\n\n### Alternative\nDownload and copy all files inside your project.\n\n## Known issues and tweaks to be made\n\u003cdetails\u003e\n\u003csummary\u003eList of known issues\u003c/summary\u003e\n\n\n### [Efficiency](https://github.com/GieziJo/ScriptableObjectVariant/issues/2)\nThe attribute `[SOVariant]` only acts as tagger, which is then looked for in `SOVariantAttributeProcessor:OdinPropertyProcessor -\u003e ProcessMemberProperties`, where the first line reads:\n```csharp\nif(!Property.Attributes.Select(attribute =\u003e attribute.GetType()).Contains(typeof(SOVariantAttribute)))\n    return;\n```\nThe problem with this is that `SOVariantAttributeProcessor` is thus set to be called for every `ScriptableObject`:\n```csharp\npublic class SOVariantAttributeProcessor\u003cT\u003e : OdinPropertyProcessor\u003cT\u003e where T : ScriptableObject\n```\nThere is probably a way to directly call `SOVariantAttributeProcessor` from the attribute, but I haven't found how.\n\n### [Selecting the parent object](https://github.com/GieziJo/ScriptableObjectVariant/issues/3)\nThe selected parent should be of the exact same class as the overriden item (otherwise fields might be missing) and should not be the child itself.\nThis check is currently done when setting the parent as:\n ```csharp\nif (parent.GetType() != target.GetType())\n{\n    Debug.Log(\"Only equal types can be selected as parent\");\n    return;\n}\n\nif (AssetDatabase.GetAssetPath(parent) == AssetDatabase.GetAssetPath(target))\n{\n    Debug.Log(\"You can't select the same object as parent\");\n    return;\n}\n ```\nIt would be alot better to directly filter the possible candidates when selecting in the object, but adding the `AssetSelector` attribute with a filter, or building a custom `ValueDropdown` both did not work, not sure why.\n\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGieziJo%2FScriptableObjectVariant","html_url":"https://awesome.ecosyste.ms/projects/github.com%2FGieziJo%2FScriptableObjectVariant","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2FGieziJo%2FScriptableObjectVariant/lists"}