using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Xml; using UnityEditor; using UnityEngine; using Azerion.BlueStack.Editor.Android; using Azerion.BlueStack.Editor.iOS; namespace Azerion.BlueStack.Editor { public class DependencyProvider { private static readonly string _editorPathInPackage = "Packages/com.azerion.bluestack/Editor/"; private static readonly string _dependencyPathInPackage = _editorPathInPackage + "BlueStackDependenciesSource.xml"; private static readonly string _mediationDependencyPathInPackage = _editorPathInPackage + "BlueStackMediationNetworks.xml"; private static readonly string _editorPathInAssets = "Assets/Editor/"; private static readonly string _dependencyPathInAssets = _editorPathInAssets + "BlueStackDependencies.xml"; private static readonly string _mediationDependencyPathInAssets = _editorPathInAssets + "BlueStackMediationNetworks.xml"; public static List GetDependencies(IDependencyParser parser) { if (File.Exists(_dependencyPathInAssets)) { return parser.ParseDependencies(_dependencyPathInAssets); } else { Debug.LogError("Dependencies file not found at: " + _dependencyPathInAssets); return new List(); } } public static List GetBlueStackDependencies(IDependencyParser parser) { // Get currently active dependencies from the asset (user selection) var activeDependencies = parser .ParseBlueStackDependencies("Assets/Editor/BlueStackDependencies.xml") .Select(d => d.Name) .ToHashSet(); // Get all available dependencies from the package (source of truth), marking active var allDependencies = parser.ParseBlueStackDependencies( _dependencyPathInPackage, activeDependencies ); return allDependencies; } public static void SyncDependenciesXMLs() { if (!File.Exists(_dependencyPathInPackage)) { Debug.LogError("BlueStackDependenciesSource.xml in Package is missing!"); return; } // TODO: remove in future, this is to clean up old files (upgrading to v3.2.0) // Check if mediation dependency file exists in assets and delete it if (File.Exists(_mediationDependencyPathInAssets)) { FileUtil.DeleteFileOrDirectory(_mediationDependencyPathInAssets); AssetDatabase.Refresh(); Debug.Log("BlueStackMediationNetworks.xml deleted from Assets/Editor."); } // 1. If the asset file does not exist, copy from package if (!File.Exists(_dependencyPathInAssets)) { Directory.CreateDirectory(_editorPathInAssets); FileUtil.CopyFileOrDirectory(_dependencyPathInPackage, _dependencyPathInAssets); AssetDatabase.Refresh(); Debug.Log("BlueStackDependencies copied to Assets/Editor (did not exist)."); return; } // 2. If the asset file exists, compare version attribute string packageVersion = GetXmlVersion(_dependencyPathInPackage); string assetVersion = GetXmlVersion(_dependencyPathInAssets); if (packageVersion != assetVersion) { FileUtil.ReplaceFile(_dependencyPathInPackage, _dependencyPathInAssets); AssetDatabase.Refresh(); Debug.Log( $"BlueStackDependencies.xml replaced in Assets/Editor (version changed: {assetVersion} -> {packageVersion})." ); return; } // If versions match, do nothing (even if hash differs, since user changes are allowed) Debug.Log("BlueStackDependencies.xml is up to date in Assets/Editor."); } // Helper to extract version attribute from the root node of the XML private static string GetXmlVersion(string xmlFilePath) { if (!File.Exists(xmlFilePath)) return null; try { var xmlDoc = new XmlDocument(); xmlDoc.Load(xmlFilePath); var root = xmlDoc.DocumentElement; if (root != null && root.Attributes != null && root.Attributes["version"] != null) { return root.Attributes["version"].Value; } } catch (Exception e) { Debug.LogError($"Error reading version from {xmlFilePath}: {e.Message}"); } return null; } // Helper to compute hash of the XML file (for future use or debugging) public static string GetFileHash(string filePath) { if (!File.Exists(filePath)) return null; try { using (var stream = File.OpenRead(filePath)) { using (var sha256 = System.Security.Cryptography.SHA256.Create()) { var hash = sha256.ComputeHash(stream); return BitConverter.ToString(hash).Replace("-", "").ToLowerInvariant(); } } } catch (Exception e) { Debug.LogError($"Error computing hash for {filePath}: {e.Message}"); } return null; } public static void SaveDependenciesXMLFile(string updatedXML) { // Replace main mediation dependency XML content with the updated XML System.IO.File.WriteAllText(_dependencyPathInAssets, updatedXML); AssetDatabase.Refresh(); } public static void SaveMainXMLFile(string updatedXML, string path) { // Replace main XML content with the updated XML System.IO.File.WriteAllText(path, updatedXML); AssetDatabase.Refresh(); } private static bool CopyDependenciesXMLFileToAssets() { if (!File.Exists(_dependencyPathInAssets)) { Directory.CreateDirectory(_editorPathInAssets); FileUtil.ReplaceFile(_dependencyPathInPackage, _dependencyPathInAssets); AssetDatabase.Refresh(); return true; } return false; } } }