[unity] Implement build preprocessor for prefabs cleanup

With the new prefab processing there is an issue where the mesh tries to
get into the build. To prevent this a build pre/post process is
introduced that will clean up the prefab from the meshes before the
build and restore the prefab meshes after the build.

This change reverts bf70a62f1 and is related to #1273,#1931.
This commit is contained in:
Vladislav Hristov 2021-08-06 11:12:46 +03:00
parent bf70a62f1b
commit 4a9f7b8a7b
3 changed files with 173 additions and 2 deletions

View File

@ -0,0 +1,132 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated January 1, 2020. Replaces all prior versions.
*
* Copyright (c) 2013-2020, Esoteric Software LLC
*
* Integration of the Spine Runtimes into software or otherwise creating
* derivative works of the Spine Runtimes is permitted under the terms and
* conditions of Section 2 of the Spine Editor License Agreement:
* http://esotericsoftware.com/spine-editor-license
*
* Otherwise, it is permitted to integrate the Spine Runtimes into software
* or otherwise create derivative works of the Spine Runtimes (collectively,
* "Products"), provided that each user of the Products must obtain their own
* Spine Editor license and redistribution of the Products in any form must
* include this license and copyright notice.
*
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
#if UNITY_2018_1_OR_NEWER
#define HAS_BUILD_PROCESS_WITH_REPORT
#endif
#if UNITY_2020_2_OR_NEWER
#define HAS_ON_POSTPROCESS_PREFAB
#endif
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using UnityEditor.Build;
#if HAS_BUILD_PROCESS_WITH_REPORT
using UnityEditor.Build.Reporting;
#endif
namespace Spine.Unity.Editor {
public class SpineBuildProcessor
{
internal static bool isBuilding = false;
#if HAS_ON_POSTPROCESS_PREFAB
static List<string> prefabsToRestore = new List<string>();
#endif
internal static void PreprocessBuild()
{
isBuilding = true;
#if HAS_ON_POSTPROCESS_PREFAB
var assets = AssetDatabase.FindAssets("t:Prefab");
foreach(var asset in assets) {
string assetPath = AssetDatabase.GUIDToAssetPath(asset);
GameObject g = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
if (SpineEditorUtilities.CleanupSpinePrefabMesh(g)) {
prefabsToRestore.Add(assetPath);
}
}
AssetDatabase.SaveAssets();
#endif
}
internal static void PostprocessBuild()
{
isBuilding = false;
#if HAS_ON_POSTPROCESS_PREFAB
foreach (string assetPath in prefabsToRestore) {
GameObject g = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
SpineEditorUtilities.SetupSpinePrefabMesh(g, null);
}
AssetDatabase.SaveAssets();
#endif
}
}
public class SpineBuildPreprocessor :
#if HAS_BUILD_PROCESS_WITH_REPORT
IPreprocessBuildWithReport
#else
IPreprocessBuild
#endif
{
public int callbackOrder {
get { return -2000; }
}
#if HAS_BUILD_PROCESS_WITH_REPORT
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
{
SpineBuildProcessor.PreprocessBuild();
}
#else
void IPreprocessBuild.OnPreprocessBuild(BuildTarget target, string path)
{
SpineBuildProcessor.PreprocessBuild();
}
#endif
}
public class SpineBuildPostprocessor :
#if HAS_BUILD_PROCESS_WITH_REPORT
IPostprocessBuildWithReport
#else
IPostprocessBuild
#endif
{
public int callbackOrder {
get { return 2000; }
}
#if HAS_BUILD_PROCESS_WITH_REPORT
void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report)
{
SpineBuildProcessor.PostprocessBuild();
}
#else
void IPostprocessBuild.OnPostprocessBuild(BuildTarget target, string path)
{
SpineBuildProcessor.PostprocessBuild();
}
#endif
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ca21cb19ac5068ee796e6cb09ff11e5d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -102,8 +102,18 @@ namespace Spine.Unity.Editor {
#if HAS_ON_POSTPROCESS_PREFAB
// Post process prefabs for setting the MeshFilter to not cause constant Prefab override changes.
void OnPostprocessPrefab (GameObject g) {
if (SpineBuildProcessor.isBuilding)
return;
SetupSpinePrefabMesh(g, context);
}
public static bool SetupSpinePrefabMesh(GameObject g, UnityEditor.AssetImporters.AssetImportContext context)
{
bool wasModified = false;
var skeletonRenderers = g.GetComponentsInChildren<SkeletonRenderer>(true);
foreach (SkeletonRenderer renderer in skeletonRenderers) {
wasModified = true;
var meshFilter = renderer.GetComponent<MeshFilter>();
if (meshFilter == null)
meshFilter = renderer.gameObject.AddComponent<MeshFilter>();
@ -114,9 +124,27 @@ namespace Spine.Unity.Editor {
var mesh = meshFilter.sharedMesh;
string meshName = string.Format("Skeleton Prefab Mesh \"{0}\"", renderer.name);
mesh.name = meshName;
mesh.hideFlags = HideFlags.DontSaveInEditor; // removed flag DontSaveInBuild, prevents a build error when the prefab is referenced
context.AddObjectToAsset(meshName, mesh);
if (context != null)
context.AddObjectToAsset(meshFilter.sharedMesh.name, meshFilter.sharedMesh);
}
return wasModified;
}
public static bool CleanupSpinePrefabMesh(GameObject g)
{
bool wasModified = false;
var skeletonRenderers = g.GetComponentsInChildren<SkeletonRenderer>(true);
foreach (SkeletonRenderer renderer in skeletonRenderers) {
var meshFilter = renderer.GetComponent<MeshFilter>();
if (meshFilter != null) {
if (meshFilter.sharedMesh) {
wasModified = true;
meshFilter.sharedMesh = null;
meshFilter.hideFlags = HideFlags.None;
}
}
}
return wasModified;
}
#endif