예제 #1
0
        public static Dictionary <CustomSet <ModKey>, RecordsClassifiedByMasters <TMod, TModGetter> > ClassifyRecordsByReferencedMasters <TMod, TModGetter>(
            TModGetter patchMod,
            CustomSetFactory <ModKey> setFactory,
            int maximumMastersPerMod = MAXIMUM_MASTERS_PER_MOD)
            where TMod : class, IMod, TModGetter
            where TModGetter : class, IModGetter, IMajorRecordContextEnumerable <TMod, TModGetter>
        {
            var recordSets       = new Dictionary <CustomSet <ModKey>, RecordsClassifiedByMasters <TMod, TModGetter> >();
            var masterSetBuilder = setFactory.NewSet();

            var patchModKey = patchMod.ModKey;

            var linkCache = patchMod.ToUntypedImmutableLinkCache();

            foreach (IModContext <TMod, TModGetter, IMajorRecordCommon, IMajorRecordCommonGetter>?context in patchMod.EnumerateMajorRecordContexts <IMajorRecordCommon, IMajorRecordCommonGetter>(linkCache, false))
            {
                masterSetBuilder.Clear();

                bool isNewRecord = false;

                IModContext?thisContext = context;
                while (thisContext is not null)
                {
                    var record = context.Record;
                    var modKey = record.FormKey.ModKey;
                    masterSetBuilder.Add(modKey);

                    if (modKey == patchModKey)
                    {
                        isNewRecord = true;
                    }

                    // TODO Does this include all child records?
                    foreach (var link in record.ContainedFormLinks)
                    {
                        masterSetBuilder.Add(link.FormKey.ModKey);
                    }

                    thisContext = thisContext.Parent;

                    int recordMasterCount = masterSetBuilder.Count;
                    if (recordMasterCount > maximumMastersPerMod)
                    {
                        throw RecordException.Factory(new Exception($"Too many masters ({recordMasterCount}) referenced by one record"), record);
                    }
                }

                CustomSet <ModKey> masterSet = masterSetBuilder.ToCustomSet();
                var recordSet = recordSets.Autovivify(masterSet, () => new(masterSet));

                recordSet.contextSet.Add(context);

                if (isNewRecord)
                {
                    recordSet.hasNewRecords = true;
                }
            }

            return(recordSets);
        }
예제 #2
0
 internal CustomSet(CustomSet <T> .Builder mutable)
 {
     this.factory = mutable.factory;
     this.set     = mutable.set.ToArray();
     Array.Sort(this.set);
     this.hashCode = mutable.hashCode;
 }
