Skip to content

Commit

Permalink
Merge branch 'fix-195-clone-srfattachnode' of https://github.com/KSPM…
Browse files Browse the repository at this point in the history
…oddingLibs/KSPCommunityFixes into fix-195-clone-srfattachnode
  • Loading branch information
gotmachine committed Feb 11, 2024
2 parents 7a4b4f3 + 8fe18ca commit 2f33a66
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 1 deletion.
5 changes: 4 additions & 1 deletion GameData/KSPCommunityFixes/Settings.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,10 @@ KSP_COMMUNITY_FIXES
// Disable the stock behavior of altering surface attachment nodes on re-rooting, which is
// unnecessary and doesn't work correctly, leading to permanently borked attachement nodes.
ReRootPreserveSurfaceAttach = true
// Replaces ReRootPreserveSurfaceAttach with some better (but more complex) logic.
// If this patch causes an issue, try turning it off and turning on ReRootPreserveSurfaceAttach
ReRootCloneSurfaceAttach = true
ReRootPreserveSurfaceAttach = false

// Fix leaking a camera and spotlight created by the thumbnail system on certain failures
ThumbnailSpotlight = true
Expand Down
106 changes: 106 additions & 0 deletions KSPCommunityFixes/BugFixes/ReRootCloneSurfaceAttach.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
using Expansions.Missions.Editor;
using HarmonyLib;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;

namespace KSPCommunityFixes.BugFixes
{
class ReRootCloneSurfaceAttach : BasePatch
{
// the name here isn't important, but if anyone is debugging an issue I'd like to make it clear where it came from.
// I'm pretty sure the empty string has some special meaning, and we need to be sure it doesn't collide with any existing node IDs
// we also use this to fix up attach nodes when loading a craft file.
const string CLONED_NODE_ID = "KSPCF-reroot-srfAttachNode";

protected override void ApplyPatches(List<PatchInfo> patches)
{
patches.Add(new PatchInfo(
PatchMethodType.Prefix,
AccessTools.Method(typeof(AttachNode), nameof(AttachNode.ReverseSrfNodeDirection)),
this));

patches.Add(new PatchInfo(
PatchMethodType.Prefix,
AccessTools.Method(typeof(AttachNode), nameof(AttachNode.ChangeSrfNodePosition)),
this));

patches.Add(new PatchInfo(
PatchMethodType.Postfix,
AccessTools.Method(typeof(Part), nameof(Part.FindAttachNode)),
this));

patches.Add(new PatchInfo(
PatchMethodType.Postfix,
AccessTools.Method(typeof(EditorLogicBase), nameof(EditorLogicBase.clearAttachNodes)),
this));
}

// In stock, this function is called after reversing a surface attachment during a re-root operation.
// it tries to alter a part's surface attachment so that it mirrors the surface attach node of its parent.
// But that's not a great idea, because a lot of things depend on the surface attach node never changing.
// For example, if the user then picks the part back up, it won't attach the same way to anything else
// To fix this, instead of using the child's actual srfAttachNode we create a new surface attach node and
// just stick it in the regular AttachNode list.
static bool AttachNode_ReverseSrfNodeDirection_Prefix(AttachNode __instance, AttachNode fromNode)
{
// Ideally we would be cloning fromNode in order to match the original attachment as closely as possible.
// however when loading a saved craft file, we won't know anything about that node, possibly leading
// to differing behavior. So we'll clone this part's attachnode instead.
AttachNode newSrfAttachNode = AttachNode.Clone(__instance);
newSrfAttachNode.attachedPart = fromNode.owner;
newSrfAttachNode.id = CLONED_NODE_ID;

// convert the position, orientation from the other part's local space into ours
Vector3 positionWorld = fromNode.owner.transform.TransformPoint(fromNode.position);
Vector3 orientationWorld = fromNode.owner.transform.TransformDirection(fromNode.orientation);
newSrfAttachNode.originalPosition = newSrfAttachNode.owner.transform.InverseTransformPoint(positionWorld);
newSrfAttachNode.originalOrientation = -newSrfAttachNode.owner.transform.InverseTransformDirection(orientationWorld);
newSrfAttachNode.position = newSrfAttachNode.originalPosition;
newSrfAttachNode.orientation = newSrfAttachNode.originalOrientation;
newSrfAttachNode.owner.attachNodes.Add(newSrfAttachNode);

// now clear the srfAttachNodes from both parts
__instance.attachedPart = null;
fromNode.attachedPart = null;

return false;
}

// this function is just horribly broken and no one could call it, ever
static bool AttachNode_ChangeSrfNodePosition_Prefix()
{
return false;
}

static void Part_FindAttachNode_Postfix(Part __instance, string nodeId, ref AttachNode __result)
{
// TODO: ideally we would only do this if we know we're in the process of loading a craft file. Is there any way to check that?
if (__result == null && nodeId == CLONED_NODE_ID)
{
AttachNode newSrfAttachNode = AttachNode.Clone(__instance.srfAttachNode);
newSrfAttachNode.id = CLONED_NODE_ID;
__instance.attachNodes.Add(newSrfAttachNode);
__result = newSrfAttachNode;
}
}

// In the editor, when detaching parts, remove the extra attachnode we added
static void EditorLogicBase_clearAttachNodes_Postfix(Part part)
{
for (int i = 0; i < part.attachNodes.Count; i++)
{
AttachNode attachNode = part.attachNodes[i];

if (attachNode.id == CLONED_NODE_ID && attachNode.attachedPart.IsNullRef())
{
part.attachNodes.RemoveAt(i);
return;
}
}
}
}
}
1 change: 1 addition & 0 deletions KSPCommunityFixes/KSPCommunityFixes.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
<Compile Include="BugFixes\MapSOCorrectWrapping.cs" />
<Compile Include="BugFixes\FixGetUnivseralTime.cs" />
<Compile Include="BugFixes\ModuleAnimateGenericCrewModSpawnIVA.cs" />
<Compile Include="BugFixes\ReRootCloneSurfaceAttach.cs" />
<Compile Include="BugFixes\ReRootPreserveSurfaceAttach.cs" />
<Compile Include="BugFixes\RespawnDeadKerbals.cs" />
<Compile Include="BugFixes\ThumbnailSpotlight.cs" />
Expand Down

0 comments on commit 2f33a66

Please sign in to comment.