Skip to content

Commit

Permalink
- New KSP bugfix patch : [CorrectDragForFlags](#126), fix the "panel"…
Browse files Browse the repository at this point in the history
… variants of the flag parts using a single drag cube, causing excessive drag for the smaller options.

- Fixed [issue #124](#124) : avoid disabling the KSP-Recall "refunding" hack when the user has disabled the KSPCF "RefundingOnRecovery" patch, thus making our friend Lisias happy again.
  • Loading branch information
gotmachine committed Mar 22, 2023
1 parent 8e439c3 commit 8debc12
Show file tree
Hide file tree
Showing 8 changed files with 306 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// To see the full list of patch names, look at the Settings.cfg file or in
// the readme.

@KSP_COMMUNITY_FIXES:FINAL
@KSP_COMMUNITY_FIXES:AFTER[KSPCommunityFixes]
{
@PatchName = false
}
2 changes: 1 addition & 1 deletion GameData/KSPCommunityFixes/KSPCommunityFixes.version
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"NAME": "KSPCommunityFixes",
"URL": "https://raw.githubusercontent.com/KSPModdingLibs/KSPCommunityFixes/master/GameData/KSPCommunityFixes/KSPCommunityFixes.version",
"DOWNLOAD": "https://github.com/KSPModdingLibs/KSPCommunityFixes/releases",
"VERSION": {"MAJOR": 1, "MINOR": 24, "PATCH": 6, "BUILD": 0},
"VERSION": {"MAJOR": 1, "MINOR": 25, "PATCH": 0, "BUILD": 0},
"KSP_VERSION": {"MAJOR": 1, "MINOR": 12, "PATCH": 5},
"KSP_VERSION_MIN": {"MAJOR": 1, "MINOR": 8, "PATCH": 0},
"KSP_VERSION_MAX": {"MAJOR": 1, "MINOR": 12, "PATCH": 5}
Expand Down
26 changes: 23 additions & 3 deletions GameData/KSPCommunityFixes/MMPatches/ModSupport/KSPRecall.cfg
Original file line number Diff line number Diff line change
@@ -1,12 +1,32 @@
@PART[*]:HAS[@MODULE[Refunding]]:NEEDS[KSPRECALL-REFUNDING]:FINAL
@PART[*]:HAS[@MODULE[Refunding]]:LAST[999_KSP-Recall]
{
!MODULE[Refunding]{}
hasRefundingOnRecovery = #$@KSP_COMMUNITY_FIXES/RefundingOnRecovery$
}

@KSP-Recall:AFTER[999_KSP-Recall]
@PART[*]:HAS[#hasRefundingOnRecovery[?rue]]:LAST[999_KSP-Recall]
{
!MODULE[Refunding]{}
}

@PART[*]:HAS[#hasRefundingOnRecovery]:LAST[999_KSP-Recall]
{
!hasRefundingOnRecovery = delete
}

@KSP-Recall:LAST[999_KSP-Recall]
{
hasRefundingOnRecovery = #$@KSP_COMMUNITY_FIXES/RefundingOnRecovery$
}

@KSP-Recall:HAS[#hasRefundingOnRecovery[?rue]]:LAST[999_KSP-Recall]
{
@INSTALLED
{
@Refunding = false
}
}

@KSP-Recall:HAS[#hasRefundingOnRecovery]:LAST[999_KSP-Recall]
{
!hasRefundingOnRecovery = delete
}
4 changes: 4 additions & 0 deletions GameData/KSPCommunityFixes/Settings.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ KSP_COMMUNITY_FIXES
// Fix spread angle still being applied after decoupling symmetry-placed parachutes.
ChutePhantomSymmetry = true

// Fix FlagDecalBackground module always using the same drag cube for all model sizes
// Implements a cache of autogenerated drag cubes and switch the part default drag cube
CorrectDragForFlags = true

// ##########################
// Obsolete bugfixes
// ##########################
Expand Down
269 changes: 269 additions & 0 deletions KSPCommunityFixes/BugFixes/CorrectDragForFlags.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
using HarmonyLib;
using System;
using System.Collections.Generic;
using Unity.Collections;
using UnityEngine;
using UnityEngine.Rendering;
using Object = UnityEngine.Object;
using Version = System.Version;

namespace KSPCommunityFixes.BugFixes
{
internal class CorrectDragForFlags : BasePatch
{
protected override Version VersionMin => new Version(1, 12, 3);

protected override void ApplyPatches(List<PatchInfo> patches)
{
patches.Add(new PatchInfo(
PatchMethodType.Postfix,
AccessTools.Method(typeof(FlagDecalBackground), nameof(FlagDecalBackground.EnableCurrentFlagMesh)),
this));
}

static void FlagDecalBackground_EnableCurrentFlagMesh_Postfix(FlagDecalBackground __instance)
{
if (__instance.flagMeshes == null)
return;

if (__instance.flagSizeOffset == 1000 && TryGetDragCube(__instance, out DragCube dragCube))
{
if (__instance.part.dragCubes.cubes.Count > 0)
__instance.part.dragCubes.cubes[0] = dragCube;
else
__instance.part.dragCubes.cubes.Add(dragCube);
}
}

static readonly Dictionary<Part, Dictionary<int, DragCube>> flagDecalBackgroundDragCubesPerPrefab = new Dictionary<Part, Dictionary<int, DragCube>>(5);

public static bool TryGetDragCube(FlagDecalBackground instance, out DragCube dragCube)
{
Part prefab = instance.part.partInfo?.partPrefab;
if (prefab.IsNullOrDestroyed())
{
dragCube = null;
return false;
}

if (!flagDecalBackgroundDragCubesPerPrefab.TryGetValue(prefab, out Dictionary<int, DragCube> dragCubes))
{
dragCubes = new Dictionary<int, DragCube>();
flagDecalBackgroundDragCubesPerPrefab[prefab] = dragCubes;
}

if (!dragCubes.TryGetValue(instance.flagSize, out dragCube))
{
dragCube = RenderDragCubeFast(instance.part);
dragCubes[instance.flagSize] = dragCube;
}

return true;
}

static Dictionary<Shader, bool> shaderHasAlphaDict = new Dictionary<Shader, bool>();

static bool MaterialShaderHasAlpha(Material material)
{
if (!shaderHasAlphaDict.TryGetValue(material.shader, out bool hasAlpha))
{
hasAlpha = material.shader.name.Contains("Alpha");
shaderHasAlphaDict[material.shader] = hasAlpha;
}

return hasAlpha;
}

private static readonly List<Component> staticComponentBuffer = new List<Component>(100);

static DragCube RenderDragCubeFast(Part part)
{
DragCubeSystem dragCubeSystem = DragCubeSystem.Instance;

DragCube dragCube = new DragCube();

Part dragPart = Object.Instantiate(part, Vector3.zero, Quaternion.identity);
GameObject dragObject = dragPart.gameObject;
dragPart.enabled = false;
dragPart.SetMirror(Vector3.one);
dragObject.SetActive(true);

for (int i = 0; i < dragPart.children.Count; i++)
if (dragPart.children[i].partTransform.parent == dragPart.partTransform)
Object.DestroyImmediate(dragPart.children[i].gameObject);

staticComponentBuffer.Clear();
dragObject.GetComponentsInChildren(true, staticComponentBuffer);

int cameraLayer = dragCubeSystem.cameraLayerInt;
Bounds partBounds = default;

int mainTexId = PropertyIDs._MainTex;
int bumpMapId = PropertyIDs._BumpMap;

for (int i = staticComponentBuffer.Count; i-- > 0;)
{
Component component = staticComponentBuffer[i];

if (component is MonoBehaviour monoBehaviour)
{
if (monoBehaviour is FXPrefab)
{
Object.DestroyImmediate(monoBehaviour);
continue;
}

monoBehaviour.enabled = false;
continue;
}

if (component is ParticleSystem)
{
Object.DestroyImmediate(component);
continue;
}

if (component is Collider collider)
{
collider.enabled = false;
continue;
}

if (component is Transform)
{
GameObject gameObject = component.gameObject;
if (((1 << gameObject.layer) & 2) == 0)
gameObject.layer = cameraLayer;
continue;
}

if (component is Renderer renderer)
{
GameObject rendererGameObject = renderer.gameObject;
if (renderer is ParticleSystemRenderer || !rendererGameObject.activeInHierarchy)
{
continue;
}

if (rendererGameObject.CompareTag("Drag_Hidden"))
{
Object.DestroyImmediate(renderer);
continue;
}

partBounds.Encapsulate(renderer.bounds);

renderer.shadowCastingMode = ShadowCastingMode.Off;
renderer.receiveShadows = false;
Material[] materials = renderer.materials;

for (int j = materials.Length; j-- > 0;)
{
Material material = materials[j];
Material dragMaterial;
if (material.HasProperty(PropertyIDs._BumpMap))
dragMaterial = new Material(dragCubeSystem.dragShaderBumped);
else
dragMaterial = new Material(dragCubeSystem.dragShader);

if (MaterialShaderHasAlpha(material) && material.HasProperty(mainTexId))
{
dragMaterial.SetTexture(mainTexId, material.GetTexture(mainTexId));
dragMaterial.SetTextureOffset(mainTexId, material.GetTextureOffset(mainTexId));
dragMaterial.SetTextureScale(mainTexId, material.GetTextureScale(mainTexId));
}
if (material.HasProperty(bumpMapId))
{
dragMaterial.SetTexture(bumpMapId, material.GetTexture(bumpMapId));
dragMaterial.SetTextureOffset(bumpMapId, material.GetTextureOffset(bumpMapId));
dragMaterial.SetTextureScale(bumpMapId, material.GetTextureScale(bumpMapId));
}
materials[j] = dragMaterial;
}
renderer.materials = materials;
}
}

staticComponentBuffer.Clear();

for (int i = 0; i < 6; i++)
{
dragCubeSystem.SetAeroCamera((DragCube.DragFace)i, partBounds);
dragCubeSystem.UpdateAeroTexture();
CalculateAerodynamicsFast(out float area, out float drag, out float depth);
dragCube.Area[i] = area;
dragCube.Drag[i] = drag;
dragCube.Depth[i] = depth;
}
dragCube.Center = partBounds.center;
dragCube.Size = partBounds.size;

dragObject.SetActive(value: false);
Object.Destroy(dragObject);

return dragCube;
}

private static float[] _dragTable;

private static float[] GetDragTable()
{
if (_dragTable == null)
{
_dragTable = new float[256];
AnimationCurve dragCurve = DragCubeSystem.Instance.dragCurve;
for (int i = 0; i < 256; i++)
_dragTable[i] = dragCurve.Evaluate(i / 255f);
}
return _dragTable;
}

private static void CalculateAerodynamicsFast(out float area, out float drag, out float depth)
{
DragCubeSystem dragCubeSystem = DragCubeSystem.Instance;
float[] dragTable = GetDragTable();

// ARGB32 texture
NativeArray<byte> pixels = dragCubeSystem.aeroTexture.GetRawTextureData<byte>();

Camera cam = dragCubeSystem.aeroCamera;
float lerpConstant = cam.nearClipPlane + (cam.farClipPlane - cam.nearClipPlane);

drag = 0f;
depth = 0f;
area = 0f;

int hits = 0;
int length = pixels.Length;
int i = 0;
while (i < length)
{
if (pixels[i] != 0)
{
hits++;

byte r = pixels[i + 1];
if (r > 0)
{
drag += dragTable[r];
}

byte g = pixels[i + 2];
if (g > 0)
{
float pixelDepth = lerpConstant * (g / 255f);
depth = Math.Max(depth, pixelDepth);
}
}
i += 4;
}

if (hits > 0)
{
float pixelArea = Mathf.Pow(2f * dragCubeSystem.aeroCameraSize / dragCubeSystem.resolution, 2f);
area = pixelArea * hits;
drag /= hits;
}
}
}
}
1 change: 1 addition & 0 deletions KSPCommunityFixes/KSPCommunityFixes.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
<Compile Include="BasePatch.cs" />
<Compile Include="BugFixes\AsteroidInfiniteMining.cs" />
<Compile Include="BugFixes\ChutePhantomSymmetry.cs" />
<Compile Include="BugFixes\CorrectDragForFlags.cs" />
<Compile Include="BugFixes\MapSOCorrectWrapping.cs" />
<Compile Include="BugFixes\UpgradeBugs.cs" />
<Compile Include="BugFixes\PartTooltipUpgradesApplyToSubstituteParts.cs" />
Expand Down
4 changes: 2 additions & 2 deletions KSPCommunityFixes/Properties/AssemblyInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
// Revision
//
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.24.6.0")]
[assembly: AssemblyFileVersion("1.25.0.0")]

[assembly: KSPAssembly("KSPCommunityFixes", 1, 24, 6)]
[assembly: KSPAssembly("KSPCommunityFixes", 1, 25, 0)]
[assembly: KSPAssemblyDependency("MultipleModulePartAPI", 1, 0, 0)]
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ User options are available from the "ESC" in-game settings menu :<br/><img src="
- **[UpgradeBugs](https://github.com/KSPModdingLibs/KSPCommunityFixes/pull/63)** [KSP 1.12.0 - 1.12.5]<br/>Fix various bugs with upgrades, like the part stats upgrade module breaking, upgrades not properly applying in the editor, upgrade cost not being applied to part cost, and various issues int the public API.
- **[MapSOCorrectWrapping](https://github.com/KSPModdingLibs/KSPCommunityFixes/pull/83)** [KSP 1.10.0 - 1.12.5]<br/>Fixes issues with biomes crossing the poles (South pole biome at north pole and vice versa). Fixes "polar spikes" in the terrain for 8-bit heightmaps.
- **[ChutePhantomSymmetry](https://github.com/KSPModdingLibs/KSPCommunityFixes/issues/107)** [KSP 1.10.0 - 1.12.5]<br/>Fix spread angle still being applied after decoupling symmetry-placed parachutes.
- **[CorrectDragForFlags](https://github.com/KSPModdingLibs/KSPCommunityFixes/issues/126)** [KSP 1.12.3 - 1.12.5]<br/>Fix the "panel" variants of the flag parts using a single drag cube, causing excessive drag for the smaller options.

#### Quality of Life tweaks

Expand Down Expand Up @@ -156,6 +157,10 @@ If doing so in the `Debug` configuration and if your KSP install is modified to

### Changelog

##### 1.25.0
- New KSP bugfix patch : [CorrectDragForFlags](https://github.com/KSPModdingLibs/KSPCommunityFixes/issues/126), fix the "panel" variants of the flag parts using a single drag cube, causing excessive drag for the smaller options.
- Fixed [issue #124](https://github.com/KSPModdingLibs/KSPCommunityFixes/issues/124) : avoid disabling the KSP-Recall "refunding" hack when the user has disabled the KSPCF "RefundingOnRecovery" patch, thus making our friend Lisias happy again.

##### 1.24.6
- Fixed [issue #121](https://github.com/KSPModdingLibs/KSPCommunityFixes/issues/121) : MapSOCorrectWrapping patch cause the Mohole to disappear

Expand Down

0 comments on commit 8debc12

Please sign in to comment.