using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
namespace Ubisoft.Hotel.Package.Editor
{
[Serializable]
public class PackageDefinition
{
[SerializeField]
public enum EImplementation
{
Prod,
Dummy,
Mock
};
[SerializeField]
private string m_name;
[SerializeField]
private string m_version;
[SerializeField]
private EImplementation m_implementation;
public string Name
{
get { return m_name; }
private set { m_name = value; }
}
public string Version
{
get { return m_version; }
set { m_version = value; }
}
public EImplementation Implementation
{
get { return m_implementation; }
set { m_implementation = value; }
}
public PackageDefinition(string id, string version, EImplementation implementation)
{
Name = id;
Version = version;
Implementation = implementation;
}
}
public class UpmBuildProperty : PackageProperty
{
///
/// Dictionary used as a backup to store dependencies before changing them so we can tell whether or not they've changed.
/// It's used as a temporary variable. It's declared only to avoid creating over and over every time configuration changes
///
private static readonly Dictionary TempDependencies = new Dictionary();
public static UpmBuildProperty CreateInstanceWithParams(string name)
{
UpmBuildProperty returnValue = CreateInstance();
returnValue.name = name;
return returnValue;
}
public static string ReadManifestJson()
{
string path = PATH_MANIFEST;
return File.Exists(path) ? File.ReadAllText(path) : null;
}
private const string PATH_MANIFEST = "Packages/manifest.json";
[SerializeField]
private List m_packages;
public void Clear()
{
if (m_packages != null)
{
m_packages.Clear();
}
}
public override void Apply(BuildSuite buildSuite)
{
if (buildSuite != null)
{
buildSuite.OrderProperty(this);
}
}
public void Join(UpmBuildProperty p)
{
if (p != null)
{
if (p.m_packages != null)
{
foreach (PackageDefinition packageDefinition in p.m_packages)
{
AddPackage(packageDefinition.Name, packageDefinition.Version, packageDefinition.Implementation);
}
}
}
}
public void PreBuild(Dictionary packagesHandledByConsumer, Action> onDone)
{
Manifest manifest = ProcessManifest(packagesHandledByConsumer, true);
PackageManagerHelper.PrunePackagesResources(packagesHandledByConsumer, manifest.Dependencies, HtAssetDatabase.UnityPathToPlatformPath(AssetManager.HOTEL_ASSETS_RESOURCES_PATH));
onDone?.Invoke(manifest, GetSymbols(manifest, packagesHandledByConsumer));
}
private HashSet GetSymbols(Manifest manifest, Dictionary packagesHandledByConsumer)
{
HashSet returnValue = null;
if (manifest != null && packagesHandledByConsumer != null)
{
returnValue = new HashSet();
if (manifest.Dependencies != null)
{
// Is the package OFF?
foreach (KeyValuePair pair in packagesHandledByConsumer)
{
if (!manifest.Dependencies.ContainsDependency(pair.Key))
{
_ = returnValue.Add(UnityBuildProperty.GetPackageSymbol(pair.Key, false));
}
}
PackageDefinition packageDefinition;
PackageDefinition.EImplementation implementation;
Dictionary dependencies = manifest.Dependencies.GetDependencies();
foreach (KeyValuePair pair in dependencies)
{
if (UnityBuildProperty.IsDefineSymbolEnabledForPackage(pair.Key))
{
packageDefinition = GetPackage(pair.Key);
if (packageDefinition == null)
{
// We assume PROD as implementation for packages with no denition provided
implementation = PackageDefinition.EImplementation.Prod;
}
else
{
implementation = packageDefinition.Implementation;
}
_ = returnValue.Add(UnityBuildProperty.GetPackageSymbol(pair.Key, true, implementation));
}
}
}
}
return returnValue;
}
public void PostBuild()
{
}
public void AddPackage(string name, string version, PackageDefinition.EImplementation implementation)
{
bool validateName = ValidatePackageAttribute(name, "name");
bool validateVersion = ValidatePackageAttribute(version, "version");
if (validateName && validateVersion)
{
PackageDefinition package = GetPackage(name);
if (package == null)
{
package = new PackageDefinition(name, version, implementation);
if (m_packages == null)
{
m_packages = new List();
}
m_packages.Add(package);
}
else
{
package.Version = version;
}
}
}
private bool ValidatePackageAttribute(string value, string attributeName = null)
{
bool returnValue = !string.IsNullOrEmpty(value);
if (!returnValue && attributeName != null)
{
string message = $"You are attempting to add an empty package {Debug.FormatTextInUserContext(attributeName)} to " +
$"{Debug.FormatTextInUserContext(Name)} PackageProperty";
message = $"[{Debug.FormatTextInUserContext(Name)}({Debug.FormatTextInCodeContext("UpmBuildProperty")})]: {message}";
Debug.EditorLogError(message);
}
return returnValue;
}
public void RemovePackage(string name)
{
PackageDefinition package = GetPackage(name);
if (package != null)
{
_ = m_packages.Remove(package);
}
}
private PackageDefinition GetPackage(string name)
{
PackageDefinition returnValue = null;
if (m_packages != null && ValidatePackageAttribute(name, null))
{
int count = m_packages.Count;
for (int i = 0; i < count && returnValue == null; ++i)
{
if (m_packages[i].Name == name)
{
returnValue = m_packages[i];
}
}
}
return returnValue;
}
private Manifest ProcessManifest(Dictionary packagesHandledViaProperties, bool writeManifest)
{
Manifest manifest = null;
string json = ReadManifestJson();
if (!string.IsNullOrEmpty(json))
{
manifest = Manifest.Parse(json);
// Remove packages that are handled by SuiteManager
if (manifest != null)
{
TempDependencies.Clear();
if (manifest.Dependencies != null)
{
Dictionary dependencies = manifest.Dependencies.GetDependencies();
if (dependencies != null)
{
foreach (KeyValuePair pair in dependencies)
{
TempDependencies.Add(pair.Key, pair.Value);
}
}
}
if (packagesHandledViaProperties != null)
{
foreach (KeyValuePair pair in packagesHandledViaProperties)
{
manifest.RemoveDependency(pair.Key);
}
}
manifest.RemovePluggableDependencies();
if (m_packages != null)
{
// Add pluggable packages
foreach (PackageDefinition p in m_packages)
{
manifest.AddDependency(p.Name, p.Version, true);
}
}
Dictionary newDependencies = null;
if (manifest.Dependencies != null)
{
newDependencies = manifest.Dependencies.GetDependencies();
}
// Manifest is written only if dependencies have changed
if (writeManifest)
{
int count = (TempDependencies == null) ? 0 : TempDependencies.Count;
int newCount = (newDependencies == null) ? 0 : newDependencies.Count;
writeManifest = count != newCount;
if (!writeManifest && newDependencies != null && TempDependencies != null)
{
foreach (KeyValuePair pair in newDependencies)
{
if (!TempDependencies.ContainsKey(pair.Key) || TempDependencies[pair.Key] != pair.Value)
{
writeManifest = true;
break;
}
}
}
}
TempDependencies.Clear();
if (writeManifest)
{
manifest.NeedsToSave = true;
// Force PackageManager to resolve in Unity 2020, otherwise packages won't get updated without leaving and returning to the Editor
UnityEditor.PackageManager.Client.Resolve();
}
}
}
return manifest;
}
}
}