Skip to content

Commit 68efdce

Browse files
committed
Add fix for Yellow-Dog-Man/Resonite-Issues#92 - duplicating / cloning components messing with drives
1 parent d109ec3 commit 68efdce

File tree

1 file changed

+97
-0
lines changed

1 file changed

+97
-0
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
using Elements.Core;
2+
using FrooxEngine;
3+
using HarmonyLib;
4+
using MonkeyLoader.Resonite;
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Text;
8+
9+
using static FrooxEngine.Worker;
10+
11+
namespace CommunityBugFixCollection
12+
{
13+
[HarmonyPatchCategory(nameof(BreakDuplicatedComponentDrives))]
14+
[HarmonyPatch(typeof(Slot), nameof(Slot.DuplicateComponents), [typeof(List<Component>), typeof(bool), typeof(List<Component>)])]
15+
internal sealed class BreakDuplicatedComponentDrives : ResoniteMonkey<BreakDuplicatedComponentDrives>
16+
{
17+
public override IEnumerable<string> Authors => Contributors.Banane9;
18+
19+
public override bool CanBeDisabled => true;
20+
21+
private static void CollectInternalReferences(List<Component> sourceComponents, InternalReferences internalRefs, HashSet<ISyncRef> externalRefs, HashSet<ISyncRef> breakRefs)
22+
{
23+
foreach (var component in sourceComponents)
24+
{
25+
var refList = Pool.BorrowList<ISyncRef>();
26+
component.GetSyncMembers(refList, true);
27+
28+
foreach (var syncRef in refList)
29+
{
30+
if (syncRef.Target is null)
31+
{
32+
if (syncRef.Value != RefID.Null)
33+
breakRefs.Add(syncRef);
34+
35+
continue;
36+
}
37+
38+
var targetParent = syncRef.Target?.FindNearestParent<Component>();
39+
40+
// Parent can't be a component being duplicated currently
41+
if (targetParent is null)
42+
externalRefs.Add(syncRef);
43+
44+
// A HashSet for the Contains would seem faster, but in 99.9% of cases this is only one component
45+
if (sourceComponents.Contains(targetParent!))
46+
{
47+
internalRefs.AddPair(syncRef, syncRef.Target!);
48+
continue;
49+
}
50+
51+
externalRefs.Add(syncRef);
52+
53+
if (syncRef is ILinkRef)
54+
breakRefs.Add(syncRef);
55+
}
56+
57+
Pool.Return(ref refList);
58+
}
59+
}
60+
61+
private static bool Prefix(Slot __instance, List<Component> sourceComponents, bool breakExternalReferences, List<Component> duplicates)
62+
{
63+
if (!Enabled)
64+
return true;
65+
66+
using var internalRefs = new InternalReferences();
67+
var breakRefs = Pool.BorrowHashSet<ISyncRef>();
68+
var externalRefs = Pool.BorrowHashSet<ISyncRef>();
69+
70+
CollectInternalReferences(sourceComponents, internalRefs, externalRefs, breakRefs);
71+
72+
if (!breakExternalReferences)
73+
externalRefs.Clear();
74+
75+
breakRefs.UnionWith(externalRefs);
76+
77+
foreach (var sourceComponent in sourceComponents)
78+
{
79+
var duplicatedComponent = __instance.AttachComponent(sourceComponent.GetType(), runOnAttachBehavior: false);
80+
81+
internalRefs.RegisterCopy(sourceComponent, duplicatedComponent);
82+
duplicatedComponent.CopyValues(sourceComponent, (from, to) => MemberCopy(from, to, internalRefs, breakRefs, checkTypes: false));
83+
duplicates.Add(duplicatedComponent);
84+
}
85+
86+
internalRefs.TransferReferences(true);
87+
88+
foreach (var duplicate in duplicates)
89+
duplicate.RunDuplicate();
90+
91+
Pool.Return(ref breakRefs);
92+
Pool.Return(ref externalRefs);
93+
94+
return false;
95+
}
96+
}
97+
}

0 commit comments

Comments
 (0)