229 lines
6.9 KiB
C#
229 lines
6.9 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using UnityEngine;
|
|
|
|
public static class DlcManifestService
|
|
{
|
|
private static readonly string[] ManifestFilePatterns =
|
|
{
|
|
"*.json"
|
|
};
|
|
|
|
private const string RuntimeFolderName = "DLC";
|
|
private const string ManifestFolderName = "manifests";
|
|
|
|
public static List<DlcManifestRuntimeEntry> LoadInstalledEntries()
|
|
{
|
|
DlcPackageArchiveService.PrepareInstalledPackages();
|
|
|
|
List<DlcManifestRuntimeEntry> result = new List<DlcManifestRuntimeEntry>();
|
|
HashSet<string> visitedFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
|
string[] roots = GetManifestSearchRoots();
|
|
|
|
for (int i = 0; i < roots.Length; i++)
|
|
{
|
|
string root = roots[i];
|
|
if (string.IsNullOrWhiteSpace(root) || !Directory.Exists(root))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
CollectManifestEntries(root, result, visitedFiles);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
public static string[] GetManifestSearchRoots()
|
|
{
|
|
List<string> result = new List<string>();
|
|
AppendIfValid(result, Path.Combine(Application.streamingAssetsPath, RuntimeFolderName, ManifestFolderName));
|
|
AppendIfValid(result, Path.Combine(Application.streamingAssetsPath, RuntimeFolderName));
|
|
AppendIfValid(result, Path.Combine(Application.persistentDataPath, RuntimeFolderName, ManifestFolderName));
|
|
AppendIfValid(result, Path.Combine(Application.persistentDataPath, RuntimeFolderName));
|
|
|
|
string playerRoot = GetPlayerRootDirectory();
|
|
AppendIfValid(result, Path.Combine(playerRoot, RuntimeFolderName, ManifestFolderName));
|
|
AppendIfValid(result, Path.Combine(playerRoot, RuntimeFolderName));
|
|
|
|
return result.ToArray();
|
|
}
|
|
|
|
public static DlcManifestFile ParseManifestJson(string json)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(json))
|
|
{
|
|
return null;
|
|
}
|
|
|
|
try
|
|
{
|
|
return JsonUtility.FromJson<DlcManifestFile>(json);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning("[DLC] Failed to parse manifest json: " + ex.Message);
|
|
return null;
|
|
}
|
|
}
|
|
|
|
private static void CollectManifestEntries(
|
|
string root,
|
|
List<DlcManifestRuntimeEntry> result,
|
|
HashSet<string> visitedFiles)
|
|
{
|
|
for (int patternIndex = 0; patternIndex < ManifestFilePatterns.Length; patternIndex++)
|
|
{
|
|
string pattern = ManifestFilePatterns[patternIndex];
|
|
string[] files;
|
|
try
|
|
{
|
|
files = Directory.GetFiles(root, pattern, SearchOption.AllDirectories);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning("[DLC] Failed to enumerate manifest files in '" + root + "': " + ex.Message);
|
|
continue;
|
|
}
|
|
|
|
for (int i = 0; i < files.Length; i++)
|
|
{
|
|
string manifestPath = files[i];
|
|
if (string.IsNullOrWhiteSpace(manifestPath))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string fullPath = Path.GetFullPath(manifestPath);
|
|
if (!visitedFiles.Add(fullPath))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
TryLoadManifestFile(fullPath, result);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static void TryLoadManifestFile(string manifestPath, List<DlcManifestRuntimeEntry> result)
|
|
{
|
|
try
|
|
{
|
|
string json = File.ReadAllText(manifestPath);
|
|
DlcManifestFile file = ParseManifestJson(json);
|
|
if (file == null || file.entries == null || file.entries.Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
string manifestDirectory = Path.GetDirectoryName(manifestPath) ?? string.Empty;
|
|
string manifestId = string.IsNullOrWhiteSpace(file.manifestId)
|
|
? Path.GetFileNameWithoutExtension(manifestPath)
|
|
: file.manifestId.Trim();
|
|
|
|
for (int i = 0; i < file.entries.Count; i++)
|
|
{
|
|
DlcManifestEntry entry = file.entries[i];
|
|
if (entry == null || !entry.enabled)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
string resolvedCatalogPath = ResolveCatalogPath(entry.catalogPath, manifestDirectory);
|
|
if (string.IsNullOrWhiteSpace(resolvedCatalogPath))
|
|
{
|
|
Debug.LogWarning("[DLC] Manifest entry '" + manifestId + "' has no valid catalogPath.");
|
|
continue;
|
|
}
|
|
|
|
result.Add(new DlcManifestRuntimeEntry
|
|
{
|
|
manifestId = manifestId,
|
|
manifestSourcePath = manifestPath,
|
|
manifestDirectory = manifestDirectory,
|
|
entry = entry,
|
|
resolvedCatalogPath = resolvedCatalogPath
|
|
});
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning("[DLC] Failed to load manifest '" + manifestPath + "': " + ex.Message);
|
|
}
|
|
}
|
|
|
|
private static string ResolveCatalogPath(string catalogPath, string manifestDirectory)
|
|
{
|
|
if (string.IsNullOrWhiteSpace(catalogPath))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
string trimmed = catalogPath.Trim();
|
|
if (trimmed.StartsWith("http://", StringComparison.OrdinalIgnoreCase) ||
|
|
trimmed.StartsWith("https://", StringComparison.OrdinalIgnoreCase) ||
|
|
trimmed.StartsWith("file://", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
return trimmed;
|
|
}
|
|
|
|
string combined = trimmed;
|
|
if (!Path.IsPathRooted(combined))
|
|
{
|
|
combined = Path.Combine(manifestDirectory ?? string.Empty, combined);
|
|
}
|
|
|
|
try
|
|
{
|
|
return new Uri(Path.GetFullPath(combined)).AbsoluteUri;
|
|
}
|
|
catch
|
|
{
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
private static string GetPlayerRootDirectory()
|
|
{
|
|
try
|
|
{
|
|
string dataPath = Application.dataPath;
|
|
if (string.IsNullOrWhiteSpace(dataPath))
|
|
{
|
|
return string.Empty;
|
|
}
|
|
|
|
DirectoryInfo parent = Directory.GetParent(dataPath);
|
|
return parent != null ? parent.FullName : string.Empty;
|
|
}
|
|
catch
|
|
{
|
|
return string.Empty;
|
|
}
|
|
}
|
|
|
|
private static void AppendIfValid(List<string> result, string path)
|
|
{
|
|
if (result == null || string.IsNullOrWhiteSpace(path))
|
|
{
|
|
return;
|
|
}
|
|
|
|
string fullPath;
|
|
try
|
|
{
|
|
fullPath = Path.GetFullPath(path);
|
|
}
|
|
catch
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!result.Contains(fullPath))
|
|
{
|
|
result.Add(fullPath);
|
|
}
|
|
}
|
|
}
|