using System;
using System.Collections.Generic;
using UnityEngine.Localization.Operations;
using UnityEngine.Localization.Tables;
using UnityEngine.Pool;
using UnityEngine.ResourceManagement.AsyncOperations;
namespace UnityEngine.Localization.Settings
{
///
/// Options for the different fallback behaviours that are available.
///
public enum FallbackBehavior
{
///
/// Uses the value in
/// when localizing a string or when localizing an asset.
///
UseProjectSettings,
///
/// Do not fallback.
///
DontUseFallback,
///
/// Attempts to use a fallback when a localized value is not found.
///
UseFallback
}
///
/// Options for how to handle a missing translation.
///
[Flags]
public enum MissingTranslationBehavior
{
///
/// Includes the missing translation message in the translated string.
///
ShowMissingTranslationMessage = 1,
///
/// Prints the missing translation message using [Debug.LogWarning](https://docs.unity3d.com/ScriptReference/Debug.LogWarning.html).
///
PrintWarning = 2
}
///
/// Options for how to handle asynchronous operations.
///
public enum AsynchronousBehaviour
{
///
/// Use the default behavior specified in the .
///
Default,
///
/// Forces the operation to complete synchronously.
///
ForceSynchronous
}
///
/// Can be assigned to to override the default table loading through Addressables in order to provide a custom table.
///
///
/// This example demonstrates how to use the to provide a custom String Table without using the Addressables system.
/// This approach is particularly useful when you want to allow users to add third-party content, such as modding.
/// The localization data could be loaded from an external file and then converted into a table at runtime.
///
///
///
public interface ITableProvider
{
///
/// Provides a way to return a custom table when when attempting to load from .
///
///
///
///
/// A valid table or , which will trigger the default table loading.
AsyncOperationHandle ProvideTableAsync(string tableCollectionName, Locale locale) where TTable : LocalizationTable;
}
///
/// Gets a notification when a or completes loading.
///
///
/// This example demonstrates how to use the to apply changes to a table after it has loaded but before it has been used.
/// This can be beneficial when you wish to modify or add entries to a table, such as when supporting third-party content, for example modding.
///
///
///
public interface ITablePostprocessor
{
///
/// This could be used to patch a table with updated values.
///
/// The loaded or .
void PostprocessTable(LocalizationTable table);
}
///
/// Provides common functionality for both string and asset table fetching.
///
///
///
[Serializable]
public abstract class LocalizedDatabase : IPreloadRequired, IReset, IDisposable
where TTable : DetailedLocalizationTable
where TEntry : TableEntry
{
///
/// Contains the results of a request. The found entry and the table the entry was found in,
/// this may be different if a fall back occurred.
///
public struct TableEntryResult
{
///
/// The entry that was resolved or if one could not be found.
///
public TEntry Entry { get; }
///
/// The table the entry was extracted from. When is , this contains the last table that was tried.
///
public TTable Table { get; }
internal TableEntryResult(TEntry entry, TTable table)
{
Entry = entry;
Table = table;
}
}
///
/// Preload operation.
/// Loads all tables and their contents(when applicable) marked with the preload label for the selected locale.
///
public AsyncOperationHandle PreloadOperation
{
get
{
#if UNITY_EDITOR
// Don't preload in Editor preview
if (!LocalizationSettings.Instance.IsPlayingOrWillChangePlaymode)
return AddressablesInterface.ResourceManager.CreateCompletedOperation(this, null);
#endif
if (!m_PreloadOperationHandle.IsValid())
{
var operation = PreloadDatabaseOperation.Pool.Get();
operation.Init(this);
m_PreloadOperationHandle = AddressablesInterface.ResourceManager.StartOperation(operation, default);
}
return m_PreloadOperationHandle;
}
}
[SerializeField] TableReference m_DefaultTableReference;
[SerializeReference] ITableProvider m_CustomTableProvider;
[SerializeReference] ITablePostprocessor m_CustomTablePostprocessor;
[SerializeField] AsynchronousBehaviour m_AsynchronousBehaviour;
[SerializeField] bool m_UseFallback;
internal AsyncOperationHandle m_PreloadOperationHandle;
Action m_ReleaseNextFrame;
readonly Action> m_PatchTableContentsAction;
readonly Action> m_RegisterSharedTableAndGuidOperationAction;
readonly Action> m_RegisterCompletedTableOperationAction;
internal Action ReleaseNextFrame => m_ReleaseNextFrame;
// Used in place of the actual selected locale when it is still being loaded.
internal static readonly LocaleIdentifier k_SelectedLocaleId = new LocaleIdentifier("selected locale placeholder");
internal Dictionary<(LocaleIdentifier localeIdentifier, string tableNameOrGuid), AsyncOperationHandle> TableOperations
{
get;
} = new Dictionary<(LocaleIdentifier localeIdentifier, string tableNameOrGuid), AsyncOperationHandle>();
internal Dictionary> SharedTableDataOperations
{
get;
} = new Dictionary>();
///
/// The default table to use when no table collection name is provided.
///
public virtual TableReference DefaultTable
{
get => m_DefaultTableReference;
set => m_DefaultTableReference = value;
}
///
/// Called when attempting to load a table, can be used to override the default table loading through Addressables in order to provide a custom table.
///
///
/// This example demonstrates how to use the to provide a custom String Table without using the Addressables system.
/// This approach is particularly useful when you want to allow users to add third-party content, such as modding.
/// The localization data could be loaded from an external file and then converted into a table at runtime.
///
///
///
public ITableProvider TableProvider
{
get => m_CustomTableProvider;
set => m_CustomTableProvider = value;
}
///
/// Gets a notification when a table completes loading.
/// This can be used to apply changes to a table at runtime, such as updating or creating new entries.
///
///
/// This example demonstrates how to use the to apply changes to a table after it has loaded but before it has been used.
/// This can be beneficial when you wish to modify or add entries to a table, such as when supporting third-party content, for example modding.
///
///
///
public ITablePostprocessor TablePostprocessor
{
get => m_CustomTablePostprocessor;
set => m_CustomTablePostprocessor = value;
}
///
/// Should the fallback Locale be used when a translation could not be found?.
///
public bool UseFallback
{
get => m_UseFallback;
set => m_UseFallback = value;
}
///
/// Options for how to handle asyncronous operations.
///
public AsynchronousBehaviour AsynchronousBehaviour
{
get => m_AsynchronousBehaviour;
set => m_AsynchronousBehaviour = value;
}
///
/// Creates a new instance of the database.
///
public LocalizedDatabase()
{
m_PatchTableContentsAction = PatchTableContents;
m_RegisterSharedTableAndGuidOperationAction = RegisterSharedTableAndGuidOperation;
m_RegisterCompletedTableOperationAction = RegisterCompletedTableOperation;
m_ReleaseNextFrame = LocalizationBehaviour.ReleaseNextFrame;
}
internal TableReference GetDefaultTable()
{
if (m_DefaultTableReference.ReferenceType == TableReference.Type.Empty)
throw new Exception($"Trying to get the DefaultTable however the {GetType().Name} DefaultTable value has not been set. This can be configured in the Localization Settings.");
return m_DefaultTableReference;
}
internal void RegisterCompletedTableOperation(AsyncOperationHandle tableOperation)
{
if (!tableOperation.IsDone)
{
tableOperation.Completed += m_RegisterCompletedTableOperationAction;
return;
}
var table = tableOperation.Result;
if (table == null)
return;
RegisterTableNameOperation(tableOperation, table.LocaleIdentifier, table.TableCollectionName);
// If the table is already present then RegisterTableNameOperation will release the operation which may cause it to become invalid.
if (tableOperation.IsValid())
RegisterSharedTableAndGuidOperation(tableOperation);
}
void RegisterTableNameOperation(AsyncOperationHandle tableOperation, LocaleIdentifier localeIdentifier, string tableName)
{
var key = (localeIdentifier, tableName);
if (TableOperations.ContainsKey(key))
{
// Dont hold onto this.
return;
}
TableOperations[key] = tableOperation;
if (TablePostprocessor != null)
{
// Patch the table contents
if (tableOperation.IsDone)
PatchTableContents(tableOperation);
else
tableOperation.Completed += m_PatchTableContentsAction;
}
}
void RegisterSharedTableAndGuidOperation(AsyncOperationHandle tableOperation)
{
if (!tableOperation.IsDone)
{
tableOperation.Completed += m_RegisterSharedTableAndGuidOperationAction;
return;
}
var table = tableOperation.Result;
if (table == null)
return;
// Register the shared table data Guid.
var tableNameGuid = table.SharedData.TableCollectionNameGuid;
if (!SharedTableDataOperations.ContainsKey(tableNameGuid))
SharedTableDataOperations[tableNameGuid] = AddressablesInterface.ResourceManager.CreateCompletedOperation(table.SharedData, null);
// Register the table via the locale identifier and guid.
var localeAndGuid = (table.LocaleIdentifier, TableReference.StringFromGuid(tableNameGuid));
if (!TableOperations.ContainsKey(localeAndGuid))
{
// We acquire when using the guid.
AddressablesInterface.Acquire(tableOperation);
TableOperations[localeAndGuid] = tableOperation;
}
}
///
/// Returns the Default table.
/// This method is asynchronous and may not have an immediate result.
/// Check [IsDone](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.IsDone) to see if the data is available,
/// if it is false then you can use the [Completed](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event to get a callback when it is finished,
/// yield on the operation or call [WaitForCompletion](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion)
/// to force the operation to complete.
///
///
public AsyncOperationHandle GetDefaultTableAsync()
{
return GetTableAsync(GetDefaultTable());
}
///
/// Returns the named table.
/// This method is asynchronous and may not have an immediate result.
/// Check [IsDone](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.IsDone) to see if the data is available,
/// if it is false then you can use the [Completed](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event to get a callback when it is finished,
/// yield on the operation or call [WaitForCompletion](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion)
/// to force the operation to complete.
///
///
/// Internally the following is performed when a table is requested:
/// 
///
/// The table identifier. Can be either the name of the table or the table collection name Guid.
/// The to load the table from, use null to default to .
///
public virtual AsyncOperationHandle GetTableAsync(TableReference tableReference, Locale locale = null)
{
// Extract the Locale Id or use a placeholder if we are using the selected locale and it is not ready yet.
bool localeAvailable = locale != null || LocalizationSettings.SelectedLocaleAsync.IsDone;
bool useSelectedLocalePlaceholder = true;
if (localeAvailable)
{
if (locale == null)
{
if (LocalizationSettings.SelectedLocaleAsync.Result == null)
return AddressablesInterface.ResourceManager.CreateCompletedOperation(null, "SelectedLocale is null. Database could not get table.");
locale = LocalizationSettings.SelectedLocaleAsync.Result;
}
useSelectedLocalePlaceholder = false;
}
// Do we have a cached operation already running?
tableReference.Validate();
var tableIdString = tableReference.ReferenceType == TableReference.Type.Guid ? TableReference.StringFromGuid(tableReference.TableCollectionNameGuid) : tableReference.TableCollectionName;
var localeId = useSelectedLocalePlaceholder ? k_SelectedLocaleId : locale.Identifier;
if (TableOperations.TryGetValue((localeId, tableIdString), out var operationHandle))
{
// Something has invalidated the handle, possibly caused by an unexpected release. We should remove it and try again.
if (!operationHandle.IsValid())
TableOperations.Remove((localeId, tableIdString));
else
return operationHandle;
}
// Start a new operation
var operation = CreateLoadTableOperation();
operation.Init(this, tableReference, locale);
operation.Dependency = LocalizationSettings.InitializationOperation;
var handle = AddressablesInterface.ResourceManager.StartOperation(operation, LocalizationSettings.InitializationOperation);
if (useSelectedLocalePlaceholder || tableReference.ReferenceType == TableReference.Type.Guid)
{
// When using a Guid we increment the reference count.
// We do not increment for placeholders as we only ever have 1 reference for them, we dont share it between
// table name and guid, because the register operation will use the actual selected locale and not the placeholder.
// We treat the table name as default and do not increment for that one.
if (!useSelectedLocalePlaceholder)
AddressablesInterface.Acquire(handle);
TableOperations[(localeId, tableIdString)] = handle;
}
else
{
// Register the table name and Guid
RegisterTableNameOperation(handle, localeId, tableIdString);
}
// Register the table operation later. This will fully register everything including shared table data, table name and guid.
RegisterCompletedTableOperation(handle);
return handle;
}
///
/// Returns the named table.
/// Uses [WaitForCompletion](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion) to force the loading to complete synchronously.
/// Please note that [WaitForCompletion](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion) is not supported on
/// [WebGL](https://docs.unity3d.com/Packages/com.unity.addressables@latest/index.html?subfolder=/manual/SynchronousAddressables.html#webgl).
///
/// The table identifier. Can be either the name of the table or the table collection name Guid.
/// The to load the table from, use null to default to cref="LocalizationSettings.SelectedLocale"/>.
///
public virtual TTable GetTable(TableReference tableReference, Locale locale = null) => GetTableAsync(tableReference, locale).WaitForCompletion();
///
/// Preloads the selected table. If the table is an its assets will also be loaded.
/// Check [IsDone](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.IsDone) to see if the data is available,
/// if it is false then you can use the [Completed](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event to get a callback when it is finished,
/// yield on the operation or call [WaitForCompletion](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion)
/// to force the operation to complete.
///
/// A reference to the table. A table reference can be either the name of the table or the table collection name Guid.
/// The to use instead of the default
///
public AsyncOperationHandle PreloadTables(TableReference tableReference, Locale locale = null)
{
// Start a new operation
var operation = CreatePreloadTablesOperation();
operation.Init(this, new[] { tableReference }, locale);
operation.Dependency = LocalizationSettings.InitializationOperation;
var handle = AddressablesInterface.ResourceManager.StartOperation(operation, LocalizationSettings.InitializationOperation);
if (LocalizationSettings.Instance.IsPlaying)
handle.CompletedTypeless += ReleaseNextFrame;
return handle;
}
///
/// Preloads the matching tables for the selected Locale. If the tables are then their assets will also be loaded.
/// Check [IsDone](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.IsDone) to see if the data is available,
/// if it is false then you can use the [Completed](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event to get a callback when it is finished,
/// yield on the operation or call [WaitForCompletion](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion)
/// to force the operation to complete.
///
/// An IList of tableReferences to check for the string.
/// The to use instead of the default
///
///
/// This shows how to manually preload tables instead of marking them as Preload in the editor.
///
///
public AsyncOperationHandle PreloadTables(IList tableReferences, Locale locale = null)
{
// Start a new operation
var operation = CreatePreloadTablesOperation();
operation.Init(this, tableReferences, locale);
operation.Dependency = LocalizationSettings.InitializationOperation;
var handle = AddressablesInterface.ResourceManager.StartOperation(operation, LocalizationSettings.InitializationOperation);
if (LocalizationSettings.Instance.IsPlaying)
handle.CompletedTypeless += ReleaseNextFrame;
return handle;
}
///
/// Releases all tables that are currently loaded in the database.
/// This will also release any references to the providing there are no other references to it, such as different Locale versions of the table that have been loaded.
///
/// The to release tables for, when all locales will be released.
public void ReleaseAllTables(Locale locale = null)
{
using (HashSetPool.Get(out var releasedTables))
{
foreach (var to in TableOperations.Values)
{
if (!to.IsValid())
continue;
if (locale != null && to.Result.LocaleIdentifier != locale.Identifier)
continue;
// We may have multiple references to the table so we keep track in order to only call release once.
if (to.Result != null && !releasedTables.Contains(to.Result))
{
ReleaseTableContents(to.Result);
releasedTables.Add(to.Result);
}
AddressablesInterface.Release(to);
}
}
foreach (var shared in SharedTableDataOperations)
{
AddressablesInterface.SafeRelease(shared.Value);
}
SharedTableDataOperations.Clear();
if (m_PreloadOperationHandle.IsValid())
{
//Debug.Assert(m_PreloadOperationHandle.IsDone, "Disposing an incomplete preload operation");
if (m_PreloadOperationHandle.IsDone)
AddressablesInterface.Release(m_PreloadOperationHandle);
m_PreloadOperationHandle = default;
}
TableOperations.Clear();
}
///
/// Releases all references to the table that matches the and .
/// This will also release any references to the providing there are no other references to it, such as different Locale versions of the table that have been loaded.
/// A table is released by calling on it which decrements the ref-count.
/// When a given Asset's ref-count is zero, that Asset is ready to be unloaded.
/// For more information, read the Addressables section [on when memory is cleared](https://docs.unity3d.com/Packages/com.unity.addressables@latest/index.html?subfolder=/manual/MemoryManagement.html).
///
/// A reference to the table. A table reference can be either the name of the table or the table collection name Guid.
/// The Locale version of the table that should be unloaded. When the will be used.
///
/// This shows how to release a table but prevent it from being unloaded.
///
///
public void ReleaseTable(TableReference tableReference, Locale locale = null)
{
tableReference.Validate();
var usingSelectedLocale = locale == LocalizationSettings.SelectedLocaleAsync.Result;
if (locale == null)
{
locale = LocalizationSettings.SelectedLocaleAsync.Result;
usingSelectedLocale = true;
if (locale == null)
return;
}
// Get the shared table data
SharedTableData sharedTableData;
if (tableReference.ReferenceType == TableReference.Type.Guid)
{
if (!SharedTableDataOperations.TryGetValue(tableReference.TableCollectionNameGuid, out var sharedTableDataOperationHandle) || sharedTableDataOperationHandle.Result == null)
return;
sharedTableData = sharedTableDataOperationHandle.Result;
}
else
{
var nameAndLocale = (locale.Identifier, tableReference.TableCollectionName);
if (!TableOperations.TryGetValue(nameAndLocale, out var operationHandleName) || operationHandleName.Result == null)
return;
sharedTableData = operationHandleName.Result.SharedData;
}
if (sharedTableData == null)
return;
// We may have multiple references to the table(Guid, Table name, placeholders etc) so we will iterate through and remove them all.
// We also need to see if the Shared table data is still being used or if we can also release that.
int sharedTableDataUsers = 0;
bool removedContents = false;
using (ListPool<(LocaleIdentifier localeIdentifier, string tableNameOrGuid)>.Get(out var itemsToRemove))
{
foreach (var tableOperation in TableOperations)
{
if (!tableOperation.Value.IsValid() || tableOperation.Value.Result == null || tableOperation.Value.Result.SharedData != sharedTableData)
continue;
// Check locale and placeholder
if (tableOperation.Key.localeIdentifier == locale.Identifier || usingSelectedLocale && tableOperation.Key.localeIdentifier == k_SelectedLocaleId)
{
// We only want to do this once.
if (!removedContents)
{
ReleaseTableContents(tableOperation.Value.Result);
removedContents = true;
}
AddressablesInterface.SafeRelease(tableOperation.Value);
itemsToRemove.Add(tableOperation.Key);
}
else
{
sharedTableDataUsers++;
}
}
// Remove the items from the dictionary
foreach (var tableKey in itemsToRemove)
{
TableOperations.Remove(tableKey);
}
// If there's no other references to the shared table data then we can also remove that.
if (sharedTableDataUsers == 0 && SharedTableDataOperations.TryGetValue(sharedTableData.TableCollectionNameGuid, out var sharedTableDataOperationHandle))
{
AddressablesInterface.SafeRelease(sharedTableDataOperationHandle);
SharedTableDataOperations.Remove(sharedTableData.TableCollectionNameGuid);
}
}
}
///
/// Returns all the tables available.
/// This method is asynchronous and may not have an immediate result.
/// Check [IsDone](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.IsDone) to see if the tables are available.
/// if it is false then you can use the [Completed](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event to get a callback when it is finished,
/// yield on the operation or call [WaitForCompletion](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion)
/// to force the operation to complete.```
///
/// The to load the table from, use null to default to cref="LocalizationSettings.SelectedLocale"/>.
///
public virtual AsyncOperationHandle> GetAllTables(Locale locale = null)
{
var operation = LoadAllTablesOperation.Pool.Get();
operation.Init(this, locale);
operation.Dependency = LocalizationSettings.InitializationOperation;
var handle = AddressablesInterface.ResourceManager.StartOperation(operation, LocalizationSettings.InitializationOperation);
if (LocalizationSettings.Instance.IsPlaying)
handle.CompletedTypeless += ReleaseNextFrame;
return handle;
}
///
/// Checks if the table is currently loaded or not.
///
/// The table identifier. Can be either the name of the table or the table collection name Guid.
/// The to load the table from, use null to default to cref="LocalizationSettings.SelectedLocale"/>.
///
public virtual bool IsTableLoaded(TableReference tableReference, Locale locale = null)
{
var tableIdString = tableReference.ReferenceType == TableReference.Type.Guid ? TableReference.StringFromGuid(tableReference.TableCollectionNameGuid) : tableReference.TableCollectionName;
var localeAndName = locale != null ? (locale.Identifier, tableIdString) : (LocalizationSettings.SelectedLocaleAsync.Result.Identifier, tableIdString);
if (TableOperations.TryGetValue(localeAndName, out var TableOperationHandle))
return TableOperationHandle.Status == AsyncOperationStatus.Succeeded;
else
return false;
}
internal virtual LoadTableOperation CreateLoadTableOperation() => LoadTableOperation.Pool.Get();
internal virtual PreloadTablesOperation CreatePreloadTablesOperation() => PreloadTablesOperation.Pool.Get();
///
/// Returns the entry from the requested table. A table entry will contain the localized item and metadata.
/// This method is asynchronous and may not have an immediate result.
/// Check [IsDone](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.IsDone) to see if the data is available,
/// if it is false then you can use the [Completed](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.Completed) event to get a callback when it is finished,
/// yield on the operation or call [WaitForCompletion](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion)
/// to force the operation to complete.
/// Once the Completed event has been called, during the next update, the internal operation will be returned to a pool so that it can be reused.
/// If you do plan to keep hold of the handle after completion then you should call [Acquire](xref::UnityEngine.ResourceManagement.AsyncOperationHandle.Acquire)
/// to prevent the operation being reused and to finally return the operation back to the pool.
///
///
/// Internally the following is performed when an Entry is requested.
/// First the table will be requested using .
/// Once the table is loaded the entry will be extracted like so:
/// 
///
/// The table identifier. Can be either the name of the table or the table collection name Guid.
/// A reference to the entry in the table.
/// The to load the table from. Null will use .
/// A Enum which determines if a Fallback should be used when no value could be found for the Locale.
///
public virtual AsyncOperationHandle GetTableEntryAsync(TableReference tableReference, TableEntryReference tableEntryReference, Locale locale = null, FallbackBehavior fallbackBehavior = FallbackBehavior.UseProjectSettings)
{
var loadTableOperation = GetTableAsync(tableReference, locale);
var getTableEntryOperation = GetTableEntryOperation.Pool.Get();
var useFallback = fallbackBehavior != FallbackBehavior.UseProjectSettings ? fallbackBehavior == FallbackBehavior.UseFallback : UseFallback;
getTableEntryOperation.Init(this, loadTableOperation, tableReference, tableEntryReference, locale, useFallback, true);
getTableEntryOperation.Dependency = loadTableOperation;
var handle = AddressablesInterface.ResourceManager.StartOperation(getTableEntryOperation, loadTableOperation);
return handle;
}
///
/// Returns the entry from the requested table. A table entry will contain the localized item and metadata.
/// Uses [WaitForCompletion](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion) to force the loading to complete synchronously.
/// Please note that [WaitForCompletion](xref:UnityEngine.ResourceManagement.AsyncOperations.AsyncOperationHandle.WaitForCompletion) is not supported on
/// [WebGL](https://docs.unity3d.com/Packages/com.unity.addressables@latest/index.html?subfolder=/manual/SynchronousAddressables.html#webgl).
///
/// The table identifier. Can be either the name of the table or the table collection name Guid.
/// A reference to the entry in the table.
/// The to load the table from. Null will use .
/// A Enum which determines if a Fallback should be used when no value could be found for the Locale.
/// The table entry result which contains the table
public virtual TableEntryResult GetTableEntry(TableReference tableReference, TableEntryReference tableEntryReference, Locale locale = null, FallbackBehavior fallbackBehavior = FallbackBehavior.UseProjectSettings)
{
return GetTableEntryAsync(tableReference, tableEntryReference, locale, fallbackBehavior).WaitForCompletion();
}
internal AsyncOperationHandle GetSharedTableData(Guid tableNameGuid)
{
if (SharedTableDataOperations.TryGetValue(tableNameGuid, out var sharedTableDataOp))
return sharedTableDataOp;
sharedTableDataOp = AddressablesInterface.LoadAssetFromGUID(TableReference.StringFromGuid(tableNameGuid));
SharedTableDataOperations[tableNameGuid] = sharedTableDataOp;
return sharedTableDataOp;
}
internal virtual void ReleaseTableContents(TTable table) {}
///
/// Called before the LocaleChanged event is sent out in order to give the database a chance to prepare.
///
///
public virtual void OnLocaleChanged(Locale locale)
{
ReleaseAllTables();
}
void PatchTableContents(AsyncOperationHandle tableOperation)
{
// This should only be called once, after the table has loaded. It gives users the opurtunity to patch a Localized table.
// For example you may want to read in some extra data from a csv file after the game has been built.
if (TablePostprocessor != null && tableOperation.Result != null)
TablePostprocessor.PostprocessTable(tableOperation.Result);
}
///
/// Resets the state of the provider by removing all the cached tables and clearing the preload operation.
///
public void ResetState()
{
ReleaseAllTables();
}
///
/// Calls ..
///
void IDisposable.Dispose()
{
ReleaseAllTables();
}
}
}