Class UITKLabelMaker
Manages a pool of reusable UITKWorldLabel instances for efficient world-anchored text, drawn by UITKWorldLabelLayer.
[DisallowMultipleComponent]
public sealed class UITKLabelMaker : MonoBehaviour
- Inheritance
-
ObjectComponentBehaviourMonoBehaviourUITKLabelMaker
- Inherited Members
-
MonoBehaviour.IsInvoking()MonoBehaviour.CancelInvoke()MonoBehaviour.StopCoroutine(Coroutine)MonoBehaviour.StopAllCoroutines()MonoBehaviour.destroyCancellationTokenMonoBehaviour.useGUILayoutMonoBehaviour.didStartMonoBehaviour.didAwakeMonoBehaviour.runInEditModeBehaviour.enabledBehaviour.isActiveAndEnabledComponent.GetComponent<T>()Component.TryGetComponent<T>(out T)Component.GetComponentInChildren<T>()Component.GetComponentsInChildren<T>()Component.GetComponentInParent<T>()Component.GetComponentsInParent<T>()Component.GetComponents<T>()Component.GetComponentIndex()Component.CompareTag(TagHandle)Component.transformComponent.transformHandleComponent.gameObjectComponent.tagObject.GetEntityId()Object.GetInstanceID()Object.GetHashCode()Object.InstantiateAsync<T>(T)Object.InstantiateAsync<T>(T, Transform)Object.InstantiateAsync<T>(T, Vector3, Quaternion)Object.InstantiateAsync<T>(T, Transform, Vector3, Quaternion)Object.Instantiate(Object, Vector3, Quaternion)Object.Instantiate(Object, Vector3, Quaternion, Transform)Object.Instantiate(Object)Object.Instantiate(Object, Scene)Object.Instantiate<T>(T, InstantiateParameters)Object.Instantiate<T>(T, Vector3, Quaternion, InstantiateParameters)Object.Instantiate(Object, Transform)Object.Instantiate<T>(T)Object.Instantiate<T>(T, Vector3, Quaternion)Object.Instantiate<T>(T, Vector3, Quaternion, Transform)Object.Instantiate<T>(T, Transform)Object.Destroy(Object)Object.DestroyImmediate(Object)Object.DontDestroyOnLoad(Object)Object.DestroyObject(Object)Object.FindObjectsOfType<T>()Object.FindObjectsByType<T>(FindObjectsSortMode)Object.FindObjectsByType<T>(FindObjectsInactive, FindObjectsSortMode)Object.FindObjectOfType<T>()Object.FindFirstObjectByType<T>()Object.FindAnyObjectByType<T>()Object.FindFirstObjectByType<T>(FindObjectsInactive)Object.FindAnyObjectByType<T>(FindObjectsInactive)Object.FindObjectsByType<T>()Object.FindObjectsByType<T>(FindObjectsInactive)Object.ToString()Object.nameObject.hideFlags
Remarks
The UI Toolkit successor to LabelMaker. The pooling contract is unchanged — the same
Dequeue/Enqueue/Display3D/Cache surface, so combat display and target frame code carries
over with only the type names swapped.
What changed is that a pooled label no longer needs a prefab. The old one carried a
TextMeshPro component, a MeshRenderer and a material, so it had to be authored as an asset;
a label is now a transform plus two plain components, which this builds on demand. That
removes the "labels silently do nothing because the prefab reference was lost" failure the
old pool had, and takes Cached3DLabel.prefab out of the project with it.
The budget. The pool used to be bounded and nothing else was: the cap only limited how many idle labels were kept, and Dequeue(out UITKWorldLabel, bool) built a new GameObject whenever the pool ran dry. Nothing bounded how many labels could be live at once or how fast they could be created, so a large area-of-effect hit — or a server sending combat events faster than a client can draw them — allocated GameObjects without limit until the client stalled. That is reachable from the network, so it is a denial of service and not merely a performance note.
Two limits close it. FishMMO.Client.UITKLabelMaker.maxLiveLabels caps how many labels exist at once;
past the cap the oldest auto-expiring label is recycled instead of a new one being built,
which for damage numbers is also the behaviour a player wants — the newest hit is the one
worth reading. FishMMO.Client.UITKLabelMaker.maxSpawnsPerSecond is a token bucket that caps the rate, so a
burst that would churn the whole cap in one frame is dropped rather than served. Labels the
caller holds itself (manualCache, used by nameplates and the target frame) are never
recycled out from under it.
The draw half of the budget lives in UITKWorldLabelLayer; both are needed, because capping the draw alone still leaves the GameObjects allocated.
Methods
Cache(UITKWorldLabel)
Returns the given label to the pool for reuse.
public static void Cache(UITKWorldLabel label)
Parameters
labelUITKWorldLabelThe label to cache.
Clear()
Clears all cached labels from the pool.
public static void Clear()
ClearCache()
Clears all cached labels from the pool and destroys their game objects.
public void ClearCache()
Remarks
Live labels are released first. Leaving them out would strand every label currently on screen: nothing else holds them, so they would tick forever against a pool that no longer knows about them.
Dequeue(out UITKWorldLabel, bool)
Retrieves a label from the pool, recycles the oldest timed label when the live cap is reached, or builds a new one.
public bool Dequeue(out UITKWorldLabel label, bool persistent = false)
Parameters
labelUITKWorldLabelThe dequeued, recycled or newly created label.
persistentboolTrue for a label the caller will hold and cache itself. Persistent labels bypass the rate limit, because the budget exists to bound transient combat spam and a nameplate that silently fails to appear because a damage burst exhausted the bucket is a worse outcome than the spam it was protecting against. They are still subject to the live cap.
Returns
- bool
True if a label is provided, false when the budget refuses one.
Remarks
Returning false is a normal outcome, not an error: it is how the rate limit and the live cap are enforced, and Display3D(string, Vector3, Color, float, float, bool, int) turns it into a dropped label rather than a stall.
Display3D(string, Vector3, Color, float, float, bool, int)
Displays a world-anchored label at the specified position with the given properties.
public static UITKWorldLabel Display3D(string text, Vector3 position, Color color, float fontSize, float persistTime, bool manualCache, int effectFlags = 0)
Parameters
textstringText to display.
positionVector3World position for the label.
colorColorText color.
fontSizefloatFont size in world units, scaled by distance at render time.
persistTimefloatDuration in seconds before the label is automatically cached. Ignored if manualCache is true.
manualCacheboolIf true, the label must be cached manually via Cache(UITKWorldLabel).
effectFlagsintBit-flag field of LabelEffect values. 0 for no effects.
Returns
- UITKWorldLabel
The displayed label, or null if the instance is unavailable or the budget refused one.
Enqueue(UITKWorldLabel)
Returns a label to the pool for reuse, or destroys it if the pool has reached maximum capacity.
public void Enqueue(UITKWorldLabel label)
Parameters
labelUITKWorldLabelThe label to enqueue.
Remarks
Re-entrant by design. The old version enqueued unconditionally, so a label that was cached twice — trivially reachable, because the expiry path cached it and a caller holding the same reference could cache it again — sat in the pool twice and was then handed to two different callers at once, each overwriting the other's text. The pooled flag on the label makes the second call a no-op.