A game about forced loneliness, made by TACStudios
at master 175 lines 7.8 kB view raw
1using System; 2using System.Collections.Generic; 3using System.Reflection; 4using Unity.Multiplayer.Center.Common; 5using Unity.Multiplayer.Center.Questionnaire; 6using Unity.Multiplayer.Center.Recommendations; 7using Unity.Multiplayer.Center.Window.UI; 8using UnityEngine; 9 10namespace Unity.Multiplayer.Center.Analytics 11{ 12 internal static class AnalyticsUtils 13 { 14 // hard-coded to avoid recomputing every time / resizing arrays 15 public const int NumNetcodePackage = 2; 16 public const int NumHostingPackages = 1; 17 18 /// <summary> 19 /// From the recommendation view data (which contains the packages that the user sees and the user's selection), 20 /// create the list of packages that will be sent to the analytics backend. 21 /// </summary> 22 /// <param name="data">The recommendation view data as shown in the recommendation tab</param> 23 /// <param name="solutionToPackageData">The packages views</param> 24 /// <returns>The list of packages to be sent along with the installation event.</returns> 25 public static Package[] GetPackagesWithAnalyticsFormat(RecommendationViewData data, SolutionsToRecommendedPackageViewData solutionToPackageData) 26 { 27 var selectedNetcode = RecommendationUtils.GetSelectedNetcode(data); 28 var selectedHostingModel = RecommendationUtils.GetSelectedHostingModel(data); 29 var packages = solutionToPackageData.GetPackagesForSelection(selectedNetcode.Solution, selectedHostingModel.Solution); 30 var packageCount = NumNetcodePackage + NumHostingPackages + packages.Length; 31 32 var result = new Package[packageCount]; 33 var resultIndex = 0; 34 35 AddSolutionPackages(data.NetcodeOptions, result, ref resultIndex); 36 AddSolutionPackages(data.ServerArchitectureOptions, result, ref resultIndex); 37 AddRecommendedPackages(packages, result, ref resultIndex); 38 39 Debug.Assert(resultIndex == packageCount, $"Expected {packageCount} packages, got {resultIndex}"); 40 41 return result; 42 } 43 44 /// <summary> 45 /// Fetches all the inspector name attributes of the Preset enum and returns the displayNames 46 /// Important! It assumes the enum values are 0, ... , N 47 /// </summary> 48 /// <returns>The array of preset names. The index in the array is the integer value of the enum value</returns> 49 public static string[] GetPresetFullNames() 50 { 51 var t = typeof(Preset); 52 var values = Enum.GetValues(t); 53 var array = new string[values.Length]; 54 foreach (var value in values) 55 { 56 var preset = (Preset) value; 57 var index = (int)preset; 58 var asString = value.ToString(); 59 var memInfo = t.GetMember(asString); 60 var attribute = memInfo[0].GetCustomAttribute<InspectorNameAttribute>(false); 61 62 if (attribute != null) 63 { 64 array[index] = attribute.displayName; 65 } 66 else 67 { 68 Debug.LogError($"Could not fetch the full name of the preset value {asString}"); 69 array[index] = asString; 70 } 71 } 72 73 return array; 74 } 75 76 /// <summary> 77 /// Converts AnswerData to game specs, providing the knowledge of the display names. 78 /// It assumes there is exactly one answer in the answer list at this point. 79 /// </summary> 80 /// <param name="data">The answer data of the user</param> 81 /// <param name="answerIdToAnswerName">Mapping answer id to display name</param> 82 /// <param name="questionIdToQuestionName">Mapping question id to display name</param> 83 /// <returns>The list of game spec that will be consumed by the analytics backend</returns> 84 public static GameSpec[] ToGameSpecs(AnswerData data, 85 IReadOnlyDictionary<string, string> answerIdToAnswerName, 86 IReadOnlyDictionary<string, string> questionIdToQuestionName) 87 { 88 var result = new GameSpec[data.Answers.Count]; 89 for (var i = 0; i < result.Length; ++i) 90 { 91 var answer = data.Answers[i]; 92 var answerId = answer.Answers[0]; // TODO: make sure that this always exists 93 result[i] = new GameSpec() 94 { 95 QuestionId = answer.QuestionId, 96 QuestionText = questionIdToQuestionName[answer.QuestionId], 97 AcceptsMultipleAnswers = false, // TODO: add test that verifies this assumption 98 AnswerId = answerId, 99 AnswerText = answerIdToAnswerName[answerId] 100 }; 101 } 102 103 return result; 104 } 105 106 /// <summary> 107 /// Creates the mapping from question id to question display name 108 /// </summary> 109 /// <param name="questionnaireData">The questionnaire data</param> 110 /// <returns>The mapping</returns> 111 public static IReadOnlyDictionary<string, string> GetQuestionDisplayNames(QuestionnaireData questionnaireData) 112 { 113 var dictionary = new Dictionary<string, string>(); 114 foreach (var question in questionnaireData.Questions) 115 { 116 dictionary[question.Id] = question.Title; 117 } 118 119 return dictionary; 120 } 121 122 /// <summary> 123 /// Creates the mapping from answer id to answer display name 124 /// </summary> 125 /// <param name="questionnaireData">The questionnaire data</param> 126 /// <returns>The mapping</returns> 127 public static IReadOnlyDictionary<string, string> GetAnswerDisplayNames(QuestionnaireData questionnaireData) 128 { 129 var dictionary = new Dictionary<string, string>(); 130 foreach (var question in questionnaireData.Questions) 131 { 132 foreach (var answer in question.Choices) 133 { 134 dictionary[answer.Id] = answer.Title; 135 } 136 } 137 138 return dictionary; 139 } 140 141 static void AddSolutionPackages(RecommendedSolutionViewData[] options, Package[] result, ref int resultIndex) 142 { 143 foreach (var t in options) 144 { 145 if(string.IsNullOrEmpty(t.MainPackage?.PackageId)) 146 continue; 147 148 result[resultIndex] = new Package() 149 { 150 PackageId = t.MainPackage.PackageId, 151 SelectedForInstall = t.Selected && t.RecommendationType != RecommendationType.Incompatible, 152 IsRecommended = t.RecommendationType is RecommendationType.MainArchitectureChoice, 153 IsAlreadyInstalled = t.MainPackage.IsInstalledAsProjectDependency 154 }; 155 ++resultIndex; 156 } 157 } 158 159 static void AddRecommendedPackages(RecommendedPackageViewData[] packageViewDatas, Package[] result, ref int resultIndex) 160 { 161 foreach (var viewData in packageViewDatas) 162 { 163 result[resultIndex] = new Package() 164 { 165 PackageId = viewData.PackageId, 166 // TODO: remove hidden? 167 SelectedForInstall = viewData.Selected && viewData.RecommendationType != RecommendationType.Incompatible, 168 IsRecommended = viewData.RecommendationType.IsRecommendedPackage(), 169 IsAlreadyInstalled = viewData.IsInstalledAsProjectDependency 170 }; 171 ++resultIndex; 172 } 173 } 174 } 175}