using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; using UnityEditor; using UnityEngine; namespace KSPTools { public class MeshPostProcessor : AssetPostprocessor { private static string[] components = new string[] {"x", "y", "z", "w"}; private void OnPostprocessModel(GameObject g) { var deleteList = new List(); Process(g.transform, deleteList); foreach (var d in deleteList) { Debug.Log("Deleting object " + d.name); Object.DestroyImmediate(d); } } private static void Process(Transform t, List deleteList) { var regex = new Regex(@"\.[0-9][0-9][0-9]"); var name = t.name; t.name = regex.Replace(name, ""); if (t.name.Contains("_DEL")) { deleteList.Add(t.gameObject); return; } if (t.name.Contains("_MERGE")) { // get all mesh filters var filters = t.GetComponentsInChildren(); // get all meshes and transforms var meshes = filters.Select(i => i.sharedMesh).ToArray(); var transforms = filters.Select(i => i.transform).ToArray(); if (meshes.Length != transforms.Length) Debug.LogError("Mesh and transformation count mismatch when attempting to process " + t.name); // generate CombineInstance array var combines = new CombineInstance[meshes.Length]; var mergedMesh = meshes[0]; var newMesh = new Mesh(); var baseMatrix = t.worldToLocalMatrix; var material = filters[0].GetComponent().sharedMaterial; for (var i = 0; i < combines.Length; i++) combines[i] = new CombineInstance { mesh = meshes[i], transform = baseMatrix * transforms[i].localToWorldMatrix }; // combine meshes into newMesh and copy data to mergedMesh // we cant use newMesh because it will disappear once importing is done, // also CombineMeshes doesnt include the base mesh in 2017.1 newMesh.CombineMeshes(combines, true, true, false); mergedMesh.vertices = newMesh.vertices; mergedMesh.normals = newMesh.normals; mergedMesh.triangles = newMesh.triangles; mergedMesh.colors = newMesh.colors; mergedMesh.boneWeights = newMesh.boneWeights; mergedMesh.uv = newMesh.uv; mergedMesh.RecalculateBounds(); mergedMesh.RecalculateTangents(); mergedMesh.name = t.name; // clear any existing MeshFilter or MeshRenderer and delete other meshes Object.DestroyImmediate(t.GetComponent()); Object.DestroyImmediate(t.GetComponent()); for (var i = 1; i < combines.Length; i++) Object.DestroyImmediate(meshes[i]); // assign mesh and material to this gameobject var filter = t.gameObject.AddComponent(); var renderer = t.gameObject.AddComponent(); filter.sharedMesh = mergedMesh; renderer.sharedMaterial = material; // add children to list for deletion at end of processing step deleteList.AddRange(transforms.Select(i => i.gameObject)); return; } if (t.name.Contains("_COLLIDER")) { var filter = t.GetComponent(); var renderer = t.GetComponent(); if (filter == null) Debug.LogWarning("Error processing " + t.name + ": no mesh filter available"); var collider = t.gameObject.AddComponent(); collider.sharedMesh = filter.sharedMesh; collider.convex = true; Object.DestroyImmediate(renderer); Object.DestroyImmediate(filter); } if (t.name.Contains("_SPHERECOLLIDER")) { var filter = t.GetComponent(); var renderer = t.GetComponent(); if (filter == null) Debug.LogWarning("Error processing " + t.name + ": no mesh filter available"); var aabb = filter.sharedMesh.bounds; var collider = t.gameObject.AddComponent(); collider.center = aabb.center; collider.radius = (aabb.size.x + aabb.size.y + aabb.size.z) / 6; Object.DestroyImmediate(renderer); Object.DestroyImmediate(filter); } if (t.name.Contains("_CAPSULECOLLIDER")) { var filter = t.GetComponent(); var renderer = t.GetComponent(); if (filter == null) Debug.LogWarning("Error processing " + t.name + ": no mesh filter available"); var aabb = filter.sharedMesh.bounds; var size = aabb.size; var collider = t.gameObject.AddComponent(); collider.center = aabb.center; if (size.x > size.y && size.x > size.z) { collider.radius = (size.y + size.z) / 4; collider.height = size.x; collider.direction = 0; } else if (size.y > size.z && size.y > size.x) { collider.radius = (size.x + size.z) / 4; collider.height = size.y; collider.direction = 1; } else { collider.radius = (size.x + size.y) / 4; collider.height = size.z; collider.direction = 2; } Object.DestroyImmediate(renderer); Object.DestroyImmediate(filter); } if (t.name.Contains("_BOXCOLLIDER")) { var filter = t.GetComponent(); var renderer = t.GetComponent(); if (filter == null) Debug.LogWarning("Error processing " + t.name + ": no mesh filter available"); var aabb = filter.sharedMesh.bounds; var collider = t.gameObject.AddComponent(); collider.center = aabb.center; collider.size = aabb.size; Object.DestroyImmediate(renderer); Object.DestroyImmediate(filter); } foreach (Transform child in t) Process(child, deleteList); var anim = t.GetComponent(); if (anim != null) { foreach (var state in anim) { var clip = ((AnimationState) state).clip; Debug.Log("Trimming animation " + clip.name); TrimAnimation(clip, t, deleteList); } } } private static void TrimAnimation(AnimationClip clip, Transform t, List deleteList) { var bindings = AnimationUtility.GetCurveBindings(clip); foreach (EditorCurveBinding b in bindings) { var curve = AnimationUtility.GetEditorCurve(clip, b); var target = (Transform) AnimationUtility.GetAnimatedObject(t.gameObject, b); if (curve.length > 2) continue; if (curve.length == 2 && !deleteList.Contains(target.gameObject)) { continue; //if (!Mathf.Approximately(curve[0].value, curve[1].value)) continue; //if (!Mathf.Approximately(curve[0].value, 0.0f) && !Mathf.Approximately(curve[0].value, 1.0f)) continue; } AnimationUtility.SetEditorCurve(clip, b, null); } } } }