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