621 lines
14 KiB
C#
621 lines
14 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using UnityEngine.AddressableAssets;
|
|
using UnityEngine.ResourceManagement.AsyncOperations;
|
|
using UnityEngine.ResourceManagement.ResourceLocations;
|
|
|
|
/// <summary>
|
|
/// Baixa e carrega jogos Addressable somente quando forem necessários.
|
|
/// Compatível com Unity 2019.3 e Addressables 1.1.x.
|
|
/// </summary>
|
|
public static class AddressableGameDownloader
|
|
{
|
|
private static readonly Dictionary<string, AsyncOperationHandle> LoadedHandles =
|
|
new Dictionary<string, AsyncOperationHandle>(
|
|
StringComparer.OrdinalIgnoreCase
|
|
);
|
|
|
|
/// <summary>
|
|
/// Valida se o Address existe no catálogo carregado,
|
|
/// verifica o tamanho pendente,
|
|
/// baixa as dependências se necessário
|
|
/// e depois carrega o asset.
|
|
/// </summary>
|
|
public static IEnumerator LoadAsset<T>(
|
|
string address,
|
|
Action<T> onSuccess,
|
|
Action<float> onProgress = null,
|
|
Action<string> onStatus = null,
|
|
Action<string> onError = null)
|
|
where T : UnityEngine.Object
|
|
{
|
|
if (string.IsNullOrEmpty(address))
|
|
{
|
|
Fail(
|
|
"O endereço Addressable está vazio.",
|
|
onError
|
|
);
|
|
|
|
yield break;
|
|
}
|
|
|
|
Debug.Log(
|
|
"[Addressables] ==================================="
|
|
);
|
|
|
|
Debug.Log(
|
|
"[Addressables] Tentando carregar: [" +
|
|
address +
|
|
"]"
|
|
);
|
|
|
|
/*
|
|
* 1. VALIDA SE O ADDRESS EXISTE
|
|
*/
|
|
onStatus?.Invoke(
|
|
"Localizando conteúdo..."
|
|
);
|
|
|
|
AsyncOperationHandle<IList<IResourceLocation>> locationHandle =
|
|
Addressables.LoadResourceLocationsAsync(
|
|
address
|
|
);
|
|
|
|
yield return locationHandle;
|
|
|
|
bool locationFound =
|
|
locationHandle.Status ==
|
|
AsyncOperationStatus.Succeeded &&
|
|
locationHandle.Result != null &&
|
|
locationHandle.Result.Count > 0;
|
|
|
|
if (!locationFound)
|
|
{
|
|
if (locationHandle.IsValid())
|
|
{
|
|
Addressables.Release(
|
|
locationHandle
|
|
);
|
|
}
|
|
|
|
Fail(
|
|
"ADDRESS NÃO EXISTE NO CATÁLOGO: [" +
|
|
address +
|
|
"]",
|
|
onError
|
|
);
|
|
|
|
yield break;
|
|
}
|
|
|
|
Debug.Log(
|
|
"[Addressables] Address encontrado: [" +
|
|
address +
|
|
"]"
|
|
);
|
|
|
|
Debug.Log(
|
|
"[Addressables] Localizações encontradas: " +
|
|
locationHandle.Result.Count
|
|
);
|
|
|
|
for (int i = 0; i < locationHandle.Result.Count; i++)
|
|
{
|
|
IResourceLocation location =
|
|
locationHandle.Result[i];
|
|
|
|
Debug.Log(
|
|
"[Addressables] Localização [" +
|
|
i +
|
|
"] PrimaryKey: " +
|
|
location.PrimaryKey
|
|
);
|
|
|
|
Debug.Log(
|
|
"[Addressables] Localização [" +
|
|
i +
|
|
"] InternalId: " +
|
|
location.InternalId
|
|
);
|
|
}
|
|
|
|
Addressables.Release(
|
|
locationHandle
|
|
);
|
|
|
|
/*
|
|
* 2. VERIFICA TAMANHO DO DOWNLOAD
|
|
*/
|
|
onStatus?.Invoke(
|
|
"Verificando conteúdo..."
|
|
);
|
|
|
|
AsyncOperationHandle<long> sizeHandle =
|
|
Addressables.GetDownloadSizeAsync(
|
|
address
|
|
);
|
|
|
|
yield return sizeHandle;
|
|
|
|
if (
|
|
sizeHandle.Status !=
|
|
AsyncOperationStatus.Succeeded
|
|
)
|
|
{
|
|
if (sizeHandle.IsValid())
|
|
{
|
|
Addressables.Release(
|
|
sizeHandle
|
|
);
|
|
}
|
|
|
|
Fail(
|
|
"Não foi possível consultar o tamanho do Addressable: [" +
|
|
address +
|
|
"]",
|
|
onError
|
|
);
|
|
|
|
yield break;
|
|
}
|
|
|
|
long downloadSize =
|
|
sizeHandle.Result;
|
|
|
|
Debug.Log(
|
|
"[Addressables] Tamanho pendente: " +
|
|
FormatBytes(downloadSize)
|
|
);
|
|
|
|
Addressables.Release(
|
|
sizeHandle
|
|
);
|
|
|
|
/*
|
|
* 3. DOWNLOAD
|
|
*/
|
|
if (downloadSize > 0)
|
|
{
|
|
onStatus?.Invoke(
|
|
"Baixando " +
|
|
FormatBytes(downloadSize)
|
|
);
|
|
|
|
Debug.Log(
|
|
"[Addressables] Iniciando download: [" +
|
|
address +
|
|
"]"
|
|
);
|
|
|
|
AsyncOperationHandle downloadHandle =
|
|
Addressables.DownloadDependenciesAsync(
|
|
address
|
|
);
|
|
|
|
while (!downloadHandle.IsDone)
|
|
{
|
|
if (onProgress != null)
|
|
{
|
|
onProgress(
|
|
downloadHandle.PercentComplete
|
|
);
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
if (
|
|
downloadHandle.Status !=
|
|
AsyncOperationStatus.Succeeded
|
|
)
|
|
{
|
|
if (downloadHandle.IsValid())
|
|
{
|
|
Addressables.Release(
|
|
downloadHandle
|
|
);
|
|
}
|
|
|
|
Fail(
|
|
"Falha ao baixar o Addressable: [" +
|
|
address +
|
|
"]",
|
|
onError
|
|
);
|
|
|
|
yield break;
|
|
}
|
|
|
|
Debug.Log(
|
|
"[Addressables] Download concluído: [" +
|
|
address +
|
|
"]"
|
|
);
|
|
|
|
if (downloadHandle.IsValid())
|
|
{
|
|
Addressables.Release(
|
|
downloadHandle
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.Log(
|
|
"[Addressables] Conteúdo já está no cache: [" +
|
|
address +
|
|
"]"
|
|
);
|
|
|
|
if (onProgress != null)
|
|
{
|
|
onProgress(1f);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* 4. CARREGA O ASSET
|
|
*/
|
|
onStatus?.Invoke(
|
|
"Carregando conteúdo..."
|
|
);
|
|
|
|
Debug.Log(
|
|
"[Addressables] LoadAssetAsync: [" +
|
|
address +
|
|
"]"
|
|
);
|
|
|
|
AsyncOperationHandle<T> loadHandle =
|
|
Addressables.LoadAssetAsync<T>(
|
|
address
|
|
);
|
|
|
|
while (!loadHandle.IsDone)
|
|
{
|
|
if (onProgress != null)
|
|
{
|
|
onProgress(
|
|
loadHandle.PercentComplete
|
|
);
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
if (
|
|
loadHandle.Status !=
|
|
AsyncOperationStatus.Succeeded ||
|
|
loadHandle.Result == null
|
|
)
|
|
{
|
|
if (loadHandle.IsValid())
|
|
{
|
|
Addressables.Release(
|
|
loadHandle
|
|
);
|
|
}
|
|
|
|
Fail(
|
|
"Falha ao carregar o Addressable: [" +
|
|
address +
|
|
"]",
|
|
onError
|
|
);
|
|
|
|
yield break;
|
|
}
|
|
|
|
/*
|
|
* 5. GUARDA HANDLE
|
|
*/
|
|
AsyncOperationHandle previous;
|
|
|
|
if (
|
|
LoadedHandles.TryGetValue(
|
|
address,
|
|
out previous
|
|
)
|
|
)
|
|
{
|
|
if (previous.IsValid())
|
|
{
|
|
Addressables.Release(
|
|
previous
|
|
);
|
|
}
|
|
|
|
LoadedHandles.Remove(
|
|
address
|
|
);
|
|
}
|
|
|
|
LoadedHandles[address] =
|
|
loadHandle;
|
|
|
|
if (onProgress != null)
|
|
{
|
|
onProgress(1f);
|
|
}
|
|
|
|
onStatus?.Invoke(
|
|
"Conteúdo carregado."
|
|
);
|
|
|
|
Debug.Log(
|
|
"[Addressables] SUCESSO: [" +
|
|
address +
|
|
"]"
|
|
);
|
|
|
|
Debug.Log(
|
|
"[Addressables] ==================================="
|
|
);
|
|
|
|
if (onSuccess != null)
|
|
{
|
|
onSuccess(
|
|
loadHandle.Result
|
|
);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Verifica se um Address existe no catálogo atualmente carregado.
|
|
/// </summary>
|
|
public static IEnumerator Exists(
|
|
string address,
|
|
Action<bool> completed)
|
|
{
|
|
if (string.IsNullOrEmpty(address))
|
|
{
|
|
Debug.LogError(
|
|
"[Addressables] Exists recebeu address vazio."
|
|
);
|
|
|
|
if (completed != null)
|
|
{
|
|
completed(false);
|
|
}
|
|
|
|
yield break;
|
|
}
|
|
|
|
Debug.Log(
|
|
"[Addressables] Verificando Address: [" +
|
|
address +
|
|
"]"
|
|
);
|
|
|
|
AsyncOperationHandle<IList<IResourceLocation>> handle =
|
|
Addressables.LoadResourceLocationsAsync(
|
|
address
|
|
);
|
|
|
|
yield return handle;
|
|
|
|
bool exists =
|
|
handle.Status ==
|
|
AsyncOperationStatus.Succeeded &&
|
|
handle.Result != null &&
|
|
handle.Result.Count > 0;
|
|
|
|
if (exists)
|
|
{
|
|
Debug.Log(
|
|
"[Addressables] Address EXISTE: [" +
|
|
address +
|
|
"]"
|
|
);
|
|
|
|
for (int i = 0; i < handle.Result.Count; i++)
|
|
{
|
|
Debug.Log(
|
|
"[Addressables] -> " +
|
|
handle.Result[i].InternalId
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Debug.LogError(
|
|
"[Addressables] Address NÃO EXISTE no catálogo: [" +
|
|
address +
|
|
"]"
|
|
);
|
|
}
|
|
|
|
if (handle.IsValid())
|
|
{
|
|
Addressables.Release(
|
|
handle
|
|
);
|
|
}
|
|
|
|
if (completed != null)
|
|
{
|
|
completed(
|
|
exists
|
|
);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Consulta quanto ainda precisa ser baixado.
|
|
/// 0 bytes significa que já está no cache.
|
|
/// </summary>
|
|
public static IEnumerator GetDownloadSize(
|
|
string address,
|
|
Action<long> completed,
|
|
Action<string> onError = null)
|
|
{
|
|
if (string.IsNullOrEmpty(address))
|
|
{
|
|
Fail(
|
|
"O endereço Addressable está vazio.",
|
|
onError
|
|
);
|
|
|
|
yield break;
|
|
}
|
|
|
|
AsyncOperationHandle<long> handle =
|
|
Addressables.GetDownloadSizeAsync(
|
|
address
|
|
);
|
|
|
|
yield return handle;
|
|
|
|
if (
|
|
handle.Status ==
|
|
AsyncOperationStatus.Succeeded
|
|
)
|
|
{
|
|
Debug.Log(
|
|
"[Addressables] Download pendente para [" +
|
|
address +
|
|
"]: " +
|
|
FormatBytes(handle.Result)
|
|
);
|
|
|
|
if (completed != null)
|
|
{
|
|
completed(
|
|
handle.Result
|
|
);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
Fail(
|
|
"Falha ao consultar tamanho: [" +
|
|
address +
|
|
"]",
|
|
onError
|
|
);
|
|
}
|
|
|
|
if (handle.IsValid())
|
|
{
|
|
Addressables.Release(
|
|
handle
|
|
);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Libera um Addressable carregado anteriormente.
|
|
/// </summary>
|
|
public static void Release(
|
|
string address)
|
|
{
|
|
if (string.IsNullOrEmpty(address))
|
|
{
|
|
return;
|
|
}
|
|
|
|
AsyncOperationHandle handle;
|
|
|
|
if (
|
|
!LoadedHandles.TryGetValue(
|
|
address,
|
|
out handle
|
|
)
|
|
)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (handle.IsValid())
|
|
{
|
|
Addressables.Release(
|
|
handle
|
|
);
|
|
}
|
|
|
|
LoadedHandles.Remove(
|
|
address
|
|
);
|
|
|
|
Debug.Log(
|
|
"[Addressables] Liberado: [" +
|
|
address +
|
|
"]"
|
|
);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Libera todos os Addressables carregados.
|
|
/// </summary>
|
|
public static void ReleaseAll()
|
|
{
|
|
foreach (
|
|
KeyValuePair<string, AsyncOperationHandle> item
|
|
in LoadedHandles
|
|
)
|
|
{
|
|
if (item.Value.IsValid())
|
|
{
|
|
Addressables.Release(
|
|
item.Value
|
|
);
|
|
}
|
|
}
|
|
|
|
LoadedHandles.Clear();
|
|
|
|
Debug.Log(
|
|
"[Addressables] Todos os handles foram liberados."
|
|
);
|
|
}
|
|
|
|
private static void Fail(
|
|
string message,
|
|
Action<string> onError)
|
|
{
|
|
Debug.LogError(
|
|
"[Addressables] " +
|
|
message
|
|
);
|
|
|
|
if (onError != null)
|
|
{
|
|
onError(
|
|
message
|
|
);
|
|
}
|
|
}
|
|
|
|
private static string FormatBytes(
|
|
long bytes)
|
|
{
|
|
const long KB = 1024;
|
|
const long MB = KB * 1024;
|
|
const long GB = MB * 1024;
|
|
|
|
if (bytes >= GB)
|
|
{
|
|
return (
|
|
bytes / (float)GB
|
|
).ToString("0.00") + " GB";
|
|
}
|
|
|
|
if (bytes >= MB)
|
|
{
|
|
return (
|
|
bytes / (float)MB
|
|
).ToString("0.00") + " MB";
|
|
}
|
|
|
|
if (bytes >= KB)
|
|
{
|
|
return (
|
|
bytes / (float)KB
|
|
).ToString("0.00") + " KB";
|
|
}
|
|
|
|
return bytes + " bytes";
|
|
}
|
|
} |