예제 #3
0
        private static void RunPatch <TMod, TModGetter>(IPatcherState <TMod, TModGetter> state)
            where TMod : class, IContextMod <TMod, TModGetter>, TModGetter
            where TModGetter : class, IContextGetterMod <TMod, TModGetter>
        {
            var setFactory = new CustomSetFactory <ModKey>();

            var patchMasterCount = state.PatchMod.MasterReferences.Count;

            if (patchMasterCount <= 1)
            {
                return;
            }

            // this would usually be 255, but we can't load a mod with 255 masters (yet).
            var MAXIMUM_MASTERS_PER_MOD = patchMasterCount / 2;

            Console.WriteLine($"found {patchMasterCount} master references, attempting to produce a set of mod that each have less than {MAXIMUM_MASTERS_PER_MOD} masters.");

            /// each entry is potentially an emitted mod.
            var recordSets = ClassifyRecordsByReferencedMasters <TMod, TModGetter>(state.PatchMod, setFactory, MAXIMUM_MASTERS_PER_MOD);

            // each entry in here is an emitted mod.
            var patches = PatchesFromRecordSets(recordSets, setFactory, MAXIMUM_MASTERS_PER_MOD);
예제 #4
0
        public static List <HashSet <IModContext <TMod, TModGetter, IMajorRecordCommon, IMajorRecordCommonGetter> > > PatchesFromRecordSets <TMod, TModGetter>(Dictionary <CustomSet <ModKey>, RecordsClassifiedByMasters <TMod, TModGetter> > recordSets, CustomSetFactory <ModKey> setFactory, int maximumMastersPerMod = MAXIMUM_MASTERS_PER_MOD)
            where TMod : class, IMod, TModGetter
            where TModGetter : class, IModGetter, IMajorRecordContextEnumerable <TMod, TModGetter>
        {
            var patches = new List <HashSet <IModContext <TMod, TModGetter, IMajorRecordCommon, IMajorRecordCommonGetter> > >();

            bool newRecordsFirst = true;

            var temp         = setFactory.NewSet();
            var smallestSets = new Dictionary <CustomSet <ModKey>, NewStruct2>();

            while (recordSets.Count > 0)
            {
                temp.Clear();
                int largestMasterSetCount           = 0;
                CustomSet <ModKey> largestMasterSet = null !;

                foreach (var(masterSet, data) in recordSets)
                {
                    if (newRecordsFirst)
                    {
                        if (!data.hasNewRecords)
                        {
                            continue;
                        }
                    }
                    else
                    {
                        temp.UnionWith(masterSet);
                    }

                    if (largestMasterSet is null || data.MasterCount > largestMasterSetCount)
                    {
                        largestMasterSetCount = data.MasterCount;
                        largestMasterSet      = masterSet;
                    }
                }

                if (largestMasterSet is null)
                {
                    newRecordsFirst = false;
                    continue;
                }

                if (!newRecordsFirst)
                {
                    if (temp.Count <= maximumMastersPerMod)
                    {
                        var patchContents = new HashSet <IModContext <TMod, TModGetter, IMajorRecordCommon, IMajorRecordCommonGetter> >();
                        foreach (var(masterSet, data) in recordSets)
                        {
                            patchContents.UnionWith(data.contextSet);
                        }
                        recordSets.Clear();
                        patches.Add(patchContents);
                        continue;
                    }
                }

                var largestMasterRecordSet = recordSets[largestMasterSet];
                recordSets.Remove(largestMasterSet);

                while (recordSets.Count > 0)
                {
                    int smallestAdditionalMasterSetCount = 0;
                    CustomSet <ModKey> smallestMasterSet = null !;
                    smallestSets.Clear();
                    foreach (var(masterSet, data) in recordSets)
                    {
                        if (newRecordsFirst)
                        {
                            if (!data.hasNewRecords)
                            {
                                continue;
                            }
                        }

                        // the set of distinct masterRecords that would be added to our current target if we added this recordSet to the mix.

                        var temp2 = masterSet.Except(largestMasterSet);

                        int additionalMasterCount = temp2.Count;

                        if (additionalMasterCount == smallestAdditionalMasterSetCount)
                        {
                            var foo = smallestSets.Autovivify(temp2, () => new(0, new()));
                            foo.recordCount += data.contextSet.Count;
                            foo.masterSets.Add(masterSet);
                        }

                        if (smallestMasterSet is null || additionalMasterCount < smallestAdditionalMasterSetCount)
                        {
                            smallestSets.Clear();
                            smallestSets[temp.ToCustomSet()] = new(data.contextSet.Count, new() { masterSet });
                            smallestAdditionalMasterSetCount = additionalMasterCount;
                            smallestMasterSet = masterSet;
                        }
                    }

                    if (smallestMasterSet is null)
                    {
                        newRecordsFirst = false;
                        continue;
                    }

                    if (smallestAdditionalMasterSetCount == 0)
                    {
                        foreach (var(_, (_, masterSets)) in smallestSets)
                        {
                            foreach (var masterSet in masterSets)
                            {
                                var recordSet = recordSets[masterSet];
                                recordSets.Remove(masterSet);

                                largestMasterRecordSet.contextSet.UnionWith(recordSet.contextSet);
                            }
                        }
                    }
                    else
                    {
                        int newMasterCount = largestMasterSetCount + smallestAdditionalMasterSetCount;

                        if (newMasterCount > maximumMastersPerMod)
                        {
                            break;
                        }

                        largestMasterSetCount = newMasterCount;

                        int maxCount = 0;
                        HashSet <CustomSet <ModKey> > victim = null !;

                        foreach (var(id, (count, masterSets)) in smallestSets)
                        {
                            if (victim is null || count > maxCount)
                            {
                                maxCount = count;
                                victim   = masterSets;
                            }
                        }

                        foreach (var masterSet in victim)
                        {
                            var recordSet = recordSets[masterSet];
                            recordSets.Remove(masterSet);

                            largestMasterRecordSet.contextSet.UnionWith(recordSet.contextSet);
                        }
                    }
                }
                newRecordsFirst = false;
                patches.Add(largestMasterRecordSet.contextSet);
            }


            return(patches);
        }
 internal Enumerator(CustomSetFactory <T> factory, ISet <ushort> set)
 {
     this.factory    = factory;
     this.enumerator = set.GetEnumerator();
 }
예제 #6
0
            internal Builder(CustomSetFactory <T> factory)
            {
                this.factory = factory;

                set = ImmutableHashSet.CreateBuilder <ushort>();
            }
예제 #7
0
 internal CustomSet(CustomSetFactory <T> factory, ISet <ushort> set)
 {
     this.factory = factory;
     this.set     = set.ToArray();
     Array.Sort(this.set);
 }
예제 #8
0
 internal Enumerator(CustomSetFactory <T> factory, ushort[] array)
 {
     this.factory    = factory;
     this.enumerator = ((IEnumerable <ushort>)array).GetEnumerator();
 }