@@ -100,12 +100,10 @@ public Permission()
100100 /// </summary>
101101 private void LoadFromDatafile ( )
102102 {
103- Utility . DatafileToProto < Dictionary < string , UserData > > ( "oxide.users" ) ;
104- Utility . DatafileToProto < Dictionary < string , GroupData > > ( "oxide.groups" ) ;
105-
106- usersData = new Dictionary < string , UserData > ( ProtoStorage . Load < Dictionary < string , UserData > > ( "oxide.users" ) , StringComparer . OrdinalIgnoreCase ) ;
107- groupsData = new Dictionary < string , GroupData > ( ProtoStorage . Load < Dictionary < string , GroupData > > ( "oxide.groups" ) , StringComparer . OrdinalIgnoreCase ) ;
103+ VerifyAndLoadUsersData ( ) ;
104+ VerifyAndLoadGroupsData ( ) ;
108105
106+ bool circularReference = false ;
109107 foreach ( KeyValuePair < string , GroupData > pair in groupsData )
110108 {
111109 if ( string . IsNullOrEmpty ( pair . Value . ParentGroup ) || ! HasCircularParent ( pair . Key , pair . Value . ParentGroup ) )
@@ -115,11 +113,149 @@ private void LoadFromDatafile()
115113
116114 Interface . Oxide . LogWarning ( "Detected circular parent group for '{0}'; removing parent '{1}'" , pair . Key , pair . Value . ParentGroup ) ;
117115 pair . Value . ParentGroup = null ;
116+ circularReference = true ;
117+ }
118+
119+ if ( circularReference )
120+ {
121+ SaveGroups ( ) ;
118122 }
119123
120124 IsLoaded = true ;
121125 }
122126
127+ private void VerifyAndLoadUsersData ( )
128+ {
129+ Utility . DatafileToProto < Dictionary < string , UserData > > ( "oxide.users" ) ;
130+
131+ Dictionary < string , UserData > storedUserData = ProtoStorage . Load < Dictionary < string , UserData > > ( "oxide.users" ) ;
132+ Dictionary < string , UserData > result = new Dictionary < string , UserData > ( StringComparer . OrdinalIgnoreCase ) ;
133+ HashSet < string > groups = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
134+ HashSet < string > permissions = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
135+
136+ bool changed = false ;
137+
138+ foreach ( KeyValuePair < string , UserData > entry in storedUserData )
139+ {
140+ UserData user = entry . Value ;
141+
142+ permissions . Clear ( ) ;
143+ groups . Clear ( ) ;
144+
145+ foreach ( string perm in user . Perms )
146+ {
147+ permissions . Add ( perm ) ;
148+ }
149+
150+ user . Perms = new HashSet < string > ( permissions , StringComparer . OrdinalIgnoreCase ) ;
151+
152+ foreach ( string group in user . Groups )
153+ {
154+ groups . Add ( group ) ;
155+ }
156+
157+ user . Groups = new HashSet < string > ( groups , StringComparer . OrdinalIgnoreCase ) ;
158+
159+ if ( result . ContainsKey ( entry . Key ) )
160+ {
161+ UserData existing = result [ entry . Key ] ;
162+ existing . Perms . UnionWith ( user . Perms ) ;
163+ existing . Groups . UnionWith ( user . Groups ) ;
164+
165+ changed = true ;
166+
167+ continue ;
168+ }
169+
170+ result . Add ( entry . Key , user ) ;
171+ }
172+
173+ usersData = result ;
174+ if ( changed )
175+ {
176+ SaveUsers ( ) ;
177+ }
178+ }
179+
180+ private void VerifyAndLoadGroupsData ( )
181+ {
182+ Utility . DatafileToProto < Dictionary < string , GroupData > > ( "oxide.groups" ) ;
183+
184+ Dictionary < string , GroupData > storedGroupData = ProtoStorage . Load < Dictionary < string , GroupData > > ( "oxide.groups" ) ;
185+ Dictionary < string , GroupData > result = new Dictionary < string , GroupData > ( StringComparer . OrdinalIgnoreCase ) ;
186+ HashSet < string > permissions = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
187+
188+ bool changed = false ;
189+
190+ foreach ( KeyValuePair < string , GroupData > entry in storedGroupData )
191+ {
192+ GroupData group = entry . Value ;
193+
194+ permissions . Clear ( ) ;
195+
196+ foreach ( string perm in group . Perms )
197+ {
198+ permissions . Add ( perm ) ;
199+ }
200+
201+ group . Perms = new HashSet < string > ( permissions , StringComparer . OrdinalIgnoreCase ) ;
202+
203+ if ( result . ContainsKey ( entry . Key ) )
204+ {
205+ GroupData existing = result [ entry . Key ] ;
206+ existing . Perms . UnionWith ( group . Perms ) ;
207+ changed = true ;
208+
209+ continue ;
210+ }
211+
212+ result . Add ( entry . Key , group ) ;
213+ }
214+
215+ groupsData = result ;
216+ if ( changed )
217+ {
218+ SaveGroups ( ) ;
219+ }
220+ }
221+
222+ private Dictionary < string , GroupData > VerifyGroupData ( Dictionary < string , GroupData > data )
223+ {
224+ Dictionary < string , GroupData > result = new Dictionary < string , GroupData > ( StringComparer . OrdinalIgnoreCase ) ;
225+ HashSet < string > permissions = new HashSet < string > ( StringComparer . OrdinalIgnoreCase ) ;
226+
227+ foreach ( KeyValuePair < string , GroupData > entry in data )
228+ {
229+ GroupData group = entry . Value ;
230+
231+ permissions . Clear ( ) ;
232+
233+ foreach ( string perm in group . Perms )
234+ {
235+ permissions . Add ( perm ) ;
236+ }
237+
238+ group . Perms = new HashSet < string > ( permissions , StringComparer . OrdinalIgnoreCase ) ;
239+
240+ if ( result . ContainsKey ( entry . Key ) )
241+ {
242+ GroupData existing = result [ entry . Key ] ;
243+ // Get a matching entry.key from result.keys
244+ var existingKey = result . Keys . FirstOrDefault ( x => x . Equals ( entry . Key , StringComparison . OrdinalIgnoreCase ) ) ;
245+
246+ existing . Perms . UnionWith ( group . Perms ) ;
247+
248+ Interface . Oxide . LogWarning ( "Duplicate group '{0}' found, merged entries with {1}" , entry . Key , existingKey ) ;
249+
250+ continue ;
251+ }
252+
253+ result . Add ( entry . Key , group ) ;
254+ }
255+
256+ return result ;
257+ }
258+
123259 /// <summary>
124260 /// Exports user/group data to json
125261 /// </summary>
0 commit comments