diff --git a/Source/KSPCommunityPartModules.csproj b/Source/KSPCommunityPartModules.csproj
index 14ed6de..134a31c 100644
--- a/Source/KSPCommunityPartModules.csproj
+++ b/Source/KSPCommunityPartModules.csproj
@@ -38,6 +38,7 @@
+
diff --git a/Source/Modules/ModuleDepthMask.cs b/Source/Modules/ModuleDepthMask.cs
new file mode 100644
index 0000000..d124932
--- /dev/null
+++ b/Source/Modules/ModuleDepthMask.cs
@@ -0,0 +1,161 @@
+/*
+ Usecase: This model allows for parts to have hollow insets that dont clip into other parts.
+ Example: Restock parts such as air intakes and deployable ladders
+ Originally By: Drew Cassidy
+ Originally For: Restock / KSP-DepthMask
+*/
+using UnityEngine;
+using System.Collections.Generic;
+
+namespace KSPCommunityPartModules
+{
+ public class ModuleDepthMask : PartModule
+ {
+ public const string MODULENAME = nameof(ModuleDepthMask);
+ // 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($"[{MODULENAME}] : [{part.partInfo?.name ?? part.name}] {message}");
+ }
+ }
+}