Various tools for making KSP mods
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

216 lines
8.0 KiB

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<GameObject>();
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<GameObject> 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<MeshFilter>();
// 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<MeshRenderer>().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<MeshFilter>());
Object.DestroyImmediate(t.GetComponent<MeshRenderer>());
for (var i = 1; i < combines.Length; i++) Object.DestroyImmediate(meshes[i]);
// assign mesh and material to this gameobject
var filter = t.gameObject.AddComponent<MeshFilter>();
var renderer = t.gameObject.AddComponent<MeshRenderer>();
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<MeshFilter>();
var renderer = t.GetComponent<MeshRenderer>();
if (filter == null) Debug.LogWarning("Error processing " + t.name + ": no mesh filter available");
var collider = t.gameObject.AddComponent<MeshCollider>();
collider.sharedMesh = filter.sharedMesh;
collider.convex = true;
Object.DestroyImmediate(renderer);
Object.DestroyImmediate(filter);
}
if (t.name.Contains("_SPHERECOLLIDER"))
{
var filter = t.GetComponent<MeshFilter>();
var renderer = t.GetComponent<MeshRenderer>();
if (filter == null) Debug.LogWarning("Error processing " + t.name + ": no mesh filter available");
var aabb = filter.sharedMesh.bounds;
var collider = t.gameObject.AddComponent<SphereCollider>();
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<MeshFilter>();
var renderer = t.GetComponent<MeshRenderer>();
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<CapsuleCollider>();
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<MeshFilter>();
var renderer = t.GetComponent<MeshRenderer>();
if (filter == null) Debug.LogWarning("Error processing " + t.name + ": no mesh filter available");
var aabb = filter.sharedMesh.bounds;
var collider = t.gameObject.AddComponent<BoxCollider>();
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<Animation>();
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<GameObject> 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;
}
AnimationUtility.SetEditorCurve(clip, b, null);
}
}
}
}