diff --git a/GameData/KSPCommunityFixes/Extras/KSPCF_UserSettings.cfg.extra b/GameData/KSPCommunityFixes/Extras/KSPCF_UserSettings.cfg.extra index 5b282c2..d925bb1 100644 --- a/GameData/KSPCommunityFixes/Extras/KSPCF_UserSettings.cfg.extra +++ b/GameData/KSPCommunityFixes/Extras/KSPCF_UserSettings.cfg.extra @@ -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 } \ No newline at end of file diff --git a/GameData/KSPCommunityFixes/KSPCommunityFixes.version b/GameData/KSPCommunityFixes/KSPCommunityFixes.version index bae7e7a..bb2d8d8 100644 --- a/GameData/KSPCommunityFixes/KSPCommunityFixes.version +++ b/GameData/KSPCommunityFixes/KSPCommunityFixes.version @@ -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} diff --git a/GameData/KSPCommunityFixes/MMPatches/ModSupport/KSPRecall.cfg b/GameData/KSPCommunityFixes/MMPatches/ModSupport/KSPRecall.cfg index 26a2b03..c62ac2b 100644 --- a/GameData/KSPCommunityFixes/MMPatches/ModSupport/KSPRecall.cfg +++ b/GameData/KSPCommunityFixes/MMPatches/ModSupport/KSPRecall.cfg @@ -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 } \ No newline at end of file diff --git a/GameData/KSPCommunityFixes/Settings.cfg b/GameData/KSPCommunityFixes/Settings.cfg index 36da191..05393fd 100644 --- a/GameData/KSPCommunityFixes/Settings.cfg +++ b/GameData/KSPCommunityFixes/Settings.cfg @@ -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 // ########################## diff --git a/KSPCommunityFixes/BugFixes/CorrectDragForFlags.cs b/KSPCommunityFixes/BugFixes/CorrectDragForFlags.cs new file mode 100644 index 0000000..6db4570 --- /dev/null +++ b/KSPCommunityFixes/BugFixes/CorrectDragForFlags.cs @@ -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 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> flagDecalBackgroundDragCubesPerPrefab = new Dictionary>(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 dragCubes)) + { + dragCubes = new Dictionary(); + flagDecalBackgroundDragCubesPerPrefab[prefab] = dragCubes; + } + + if (!dragCubes.TryGetValue(instance.flagSize, out dragCube)) + { + dragCube = RenderDragCubeFast(instance.part); + dragCubes[instance.flagSize] = dragCube; + } + + return true; + } + + static Dictionary shaderHasAlphaDict = new Dictionary(); + + 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 staticComponentBuffer = new List(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 pixels = dragCubeSystem.aeroTexture.GetRawTextureData(); + + 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; + } + } + } +} diff --git a/KSPCommunityFixes/KSPCommunityFixes.csproj b/KSPCommunityFixes/KSPCommunityFixes.csproj index d95b0c5..6cece19 100644 --- a/KSPCommunityFixes/KSPCommunityFixes.csproj +++ b/KSPCommunityFixes/KSPCommunityFixes.csproj @@ -99,6 +99,7 @@ + diff --git a/KSPCommunityFixes/Properties/AssemblyInfo.cs b/KSPCommunityFixes/Properties/AssemblyInfo.cs index 63f4aea..5c1626d 100644 --- a/KSPCommunityFixes/Properties/AssemblyInfo.cs +++ b/KSPCommunityFixes/Properties/AssemblyInfo.cs @@ -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)] diff --git a/README.md b/README.md index c1440a3..c8e4cde 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,7 @@ User options are available from the "ESC" in-game settings menu :
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]
Fix the "panel" variants of the flag parts using a single drag cube, causing excessive drag for the smaller options. #### Quality of Life tweaks @@ -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