Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Source/KSPCommunityPartModules.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
<Compile Include="Modules\ModuleAutoCutDrogue.cs" />
<Compile Include="Modules\ModuleCenterFollowTransform.cs" />
<Compile Include="Modules\ModuleCoPFollowTransform.cs" />
<Compile Include="Modules\ModuleDepthMask.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
Expand Down
161 changes: 161 additions & 0 deletions Source/Modules/ModuleDepthMask.cs
Original file line number Diff line number Diff line change
@@ -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<Transform> maskTransformObjects;

// body object transform
public List<Transform> 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<Transform>();
this.bodyTransformObjects = new List<Transform>();

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<Renderer>();
foreach (var body in bodyTransformObjects)
{
renderers.AddRange(body.GetComponentsInChildren<Renderer>(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>();
renderer.material.shader = depthShader;
renderer.material.renderQueue = maskRenderQueue;
}
}

private void LogError(string message)
{
Debug.LogError($"[{MODULENAME}] : [{part.partInfo?.name ?? part.name}] {message}");
}
}
}