using UnityEngine; using UnityEngine.Serialization; using System.Collections.Generic; using System.Linq; namespace DepthMask { public class ModuleDepthMask : PartModule { // The name of the transform that has your mask mesh. The only strictly required property [KSPField] public string maskTransform = ""; [KSPField] public string bodyTransform = ""; // The name of the depth mask shader [KSPField] public string shaderName = "DepthMask"; // The render queue value for the mesh, should be less than maskRenderQueue [KSPField] public int meshRenderQueue = 1000; // the render queue value for the mask, should be less than 2000 [KSPField] public int maskRenderQueue = 1999; // depth mask object transforms public List maskTransformObjects; // body object transform public List bodyTransformObjects; // depth mask shader object public Shader depthShader; public override void OnStart(StartState state) { base.OnStart(state); UpdateAllMaterials(); // the part variant system is implemented extremely stupidly // so we have to make this whole module more complicated as a result GameEvents.onVariantApplied.Add(OnVariantApplied); GameEvents.onPartRepaired.Add(OnPartRepaired); } private void OnDestroy() { GameEvents.onVariantApplied.Remove(OnVariantApplied); GameEvents.onPartRepaired.Remove(OnPartRepaired); } public override void OnLoad(ConfigNode node) { base.OnLoad(node); if (HighLogic.LoadedSceneIsEditor || HighLogic.LoadedSceneIsFlight) return; this.maskTransformObjects = new List(); this.bodyTransformObjects = new List(); foreach (string name in maskTransform.Split(',')) { var trimmed = name.Trim(); var transforms = base.part.FindModelTransforms(trimmed); if (transforms.Length == 0) { this.LogError($"Can't find any mask transforms named {trimmed}"); } this.maskTransformObjects.AddRange(transforms); } if (this.maskTransformObjects.Count == 0) { this.LogError($"Can't find any mask transforms"); return; } if (bodyTransform.Length == 0) { this.bodyTransformObjects.Add(base.part.partTransform); } else { foreach (string name in bodyTransform.Split(',')) { var trimmed = name.Trim(); var transforms = base.part.FindModelTransforms(trimmed); if (transforms.Length == 0) { this.LogError($"Can't find any body transforms named {trimmed}"); } this.bodyTransformObjects.AddRange(transforms); } } if (this.bodyTransformObjects.Count == 0) { this.LogError($"Can't find any body transforms"); return; } this.depthShader = Shader.Find(shaderName); if (this.depthShader == null) { this.LogError($"Can't find shader {shaderName}"); return; } } public void OnVariantApplied(Part appliedPart, PartVariant variant) { // I dont know why changing part variants resets all the materials to their as-loaded state, but it does if (appliedPart == this.part) UpdateAllMaterials(); } public void OnPartRepaired(Part repairedPart) { // Part repair resets part of the mesh from the prefab, so it needs to be reapplied if (repairedPart == this.part) UpdateAllMaterials(); } private void UpdateAllMaterials() { var renderers = new List(); foreach (var body in bodyTransformObjects) { renderers.AddRange(body.GetComponentsInChildren(true)); } foreach (var renderer in renderers) { var queue = renderer.material.renderQueue; if (queue <= maskRenderQueue) continue; queue = meshRenderQueue + ((queue - 2000) / 2); renderer.material.renderQueue = queue; } foreach (var maskObject in maskTransformObjects) { var renderer = maskObject.GetComponent(); renderer.material.shader = depthShader; renderer.material.renderQueue = maskRenderQueue; } } private void LogError(string message) { Debug.LogError($"[{part.partInfo?.name ?? part.name} {this.GetType()}] {message}"); } } }