# spine-unity 4.3 Split Component Upgrade Guide ## Component Architecture Restructuring > **Note:** You can find Chinese and Japanese translations of this upgrade guide right next to this file. > * [中文版 4.3 分体组件升级指南 - Chinese 4.3 Split Component Upgrade Guide](https://github.com/EsotericSoftware/spine-runtimes/tree/4.3-beta/spine-unity/Assets/Spine/Documentation/4.3-split-component-upgrade-guide-zh.md) > * [日本語版 4.3 分割コンポーネントアップグレードガイド - Japanese 4.3 Split Component Upgrade Guide](https://github.com/EsotericSoftware/spine-runtimes/tree/4.3-beta/spine-unity/Assets/Spine/Documentation/4.3-split-component-upgrade-guide-ja.md) --- ## 📋 Scope of This Document **This document covers only the spine-unity component split migration.** From version 4.2 to 4.3, there have been additional breaking changes in both spine-csharp and spine-unity that you need to address before handling the component split: - **spine-csharp API changes:** New pose system affecting bone, slot, and constraint properties For complete migration steps covering all 4.2 to 4.3 changes, please refer to: - The [CHANGELOG.md](https://github.com/EsotericSoftware/spine-runtimes/blob/4.3-beta/CHANGELOG.md#c-2) document (sections C# and Unity) - The forum post ["Spine-Unity 4.2 to 4.3 Upgrade Guide"](https://esotericsoftware.com/forum) for a comprehensive migration guide **Important:** Complete the spine-csharp API migration first, then proceed with the component split migration described in this document. --- ## ⚠️ IMPORTANT: Before You Upgrade **This warning only applies to existing projects being upgraded. New projects can safely ignore this section.** ### What Will Happen Components will be **automatically upgraded** and split into separate animation and rendering components: - `SkeletonAnimation` → `SkeletonAnimation` + `SkeletonRenderer` components - `SkeletonMecanim` → `SkeletonMecanim` + `SkeletonRenderer` components - `SkeletonGraphic` → `SkeletonAnimation` + `SkeletonGraphic` components All component settings and fields will be automatically transferred - nothing will be lost. **However:** Due to these type changes, existing references in your custom scripts may be lost because the component types no longer match (e.g., `SkeletonAnimation` is no longer a subclass of `SkeletonRenderer`). ### Required Upgrade Steps (In Order): 1. **🔒 BACKUP YOUR PROJECT** Create a complete backup before upgrading. These changes will modify your scenes and prefabs. 2. **📖 READ THIS ENTIRE DOCUMENT** Understand all breaking changes before proceeding. 3. **✏️ TEST AND UPDATE YOUR CODE** - **Update your scripts:** Fix custom scripts that reference Spine components according to this document, as your code may no longer compile when members were moved to the split classes - **Test:** Open a few test scenes to see which component references are lost. Unsaved scenes still contain the old component data and serve as a safety backup - only when you save will the split components replace the old ones and references be lost. **⚠️ WARNING:** Prefabs behave differently! Opening a prefab in Prefab Edit Mode will automatically save the component migration due to Unity's prefab auto-save feature. Always test with scenes first, not prefabs. - **Decide:** Either manually re-assign lost references, or write migration code (explained below) to handle this automatically **⚠️ IMPORTANT:** Automatic component splitting only happens when scenes/prefabs are opened in the Unity Editor. You must choose 'Upgrade All' or save each scene/prefab before building your game, otherwise the old single components won't be split and half the required components might be missing in the build! **💡 HINT:** If you encounter the Console log output "SendMessage cannot be called during Awake, CheckConsistency, or OnValidate", this is a sign that old un-migrated assets were present in the scene which were just auto-upgraded. These messages will be followed by a log message confirming that an old component was auto-migrated to split components. 4. **🔄 CHOOSE YOUR UPGRADE PATH** **Option A - Manual re-assignment (recommended for small projects):** - Open each scene and prefab individually - Manually re-assign lost references in the Inspector - Save when satisfied **Option B - Automatic migration (for large projects with many scenes/prefabs):** - Write migration code first: - Implement the reference migration pattern (see "Preventing Lost Component References" section below) - For `SkeletonGraphic` references, see "Changing Existing References to SkeletonAnimation" section - Test migration code on a few files - Then use `Upgrade All`: - Go to `Edit → Preferences → Spine` - Under "Upgrade Scenes & Prefabs" - Click `Upgrade All` button ### What Will Break If You Don't Prepare: - Component references in scenes or prefabs may be lost (set to null) once you save your scenes or prefabs - Building before upgrading all scenes/prefabs may result in missing components in the build **Do not proceed without completing steps 1-3, or you risk breaking your project.** --- ## 📦 Optional Two-Step Migration from 4.2 If you're migrating from spine-unity 4.2, you may find it easier to upgrade in two steps to isolate potential issues: ### Step 1: Upgrade to a 4.3-beta pre-split version First upgrade to a 4.3-beta version before the component split changes: - **Commit Hash**: `a07b1de` - **add package via Git URL**: `https://github.com/EsotericSoftware/spine-runtimes.git?path=spine-csharp/src#a07b1de` - or **unitypackage**: https://esotericsoftware.com/files/runtimes/unity/spine-unity-4.2-2025-09-26.unitypackage This intermediate step allows you to: - Fix any issues related to the 4.2 → 4.3 spine-csharp API changes first and ensures your project works - Verify your project is stable before proceeding - Once your project is working with this 4.3-beta version, create another backup before proceeding to step 2 ### Step 2: Upgrade to latest 4.3-beta version (with split components) Once your project is working with 4.3-beta: - Upgrade to the latest 4.3-beta package - Follow the component split migration guide above - Handle the separated animation and rendering components This two-step approach helps isolate issues - if something breaks, you'll know whether it's due to the 4.2 → 4.3 spine-csharp changes or the component split specifically. --- ## 📋 Introduction The spine-unity 4.3 runtime introduces a major architectural change: **separation of animation from rendering by using two separate components instead of component inheritance**. This enables flexible combinations like using `SkeletonMecanim` for animation with `SkeletonGraphic` for rendering, which was previously not possible. ### Key Changes: - **Component Split**: The previously monolithic components have been split into separate rendering and animation components. - **Separate Components**: `SkeletonAnimation` and `SkeletonMecanim` no longer inherit from `SkeletonRenderer`. They now work alongside a separate renderer component (a subclass of `ISkeletonRenderer`), such as `SkeletonRenderer` and `SkeletonGraphic`. - **Interface Updates**: New `ISkeletonRenderer` and `ISkeletonAnimation` interfaces with updated property names. - **Settings Grouping**: Mesh generation settings are now grouped under `MeshSettings` property. - **Automatic Migration**: The Unity Editor will automatically upgrade your components to the new split components and transfer deprecated fields when `AUTO_UPGRADE_TO_43_COMPONENTS` is defined (*the default*). - **Upgrade all Scenes and Prefabs**: To upgrade all scenes and prefabs at once, go to `Edit - Preferences - Spine` and under `Automatic Component Upgrade` hit `Upgrade Scenes & Prefabs` - `Upgrade All`. ### Component Relationships: | **Old Architecture** | **New Architecture** | |---------------------|---------------------| | `SkeletonAnimation` inherits from `SkeletonRenderer` | `SkeletonAnimation` + separate `SkeletonRenderer` component | | `SkeletonMecanim` inherits from `SkeletonRenderer` | `SkeletonMecanim` + separate `SkeletonRenderer` component | | `SkeletonGraphic` provides embedded AnimationState | `SkeletonGraphic` + separate `SkeletonAnimation` component | --- ## Adapting Your Code Here's what changes for each component: ## ▶️ SkeletonRenderer ### Breaking Changes #### 1. Interface Changes - `IHasSkeletonRenderer` interface changed property name from `SkeletonRenderer` to `Renderer`, type from `SkeletonRenderer` to `ISkeletonRenderer`. #### 2. Event Changes - `SkeletonRendererDelegate` type is no longer a nested type in `SkeletonRenderer`. To fix any compile errors, replace `SkeletonRenderer.SkeletonRendererDelegate` with `SkeletonRendererDelegate`. - `BeforeApply` delegate type changed from `SkeletonRendererDelegate` to `SkeletonAnimationDelegate`. - `SkeletonRendererDelegate` type changed from `SkeletonRendererDelegate(SkeletonRenderer)` to `SkeletonRendererDelegate(ISkeletonRenderer)`. This affects events: `OnRebuild`, `OnMeshAndMaterialsUpdated`. To fix any compile errors, change your method parameter from `SkeletonRenderer` to `ISkeletonRenderer`. - Moved bone events `UpdateLocal`, `UpdateWorld`, and `UpdateComplete` from `ISkeletonAnimation` classes (`SkeletonAnimation`, `SkeletonMecanim`) to `ISkeletonRenderer classes (SkeletonRenderer, SkeletonGraphic)`. Changed delegate type from `UpdateBonesDelegate` to `SkeletonRendererDelegate`, with parameter `ISkeletonRenderer` instead of `ISkeletonAnimation`. #### 2. Method Changes - `LateUpdateMesh()` has been changed to `UpdateMesh()`. - Removed `MeshGenerator.TryReplaceMaterials`. #### 3. Execution Order - `SkeletonRenderer` and `SkeletonGraphic` components received `DefaultExecutionOrder(1)]` which makes them run after default *(order=0)* scripts. This ensures animations are applied before the skeleton is updated even if `UpdateTiming` is set to `InLateUpdate`. #### 4. Behaviour Changes - `generateMeshOverride` is now also called when `singleSubmesh` is enabled. ### Field and Property Migration #### Mesh Generation Settings | **Old API** | **New API** | **Notes** | |-------------------|-------------------|-----------| | `skeletonRenderer.zSpacing` | `skeletonRenderer.MeshSettings.zSpacing` | Moved to MeshSettings | | `skeletonRenderer.useClipping` | `skeletonRenderer.MeshSettings.useClipping` | Moved to MeshSettings | | `skeletonRenderer.immutableTriangles` | `skeletonRenderer.MeshSettings.immutableTriangles` | Moved to MeshSettings | | `skeletonRenderer.pmaVertexColors` | `skeletonRenderer.MeshSettings.pmaVertexColors` | Moved to MeshSettings | | `skeletonRenderer.tintBlack` | `skeletonRenderer.MeshSettings.tintBlack` | Moved to MeshSettings | | `skeletonRenderer.addNormals` | `skeletonRenderer.MeshSettings.addNormals` | Moved to MeshSettings | | `skeletonRenderer.calculateTangents` | `skeletonRenderer.MeshSettings.calculateTangents` | Moved to MeshSettings | #### Hidden Lowercase Attributes - `skeletonRenderer.maskInteraction` is replaced by Property `skeletonRenderer.MaskInteraction`. #### Deprecated Lowercase Attributes - Lowercase attributes `initialFlipX`, `initialFlipY` and `initialSkinName` are now deprecated and will be removed in future runtime versions. Use the added properties of the same name but uppercase instead: `InitialFlipX`, `InitialFlipY` and `InitialSkinName`. --- ## ▶️ SkeletonAnimation ### Breaking Changes #### 1. Component Architecture - **SkeletonAnimation is now a separate component from SkeletonRenderer**, no longer a subclass. - Access renderer via: `skeletonAnimation.Renderer`. - Access animation from renderer via: `skeletonRenderer.Animation`. #### 2. Property Changes - `state` is no longer public. Use `AnimationState` property instead. - `valid` removed. Use `IsValid` instead. #### 3. Method Changes - Added `UpdateOncePerFrame()` - updates if `Update` has not been called this frame. The existing `Update(float time)` still always updates when called. - `Update()` without parameters is no longer public, use either `UpdateOncePerFrame()` to update when no update has been performed this frame, or `Update(0)` to force an animation update. ### Field and Property Migration As `SkeletonAnimation` is now a separate component, methods and properties provided by `SkeletonRenderer` can no longer be accessed directly via a `SkeletonAnimation` object. There is a `skeletonAnimation.Renderer` property available to access the associated `ISkeletonRenderer` from a `SkeletonAnimation` object, and an `skeletonRenderer.Animation` property to access the associated `ISkeletonAnimation` from a `SkeletonRenderer` or `SkeletonGraphic` object. For members that are not exposed by the `ISkeletonRenderer` interface, you can cast `skeletonAnimation.Renderer` to `SkeletonRenderer` or `SkeletonGraphic` respectively to access the renderer member variables. ### Example Code ```csharp // Old SkeletonRenderer property access from SkeletonAnimation skeletonAnimation.zSpacing = 0.1f; skeletonAnimation.AnySkeletonRendererProperty; // New SkeletonRenderer property access from SkeletonAnimation skeletonAnimation.Renderer.MeshSettings.zSpacing = 0.1f; // exposed in ISkeletonRenderer interface var skeletonRenderer = (SkeletonRenderer)skeletonAnimation.Renderer; skeletonRenderer.AnySkeletonRendererProperty; // not exposed in ISkeletonRenderer interface ``` --- ## ▶️ SkeletonMecanim ### Breaking Changes #### 1. Component Architecture - **SkeletonMecanim is now a separate component from SkeletonRenderer**, no longer a subclass. - Same access pattern as [SkeletonAnimation](#▶️-skeletonanimation). #### 2. Method Changes - `Update()` is no longer public. - Use `UpdateIfNecessary()` or `Update(0)` to force update. ### Field and Property Migration Same as [SkeletonAnimation](#▶️-skeletonanimation) above. --- ## ▶️ SkeletonGraphic ### Breaking Changes #### 1. Component Architecture - **SkeletonGraphic no longer covers animation, add SkeletonAnimation as a separate animation component**. - Animation accessed via: `skeletonGraphic.Animation`. #### 2. Changing Existing References to SkeletonAnimation If your components are holding a reference to `SkeletonGraphic` only to modify its animation properties, it is recommended to change the reference type to `SkeletonAnimation`. This way you can access animation state like `skeletonAnimation.AnimationState` instead of having to cast it like `((SkeletonAnimation)skeletonGraphic.Animation).AnimationState`. Note that if you want to change the name of serialized component variables, you can use the `[FormerlySerializedAs("previousName")]` attribute in front of a variable definition to automatically reassign your existing serialized value. #### Example Code ```csharp // Automatically reassign previous serialized values [FormerlySerializedAs("skeletonGraphic")] public SkeletonAnimation skeletonAnimation; // Will maintain the reference after upgrade ``` #### 3. Property Changes - Removed property `AnimationState` - query it from the `SkeletonAnimation` component instead. - `MeshGenerator` is no longer public - use `MeshSettings` property and `SetMeshSettings()` instead. - `MaterialsMultipleCanvasRenderers` type changed from `ExposedList` to `Material[]`. #### 4. Creation Helper Methods - `NewSkeletonGraphicGameObject` now creates both `SkeletonGraphic` and `SkeletonAnimation` to maintain existing behaviour. Return type changed to return both component references in a single struct. - `AddSkeletonGraphicComponent` is removed and replaced by: - `AddSkeletonGraphicAnimationComponents` - creates both `SkeletonGraphic` and `SkeletonAnimation` components. - `AddSkeletonGraphicRenderingComponent` - creates only `SkeletonGraphic` component. #### 5. Event Changes - Delegate signature changed from `SkeletonRendererDelegate(SkeletonGraphic)` to `SkeletonRendererDelegate(ISkeletonRenderer)`. This affects events: `OnRebuild`, `OnMeshAndMaterialsUpdated`. To fix any compile errors, change your method parameter from SkeletonGraphic to ISkeletonRenderer. #### 6. Execution Order - `SkeletonRenderer` and `SkeletonGraphic` components received `DefaultExecutionOrder(1)]` which makes them run after default *(order=0)* scripts. This ensures animations are applied before the skeleton is updated even if `UpdateTiming` is set to `InLateUpdate`. #### 7. Behaviour Changes - Material Updates - Materials at each `CanvasRenderer` are no longer updated every `LateUpdate`, instead they are updated when either: - a) the updated skeleton requires a change of materials, or - b) when `CustomMaterialOverride` or `CustomTextureOverride` were accessed and thus potentially modified. ### Field and Property Migration #### Animation Properties | **Old API** | **New API** | **Notes** | |-------------------|-------------------|-----------| | `skeletonGraphic.AnimationState` | `((SkeletonAnimation)skeletonGraphic.Animation).AnimationState` | Cast required | | `skeletonGraphic.startingAnimation` | `skeletonAnimation.AnimationName` | Via Animation component | | `skeletonGraphic.startingLoop` | `skeletonAnimation.loop` | Via Animation component | | `skeletonGraphic.timeScale` | `skeletonAnimation.timeScale` | Via Animation component | | `skeletonGraphic.unscaledTime` | `skeletonAnimation.unscaledTime` | Via Animation component | #### Mesh Generator Settings | **Old API** | **New API** | **Notes** | |-------------------|-------------------|-----------| | `skeletonGraphic.MeshGenerator.settings` | `skeletonGraphic.MeshSettings` | Direct access to settings | --- ## ⚠️ Additional Important Notes ### Preventing Lost Component References Any references by other components (e.g. `SkeletonRenderSeparator`) that reference a `SkeletonRenderer` component and had a `SkeletonAnimation` or `SkeletonMecanim` target will be pointing to *null* after the upgrade, since the `SkeletonAnimation` and `SkeletonMecanim` components are no longer subclasses of `SkeletonRenderer` and thus no valid reference. The manual solution is to leave the type as `SkeletonRenderer` and lose references to `SkeletonAnimation` (will be set to *none*). Then you need to manually re-assign the lost references in your scenes and prefabs. A semi-automatic alternative solution is as follows: change the type of your `SkeletonRenderer` variable to `Component` (to capture the object reference and not lose it) and add a second variable of type `SkeletonRenderer` (or `SkeletonAnimation`) and then programmatically read it from the `Component` variable and assign it to the newly added variable. You can e.g. do this automatically in the Unity Editor in `Awake()` with an `[ExecuteAlways]` tag added to your component. #### Example code ```csharp // Old class before upgrading public class TestMigrateReferences : MonoBehaviour { public SkeletonRenderer skeletonRenderer; // this SkeletonAnimation reference assigned here would be lost after upgrading. public void Foo () { skeletonRenderer.skeleton.ScaleX = -1; } } // New class after upgrading [ExecuteAlways] // or [ExecuteInEditMode] public class TestMigrateReferences : MonoBehaviour { #if UNITY_EDITOR [SerializeField, HideInInspector, FormerlySerializedAs("skeletonRenderer")] Component previousSkeletonRenderer; // this captures the old SkeletonAnimation reference assigned at the name skeletonRenderer. #endif public SkeletonRenderer skeletonRenderer; public void Foo () { skeletonRenderer.skeleton.ScaleX = -1; } #if UNITY_EDITOR public void Awake () { AutoUpgradeReferences(); } public void AutoUpgradeReferences () { if (previousSkeletonRenderer != null && skeletonRenderer == null) { skeletonRenderer = previousSkeletonRenderer.GetComponent(); if (skeletonRenderer != null) Debug.Log("Upgraded SkeletonRenderer reference."); } } #endif } ``` ### Component Enable/Disable Since `ISkeletonRenderer` and `ISkeletonAnimation` components are now separate, scripts that enable/disable any of these components need adjustment to **enable/disable both**. ### SkeletonUtilityBone Behaviour Change In mode Override, `SkeletonUtilityBone` no longer adjusts the Transform in `UpdatePhase.World`, only in `UpdatePhase.Complete` (removes redundant update). ### Automatic Migration - Unity Editor automatically transfers deprecated fields when `AUTO_UPGRADE_TO_43_COMPONENTS` is defined. - To upgrade all scenes and prefabs at once, go to `Edit - Preferences - Spine` and select `Upgrade Scenes & Prefabs` - `Upgrade All`. - The `UpgradeTo43` and `TransferDeprecatedFields()` methods in each class handles serialized data migration. - Manual code updates are still required for runtime access. ### Summary of Most Common Changes 1. **Add `.Renderer.`** prefix to access rendering properties from animation components. 2. **Add `.MeshSettings.`** to access mesh generation settings. 3. **Cast to SkeletonAnimation** when accessing AnimationState from SkeletonGraphic. 4. **Update delegate method signatures** from concrete types to interfaces. 5. **Re-assign lost references** after upgrade using the migration pattern above. --- ## Disabling Automatic Upgrade Checks Once you have completed the migration of all your Spine assets, scenes, and prefabs, you can disable the automatic upgrade checks to improve editor performance: 1. Go to `Edit → Preferences → Spine` 2. Under `Automatic Component Upgrade`, click `Split Component Upgrade` → `Disable` This will stop the Unity Editor from performing in-editor checks upon scene or prefab loading to determine whether components need to be migrated. You can re-enable it at any time if you need to migrate additional assets. --- ## Need Help? If you encounter any unexpected problems during migration or find that component properties are incorrectly migrated, please post on the [Spine forum](https://esotericsoftware.com/forum). We're happy to help and fix any issues to make automatic migration as painless as possible.