1- using Elements . Core ;
1+ using Elements . Assets ;
22using FrooxEngine ;
33using HarmonyLib ;
44using MonkeyLoader . Patching ;
@@ -20,6 +20,7 @@ internal sealed class LagFreeContactsLoading : ResoniteMonkey<LagFreeContactsLoa
2020 {
2121 private const int ContactsPerUpdate = 8 ;
2222
23+ public override bool CanBeDisabled => true ;
2324 internal static bool AllowSorting { get ; private set ; } = true ;
2425
2526 protected override IEnumerable < IFeaturePatch > GetFeaturePatches ( ) => Enumerable . Empty < IFeaturePatch > ( ) ;
@@ -43,22 +44,39 @@ private static void AddContactItems(ContactsDialog contactsDialog)
4344 var segments = contactsSortInfo . Length / ContactsPerUpdate ;
4445 for ( var segment = 0 ; segment < segments ; ++ segment )
4546 {
46- for ( var i = 0 ; i <= ContactsPerUpdate ; ++ i )
47- contactsDialog . UpdateContactItem ( contactsSortInfo [ ContactsPerUpdate * segment + i ] . contactData ) ;
47+ for ( var i = 0 ; i < ContactsPerUpdate ; ++ i )
48+ contactsDialog . UpdateContactItem ( contactsSortInfo [ ( ContactsPerUpdate * segment ) + i ] . contactData ) ;
4849
4950 await default ( NextUpdate ) ;
5051 }
5152
5253 for ( var i = segments * ContactsPerUpdate ; i < contactsSortInfo . Length ; ++ i )
5354 contactsDialog . UpdateContactItem ( contactsSortInfo [ i ] . contactData ) ;
5455
56+ await default ( NextUpdate ) ;
57+
5558 AllowSorting = true ;
5659 } ) ;
5760
61+ private static void AddSearchResult ( ContactsDialog contactsDialog , SkyFrost . Base . User user )
62+ {
63+ if ( contactsDialog . _contactItems . ContainsKey ( user . Id )
64+ || contactsDialog . _searchResultItems . Any ( item => item . Contact . ContactUserId == user . Id )
65+ || user . Id == contactsDialog . Cloud . CurrentUserID )
66+ return ;
67+
68+ var contactItem = contactsDialog . AddContactItem ( ) ;
69+ contactItem . Update ( user ) ;
70+ contactsDialog . _searchResultItems . Add ( contactItem ) ;
71+ }
72+
5873 [ HarmonyTranspiler ]
59- [ HarmonyPatch ( " OnAttach" ) ]
74+ [ HarmonyPatch ( nameof ( ContactsDialog . OnAttach ) ) ]
6075 private static IEnumerable < CodeInstruction > OnAttachTranspiler ( IEnumerable < CodeInstruction > instructionsEnumerable )
6176 {
77+ if ( ! Enabled )
78+ return instructionsEnumerable ;
79+
6280 var foreachContactDataMethod = AccessTools . Method ( typeof ( ContactManager ) , nameof ( ContactManager . ForeachContactData ) ) ;
6381 var addContactItemsMethod = AccessTools . Method ( typeof ( LagFreeContactsLoading ) , nameof ( AddContactItems ) ) ;
6482
@@ -71,5 +89,95 @@ private static IEnumerable<CodeInstruction> OnAttachTranspiler(IEnumerable<CodeI
7189
7290 return instructions ;
7391 }
92+
93+ private static bool RemoveItem ( ContactItem contact , string ? searchTerm , bool clear )
94+ {
95+ if ( clear || ! ( contact . Username . StartsWith ( searchTerm )
96+ || contact . AlternateNames . Any ( name => name . StartsWith ( searchTerm , StringComparison . InvariantCulture ) ) ) )
97+ {
98+ contact . Slot . Destroy ( ) ;
99+ return true ;
100+ }
101+
102+ return false ;
103+ }
104+
105+ [ HarmonyPrefix ]
106+ [ HarmonyPatch ( nameof ( ContactsDialog . SearchTextChanged ) ) ]
107+ private static bool SearchTextChangedPrefix ( ContactsDialog __instance , TextEditor editor )
108+ {
109+ if ( ! Enabled )
110+ return true ;
111+
112+ __instance . StartTask ( async ( ) =>
113+ {
114+ var searchTerm = editor . TargetString ? . Trim ( ) . ToLower ( ) ;
115+ var clear = string . IsNullOrWhiteSpace ( searchTerm ) ;
116+
117+ var segments = __instance . _searchResultItems . Count / ContactsPerUpdate ;
118+
119+ for ( var i = __instance . _searchResultItems . Count - 1 ; i >= segments * ContactsPerUpdate ; -- i )
120+ {
121+ if ( RemoveItem ( __instance . _searchResultItems [ i ] , searchTerm , clear ) )
122+ __instance . _searchResultItems . RemoveAt ( i ) ;
123+ }
124+
125+ for ( var segment = segments - 1 ; segment >= 0 ; -- segment )
126+ {
127+ await default ( NextUpdate ) ;
128+
129+ for ( var i = ContactsPerUpdate - 1 ; i >= 0 ; -- i )
130+ {
131+ var x = ( ContactsPerUpdate * segment ) + i ;
132+
133+ if ( RemoveItem ( __instance . _searchResultItems [ x ] , searchTerm , clear ) )
134+ __instance . _searchResultItems . RemoveAt ( x ) ;
135+ }
136+ }
137+
138+ await default ( NextUpdate ) ;
139+
140+ foreach ( var contactItem in __instance . _contactItems )
141+ {
142+ contactItem . Value . Slot . ActiveSelf = clear
143+ || contactItem . Value . Username . StartsWith ( searchTerm , StringComparison . InvariantCultureIgnoreCase )
144+ || contactItem . Value . AlternateNames . Any ( name => name . StartsWith ( searchTerm , StringComparison . InvariantCulture ) ) ;
145+ }
146+ } ) ;
147+
148+ __instance . globalSearchTimer = 0.5 ;
149+
150+ return false ;
151+ }
152+
153+ [ HarmonyPrefix ]
154+ [ HarmonyPatch ( nameof ( ContactsDialog . SetSearchResults ) ) ]
155+ private static bool SetSearchResultsPrefix ( ContactsDialog __instance , List < SkyFrost . Base . User > users )
156+ {
157+ if ( ! Enabled )
158+ return true ;
159+
160+ __instance . StartTask ( async ( ) =>
161+ {
162+ var segments = users . Count / ContactsPerUpdate ;
163+
164+ for ( var segment = 0 ; segment < segments ; ++ segment )
165+ {
166+ for ( var i = 0 ; i < ContactsPerUpdate ; ++ i )
167+ AddSearchResult ( __instance , users [ ( ContactsPerUpdate * segment ) + i ] ) ;
168+
169+ await default ( NextUpdate ) ;
170+ }
171+
172+ for ( var i = segments * ContactsPerUpdate ; i < users . Count ; ++ i )
173+ AddSearchResult ( __instance , users [ i ] ) ;
174+
175+ await default ( NextUpdate ) ;
176+
177+ __instance . sortList = true ;
178+ } ) ;
179+
180+ return false ;
181+ }
74182 }
75183}
0 commit comments