/// <summary> /// Find the closest template in the base cache to the input template. /// </summary> private CachedTag FindClosestTemplate(CachedTag sourceRmt2Tag, RenderMethodTemplate sourceRmt2) { Debug.Assert(IsInitialized); Rmt2Descriptor sourceRmt2Desc; if (!Rmt2Descriptor.TryParse(sourceRmt2Tag.Name, out sourceRmt2Desc)) { throw new ArgumentException($"Invalid rmt2 name '{sourceRmt2Tag.Name}'", nameof(sourceRmt2Tag)); } var relevantRmt2s = new List <Rmt2Pairing>(); foreach (var rmt2Tag in BaseCache.TagCache.NonNull().Where(tag => tag.IsInGroup("rmt2"))) { Rmt2Descriptor destRmt2Desc; if (!Rmt2Descriptor.TryParse(rmt2Tag.Name, out destRmt2Desc)) { continue; } // ignore ms30 templates if desired if (!UseMs30 && destRmt2Desc.IsMs30) { continue; } // ignore templates that are not of the same type if (destRmt2Desc.Type != sourceRmt2Desc.Type) { continue; } // match the options from the rmt2 tag names int commonOptions = 0; for (int i = 0; i < sourceRmt2Desc.Options.Length; i++) { if (sourceRmt2Desc.Options[i] == destRmt2Desc.Options[i]) { commonOptions++; } } // if we found an exact match, return it if (commonOptions == sourceRmt2Desc.Options.Length) { return(rmt2Tag); } // add it to the list to be considered relevantRmt2s.Add(new Rmt2Pairing() { CommonOptions = commonOptions, DestTag = rmt2Tag, SourceTag = sourceRmt2Tag }); } // if we've reached here, we haven't found an extract match. // now we need to consider other factors such as which options they have, which parameters are missing etc.. // whatever can be used to narrow it down. foreach (var pairing in relevantRmt2s) { var rmt2 = GetTemplate(pairing.DestTag); pairing.RealParams = MatchParameterBlocks(sourceRmt2.RealParameterNames, rmt2.RealParameterNames); pairing.IntParams = MatchParameterBlocks(sourceRmt2.IntegerParameterNames, rmt2.IntegerParameterNames); pairing.BoolParams = MatchParameterBlocks(sourceRmt2.BooleanParameterNames, rmt2.BooleanParameterNames); pairing.TextureParams = MatchParameterBlocks(sourceRmt2.TextureParameterNames, rmt2.TextureParameterNames); } // finally order by some criteria var ordered = relevantRmt2s .OrderBy(x => x.CommonOptions); //.ThenByDescending(x => x.MissingFromDest); // return the best rmt2 or the default if one could not be found (only when a template type is not in the base cache) var bestRmt2 = ordered.LastOrDefault()?.DestTag; if (bestRmt2 == null) { return(BaseCache.GetTag(DefaultTemplate)); } return(bestRmt2); }