Most users will not need to understand GHUD's internal systems to use it effectively. This section covers some of the underlying structures and processes that support GHUD, including how generated data is stored, how JSON data is converted into usable types, and how resources are managed in memory.
These topics are useful when troubleshooting, optimizing a project, or modifying GHUD beyond its standard configuration.
GHUD receives tab data from the Google Sheets API as JSON.
Internally, GHUD uses the included SimpleJSON library to parse the response.
Each data row is first stored as column names paired with string values.
When GHUD builds the generated tab data, those strings are converted into the types defined by Row 2 of the Google Sheet.
GHUD's DB_Tab class provides conversion methods including:
GetBool
GetByte
GetInt
GetFloat
GetString
GetEnum
Generated tab loaders use these methods when filling the typed arrays exposed through the tab API.
If a value cannot be converted to its expected type,
GHUD reports the invalid cell in the Unity Console and returns the type's fallback value.
Type Conversion Methods
DB_Tab stores imported cell values as strings.
The generated tab loaders call the appropriate method below to convert each string into the type defined for that column.
This conversion happens during GHUD's ~ Data Loading ~ methods.
Because these conversions happen while GHUD loads the data, normal runtime references are efficient typed-array lookups, with Row enums cast to integer indices.
Here we go into more detail for how each of DB_Tab's Get methods work:
GetString(row, column)
Returns the cell value as a string without additional conversion.
If the requested row or column does not exist, it logs an error and returns an empty string: ""
GetFloat(row, column)
Attempts to parse the cell as a float.
An empty cell returns 0 without logging an error.
If a non-empty value cannot be parsed as a float, it logs a conversion error and returns 0.
GetBool(row, column)
First attempts to parse the value as a C# boolean, so TRUE and FALSE are handled normally.
If that fails, GHUD attempts to parse the value as a number: x > 0 โ TRUE; x <= 0 โ FALSE
An empty cell returns FALSE without logging an error.
If the value is not empty and can't be parsed as a boolean or as a number, it returns FALSE along with an error log.
GetInt(row, column)
Attempts to parse the cell as an int.
An empty cell returns: 0.
If a non-empty value cannot be parsed as an int, it logs a conversion error and returns: 0.
Fractional values such as 5.5 log an error and are truncated, returning an integer truncated towards 0; 5 in the case of 5.5.
GetByte(row, column)
Uses GetInt to read the value, then casts the resulting integer to a byte.
This means it inherits GetInt's fallback of 0 for empty or invalid integer values.
Values outside 0โ255 wrap according to unchecked C# byte conversion, effectively modulo 256.
Fractional values such as -5.5 log an error and are truncated, returning the nearest integer towards 0; 251 in the case of -5.5.
GetEnum(enumType, row, column)
Attempts to parse the cell as a value of the supplied enum type.
An empty cell returns the enum's numeric 0 value without logging an error ('None' by default in the GHUD System).
A valid enum member name returns that member's underlying numeric value.
Enum cells that contain int values in place of string names will still be converted into the corresponding enum if it exists.
If a non-empty value cannot be converted to the requested enum, it logs an error and returns the enum's numeric 0 value.
Note that enum names are case-sensitive, and the expectation is for enum entries to be PascalCase.
Relevant Scripts
Assets/GHUDatabase/GHUDScripts/Loaders/DB_Tab.cs
Fetches the Google Sheets JSON response, passes it through SimpleJSON, stores the imported rows and columns, and provides GetString, GetBool, GetInt, GetByte, GetFloat, and GetEnum.
Assets/GHUDatabase/GHUDScripts/SimpleJSON/SimpleJSON.cs
Third-party JSON parser used by DB_Tab to parse the Google Sheets API response.
SimpleJSON is packaged with GHUD, but the original library can be found here:
https://github.com/Bunny83/SimpleJSON
Assets/GHUDatabase/GHUDScripts/Loaders/TabLoader.cs
Generates the per-tab scripts,
including loader code that allocates serialized typed arrays and fills them using the appropriate DB_Tab conversion methods.
Assets/GHUDatabase/GHUDScripts/Tabs/[TabName].cs
The generated result for each tab. These scripts contain the serialized typed arrays for each column
and the actual calls to the DB_Tab Get methods to load those serialized column arrays.
GHUD creates a DB_Tab ScriptableObject for each Google Sheets tab.
These generated assets are stored in:
Assets/GHUDatabase/Assets/
Each file is named:
[TabName]_Tab.asset
For example:
Assets/GHUDatabase/Assets/Abilities_Tab.asset
These asset files are not included in game builds, but the tab scripts generated from them are.
A DB_Tab SO stores the imported tab data in a generic form.
Each data row is represented by a RowEntry, which contains a list of ColumnValue entries.
Each ColumnValue stores the column name and its imported cell value as strings.
This allows GHUD to preserve the imported sheet data as it prepares to generate the strongly typed arrays in the tab classes.
The full data pipeline looks like this:
Google Sheets โ JSON โ DB_Tab ScriptableObject โ typed DataTab prefab arrays โ runtime tab API
When GHUD updates a tab, DB_Tab_Generator loads the existing [TabName]_Tab.asset, or creates one if it does not exist. DB_Tab then retrieves and stores the current sheet values and uses that data to update the generated DataTab prefab,
which is a GameObject with the generated [TabName].cs attached as a component.
The generated DataTab prefab is what provides the serialized typed arrays and their accessors.
The DB_Tab therefore acts as the general-purpose imported data container,
while the generated DataTab represents that data in the types and structure used by the project at runtime.
ย Inspecting the Data
You can inspect a generated DB_Tab directly in Unity by selecting its .asset file and expanding Tab in the Inspector.
For large tabs, inspecting the ScriptableObject directly is often slower and less convenient. The GHUD Preview Scene provides a more readable way to inspect the same imported tab data.
These ScriptableObjects are generated GHUD data. Their imported values should not be edited manually. Edit the Google Sheets values instead.
One unique advantage of examining these assets is access to the Load checkbox, the top serialized variable. Clicking it updates only the selected tab with its current data from Google Sheets. This should only be used when the Column A row identifiers and their order, the column names, and column types must all be unchanged from the last full update.ย
You can also find SOs here for GHUD's helper tabs in Google Sheets. You should never need to edit these manually, but a brief description of their roles in the GHUD system can be found below.
Relevant Scripts
Assets/GHUDatabase/GHUDScripts/Loaders/DB_Tab.cs
Defines the DB_Tab ScriptableObject and its Tab, RowEntry, and ColumnValue data structures. It also retrieves Google Sheets data, parses the JSON response, stores imported cell values, and provides the type-conversion methods discussed above.
Assets/GHUDatabase/GHUDScripts/Loaders/DB_Tab_Generator.cs
Creates or finds each [TabName]_Tab.asset,
associates it with its generated DataTab prefab, and updates its data during GHUD data-loading operations.
Assets/GHUDatabase/GHUDScripts/Loaders/TabData.cs
Base class for the generated DataTab prefabs.
It receives a DB_Tab and invokes the generated loader that converts its string data into serialized typed arrays.
Assets/GHUDatabase/GHUDScripts/Tabs/[TabName].cs
Generated tab class containing the final typed arrays and static runtime accessors for that tab.
ย Helper Tab Scriptable Objects
GHUD also creates several DB_Tab ScriptableObjects for its hidden helper tabs.
These contain code and structural information generated by formulas in the GHUD Google Sheets template.
They are used during GHUD's code-generation process and should not normally be edited manually.
EnumsLoader_Tab.asset
Stores the generated contents of the EnumsLoader Sheet tab.
EnumsLoader.cs reads its RowCount and Enums values to generate the project's GHUD enums in:
Assets/GHUDatabase/GHUDScripts/Enums/Enums.cs
The same data is also used when GHUD regenerates the _Tabs.cs tab-access class.
TLAllocate_Tab.asset
Contains the generated field declarations and static accessors for each column.
For example, it can contain code like this:
[SerializeField] int[] _damage;
public static int Damage(EAbility row)
{
ย ย return Instance._damage[(int)row];
}
It also provides structural information such as the number of generated columns and the row enum type used by each tab.
TLArrays_Tab.asset
Contains the generated code used to allocate the typed arrays when a DataTab is loaded.
For example:
_damage = new int[_rowCount];
_range = new float[_rowCount];
It also loads a protected utility variable in the TabData for referencing the number of rows in the tab.
_rowCount = (int)EAbility.COUNT;
TLGet_Tab.asset
Contains the generated assignments that convert the imported DB_Tab string values and place them into those typed arrays.
For example:
_damage[i] = tab.GetInt(i, "Damage");
_range[i] = tab.GetFloat(i, "Range");
Each of the above helper ScriptableObjects contain code generated in Google Sheets specifically for the tabs in your project.
Unless you are Expanding the Size Limitations of your Google Sheets,
you should never need to edit these tabs in Google Sheets, and you should never need to edit their ScriptableObjects manually.
Relevant Scripts
Assets/GHUDatabase/GHUDScripts/Loaders/EnumsLoader.cs
Uses EnumsLoader_Tab.asset to generate GHUD enum and tab-access code.
Assets/GHUDatabase/GHUDScripts/Loaders/TabLoader.cs
Combines TLAllocate, TLArrays, and TLGet to generate each typed tab class.
Assets/GHUDatabase/GHUDScripts/Application/GrandHawkUnionDatabase.cs
Coordinates loading and updating the helper DB_Tab assets during GHUD data-loading operations.
GHUD's generated asset loaders use Unity's Resources system to load row-associated assets at runtime.
Asset paths are stored on the generated DataTab prefabs,
but the actual Unity assets are not loaded merely because the DataTab exists.
They are loaded when they are first requested through an asset accessor such as:
Items.Sprite(EItem.Coin), or
Characters.Prefab(ECharacter.Hero), or
Abilities.AudioClip(EAbility.Fire0)
Once loaded, the asset is cached so later requests can return the existing reference instead of loading it again from resources.
The Asset Memory Manager
All generated asset-loader caches are managed globally by:
Assets/GHUDatabase/Resources/GHUD/System/AssetMemoryManager.prefab
It uses a Least Recently Used, or LRU, cache.
Each time a cached asset is requested, it is marked as recently used.
If the cache becomes too large, GHUD begins removing the least recently used cached references first.
The manager tracks two project-wide limits across all GHUD asset loaders:
_maxTrackedAssets (Default 256)
Limits the number of cached assets regardless of their size.
_maxTrackedAssetMemoryMB (Default 512)
Limits the total estimated memory used by cached assets.
GHUD estimates an asset's size using Unity's runtime memory-size reporting when the asset first enters the cache. Because Unity's reported size can vary by asset, platform, and build, this setting should be considered a rough cache budget,
not a guaranteed limit on the application's total RAM usage; which is why there is also a count limit with _maxTrackedAssets.
Flush To Percentย
When either hard limit is exceeded, the AssetMemoryManager does not simply remove one asset and stop.
Instead, it removes least recently used cache entries until both tracked values are at or below a percentage of their limits.
This percentage is controlled by: _flushToPercent (Default 0.6)
With the default settings, exceeding the 256-entry limit causes GHUD to work back toward 153 cached entries.
Likewise, exceeding the 512 MB tracked-memory limit causes it to work back toward approximately 307 MB.
This extra headroom prevents the AssetMemoryManager from having to perform another eviction every time a single new asset pushes the cache slightly over its limit.
One exception is that the AssetMemoryManager will not evict the final remaining cache entry. (The asset just loaded)
A single asset larger than the configured memory limit may therefore remain cached by itself until a different asset is loaded.
When Flushing Happens
By default the AssetMemoryManager waits for a scene change to flush cached assets, and evicts them during that transition.
This helps avoid potentially expensive asset-unloading work during active gameplay.
The serialized bool _waitForSceneChangeToFlushAssets on the AssetMemoryManager which is true by default,
offers the option to flush assets immediately upon exceeding either asset limit, by setting it to false.
This might be necessary for open-world games, or any game where many assets are loaded from a single scene.
Either way, after cache entries are evicted, the AssetMemoryManager requests: Resources.UnloadUnusedAssets()
What Eviction Actually Does
Evicting assets from the AssetMemoryManager's cache does not forcibly destroy or unload assets the game is still using.
Instead, the AssetMemoryManager removes its own cached reference to that asset.
Unity then decides whether the asset is actually unused when Resources.UnloadUnusedAssets() runs.
Configuring the AssetMemoryManager Cache
You can select the AssetMemoryManager prefab directly from the GHUD Window.
Open: Tools > GHUD > Window
Then click the: ~ Asset Loading ~ section heading.
GHUD highlights: Assets/GHUDatabase/Resources/GHUD/System/AssetMemoryManager.prefab
Custom Asset Loaders
Generated GHUD asset loaders (Assets/GHUDatabase/UserScripts/Partials/[TabName]_Assets.cs)
automatically report their cached assets to the AssetMemoryManager.
If you add custom asset-loading behavior with your own runtime asset arrays,
those arrays should use the same memory tracking.
After storing a loaded asset in an array, and whenever returning an existing cached asset, call:
NotifyCachedAssetUsed(loadedAssets, index);
Before discarding or replacing a tracked asset array, call:
UntrackCachedAssetArray(loadedAssets);
Do not resize a tracked array in place.
Untrack it first, then replace it with a new array so cached references cannot remain outside the global memory management.
Custom loaders do not need to manage cache IDs themselves.
TabData assigns the tracking IDs and communicates with the AssetMemoryManager.
Relevant Scripts
Assets/GHUDatabase/GHUDScripts/Loaders/AssetMemoryManager.cs
Implements GHUD's global LRU asset cache, including the cached-entry and approximate-memory limits, eviction order, delayed scene-change flushing, and requests to Resources.UnloadUnusedAssets().
Assets/GHUDatabase/GHUDScripts/Loaders/TabData.cs
Provides NotifyCachedAssetUsed and UntrackCachedAssetArray.
It tracks each cached array entry, and clears an entry when the AssetMemoryManager evicts it.
Assets/GHUDatabase/UserScripts/Partials/[TabName]_Assets.cs
Generated per-tab asset-loader code.
These scripts load row-associated assets from Resources, cache them for reuse,
and notify the global memory manager when cached assets are used.
Assets/GHUDatabase/GHUDScripts/Tabs/[TabName].cs
Generated tab class containing the final typed arrays and static runtime accessors for that tab.