4using System.Text.RegularExpressions;
19 internal static class YandexEditorDummyUpdater
24 private const string AssetsFolder =
"Assets";
27 private const string FactoryFileName =
"YandexMobileAdsClientFactory.cs";
30 private const string GeneratedFolderName =
"SCG.EditorDummies";
33 private const string FactoryPatchMarker =
"SCG_ENHANCED_EDITOR_FACTORY_PATCH";
40 private static readonly Encoding s_utf8Encoding =
new UTF8Encoding(
false);
43 private static readonly
string[] s_generatedFileNames =
45 "SCGEditorRewardedAdDummy.cs",
46 "SCGEditorInterstitialAdDummy.cs",
47 "SCGEditorAppOpenAdDummy.cs",
48 "SCGEditorBannerClient.cs"
57 private static (
string FileName,
string Content)[] GetGeneratedFiles(YandexData yandexData) =>
new[]
59 (s_generatedFileNames[0], yandexData.RewardedDummyTemplate),
60 (s_generatedFileNames[1], yandexData.InterstitialDummyTemplate),
61 (s_generatedFileNames[2], yandexData.AppOpenDummyTemplate),
62 (s_generatedFileNames[3], yandexData.BannerDummyTemplate)
69 private static readonly (
string MethodName,
string StockReturnLine,
string PatchedReturnLine)[] s_factoryPatches =
71 CreateFactoryPatch(
"BuildBannerClient",
"DummyBannerClient",
"SCGEditorBannerClient"),
72 CreateFactoryPatch(
"BuildInterstitialAdLoaderClient",
"DummyInterstitialAdLoaderClient",
"SCGEditorInterstitialAdLoaderClient"),
73 CreateFactoryPatch(
"BuildRewardedAdLoaderClient",
"DummyRewardedAdLoaderClient",
"SCGEditorRewardedAdLoaderClient"),
74 CreateFactoryPatch(
"BuildAppOpenAdLoaderClient",
"DummyAppOpenAdLoaderClient",
"SCGEditorAppOpenAdLoaderClient")
84 private static (
string MethodName,
string StockReturnLine,
string PatchedReturnLine) CreateFactoryPatch(
85 string methodName,
string stockTypeName,
string enhancedTypeName) =>
86 (methodName, $
"return new {stockTypeName}();", $
"return new {enhancedTypeName}(); // {FactoryPatchMarker}");
99 internal static bool ApplyOrRestore(YandexData yandexData,
bool useEnhancedEditorDummies)
101 if (UnityEditor.AssetDatabase.IsAssetImportWorkerProcess())
104 if (yandexData ==
null)
105 throw new ArgumentNullException(nameof(yandexData));
107 if (useEnhancedEditorDummies)
109 var generatedChanged = EnsureGeneratedFiles(yandexData);
110 var factoryChanged = TryUpdateFactory(yandexData,
true, out var appliedFactoryPatch);
111 return generatedChanged || (factoryChanged && appliedFactoryPatch);
114 if (!TryUpdateFactory(yandexData,
false, out var restoredFactoryPatch))
117 var deletedFiles = DeleteGeneratedFiles(yandexData);
118 return restoredFactoryPatch || deletedFiles;
121 #region Generated files
128 private static bool EnsureGeneratedFiles(YandexData yandexData)
130 var folderPath = GetGeneratedFolderPath(yandexData);
131 var absoluteFolderPath = ToAbsolutePath(folderPath);
132 Directory.CreateDirectory(absoluteFolderPath);
135 foreach (var (fileName, content) in GetGeneratedFiles(yandexData))
137 if (
string.IsNullOrWhiteSpace(content))
139 Debug.LogWarning($
"[{nameof(YandexEditorDummyUpdater)}]: {fileName} template is empty in {nameof(AdAggregatorResource)}.");
143 var assetsRelativePath = $
"{folderPath}/{fileName}";
144 var absolutePath = ToAbsolutePath(assetsRelativePath);
145 var currentContent = File.Exists(absolutePath) ? File.ReadAllText(absolutePath) :
null;
147 if (
string.Equals(currentContent, content, StringComparison.Ordinal))
150 File.WriteAllText(absolutePath, content, s_utf8Encoding);
151 Debug.Log($
"[{nameof(YandexEditorDummyUpdater)}]: Updated {fileName}.");
163 private static bool DeleteGeneratedFiles(YandexData yandexData)
165 var folderPath = GetGeneratedFolderPath(yandexData);
169 foreach (var fileName
in s_generatedFileNames)
171 changed |= DeleteFileWithMeta($
"{folderPath}/{fileName}");
174 return DeleteDirectoryIfEmpty(folderPath) || changed;
181 private static bool DeleteFileWithMeta(
string assetsRelativePath)
183 var absolutePath = ToAbsolutePath(assetsRelativePath);
186 if (File.Exists(absolutePath))
188 File.Delete(absolutePath);
189 Debug.Log($
"[{nameof(YandexEditorDummyUpdater)}]: Deleted {Path.GetFileName(assetsRelativePath)}.");
193 var metaPath = absolutePath +
".meta";
195 if (File.Exists(metaPath))
197 File.Delete(metaPath);
208 private static bool DeleteDirectoryIfEmpty(
string assetsRelativePath)
210 var absolutePath = ToAbsolutePath(assetsRelativePath);
211 if (!Directory.Exists(absolutePath))
214 if (Directory.GetFiles(absolutePath).Length > 0 || Directory.GetDirectories(absolutePath).Length > 0)
217 Directory.Delete(absolutePath);
219 var metaPath = absolutePath +
".meta";
220 if (File.Exists(metaPath))
222 File.Delete(metaPath);
233 private static string GetGeneratedFolderPath(YandexData yandexData) =>
234 $
"{ToAssetsPath(yandexData.AssetPath)}/Common/{GeneratedFolderName}";
238 #region Factory patch
253 private static bool TryUpdateFactory(YandexData yandexData,
bool applyEnhancedDummies, out
bool changed)
255 var factoryPath = GetFactoryPath(yandexData);
256 var absolutePath = ToAbsolutePath(factoryPath);
259 if (!File.Exists(absolutePath))
262 $
"[{nameof(YandexEditorDummyUpdater)}]: {FactoryFileName} was not found at '{factoryPath}'.");
266 var original = File.ReadAllText(absolutePath);
267 var updated = original;
269 foreach (var factoryPatch
in s_factoryPatches)
271 if (TryPatchFactoryMethod(updated, factoryPatch, applyEnhancedDummies, out updated))
continue;
273 $
"[{nameof(YandexEditorDummyUpdater)}]: Unable to {(applyEnhancedDummies ? "apply
" : "restore
")} editor patch for {factoryPatch.MethodName}.");
277 if (
string.Equals(original, updated, StringComparison.Ordinal))
280 File.WriteAllText(absolutePath, updated, s_utf8Encoding);
283 $
"[{nameof(YandexEditorDummyUpdater)}]: {(applyEnhancedDummies ? "Applied
" : "Restored
")} editor factory patch.");
296 private static bool TryPatchFactoryMethod(
298 (
string MethodName,
string StockReturnLine,
string PatchedReturnLine) patch,
299 bool applyEnhancedDummies,
302 var sourceLine = applyEnhancedDummies ? patch.StockReturnLine : patch.PatchedReturnLine;
303 var targetLine = applyEnhancedDummies ? patch.PatchedReturnLine : patch.StockReturnLine;
305 $@"(internal static [^\r\n]+ {Regex.Escape(patch.MethodName)}\([^)]*\)\s*\{{\s*#if UNITY_EDITOR\s*){Regex.Escape(sourceLine)}(?=\s*#elif)";
307 var regex =
new Regex(methodPattern, RegexOptions.Singleline | RegexOptions.CultureInvariant);
308 var match = regex.Match(source);
311 updated = regex.Replace(source, currentMatch => currentMatch.Groups[1].Value + targetLine, 1);
316 $@"internal static [^\r\n]+ {Regex.Escape(patch.MethodName)}\([^)]*\)\s*\{{\s*#if UNITY_EDITOR\s*{Regex.Escape(targetLine)}(?=\s*#elif)";
317 if (Regex.IsMatch(source, currentPattern, RegexOptions.Singleline | RegexOptions.CultureInvariant))
332 private static string GetFactoryPath(YandexData yandexData) =>
333 $
"{ToAssetsPath(yandexData.AssetPath)}/Platforms/{FactoryFileName}";
344 private static string ToAssetsPath(
string possiblyRelativeToAssetsFolder)
346 var path = possiblyRelativeToAssetsFolder.Replace(
"\\",
"/");
347 return path.StartsWith($
"{AssetsFolder}/", StringComparison.Ordinal) ? path : $
"{AssetsFolder}/{path}";
356 private static string ToAbsolutePath(
string assetsRelativePath)
358 var normalizedPath = assetsRelativePath.Replace(
"\\",
"/");
359 if (
string.Equals(normalizedPath, AssetsFolder, StringComparison.Ordinal))
360 return Application.dataPath.Replace(
"\\",
"/");
362 if (!normalizedPath.StartsWith($
"{AssetsFolder}/", StringComparison.Ordinal))
364 throw new UnityException($
"Path must be {AssetsFolder}-relative: {assetsRelativePath}");
367 var relativePath = normalizedPath[(AssetsFolder.Length + 1)..];
368 return Path.GetFullPath(Path.Combine(Application.dataPath, relativePath)).Replace(
'\\',
'/');