com.wallstop-studios.unity-helpers
Version:
Treasure chest of Unity developer tools
1 lines • 1.04 MB
JSON
{"config":{"lang":["en"],"separator":"[\\s\\-,:!=\\[\\]()\"/]+|(?!\\b)(?=[A-Z][a-z])|\\.(?!\\d)|&[lg]t;","pipeline":["stopWordFilter"],"fields":{"title":{"boost":1000.0},"text":{"boost":1.0},"tags":{"boost":1000000.0}}},"docs":[{"location":"","title":"Unity Helpers","text":"<p>Utilities tested in commercial releases</p> <p>Unity Helpers reduces repetitive work with utilities tested in commercial releases. Benchmarks demonstrate 10-15x faster random generation compared to Unity.Random and significant speedups for common reflection operations. From auto-wiring components to fast spatial queries, this toolkit provides common utilities for Unity development.</p>"},{"location":"#quick-install","title":"Quick Install","text":"OpenUPM (Recommended)Git URLNPM RegistrySource Bash<pre><code>openupm add com.wallstop-studios.unity-helpers\n</code></pre> <p>In Unity Package Manager, click Add package from git URL and enter:</p> Text Only<pre><code>https://github.com/wallstop/unity-helpers.git\n</code></pre> <p>Add scoped registry in <code>manifest.json</code>:</p> JSON<pre><code>{\n \"scopedRegistries\": [\n {\n \"name\": \"npm\",\n \"url\": \"https://registry.npmjs.org\",\n \"scopes\": [\"com.wallstop-studios\"]\n }\n ],\n \"dependencies\": {\n \"com.wallstop-studios.unity-helpers\": \"3.0.0\"\n }\n}\n</code></pre> <p>Download the latest release <code>.unitypackage</code> or clone the repository.</p>"},{"location":"#what-makes-this-different","title":"What Makes This Different","text":""},{"location":"#inspector-tooling","title":"Inspector Tooling","text":"<p>Grouping, buttons, conditional display, toggle grids for Unity inspectors, free and open source.</p> <p>Learn more </p>"},{"location":"#10-15x-faster-random","title":"10-15x Faster Random","text":"<p><code>PRNG.Instance</code> provides high-performance random generation with API including weighted selection, Gaussian distribution, and Perlin noise.</p> <p>Learn more </p>"},{"location":"#zero-boilerplate-component-wiring","title":"Zero-Boilerplate Component Wiring","text":"<p>Auto-wire components with attributes like <code>[SiblingComponent]</code>, <code>[ParentComponent]</code>, and <code>[ChildComponent]</code>. Works with DI containers.</p> <p>Learn more </p>"},{"location":"#data-driven-effects-system","title":"Data-Driven Effects System","text":"<p>Designer-friendly buffs and debuffs as ScriptableObjects. Add new effects via data instead of code changes.</p> <p>Learn more </p>"},{"location":"#olog-n-spatial-queries","title":"O(log n) Spatial Queries","text":"<p>QuadTree, KdTree, RTree, OctTree, and SpatialHash for 2D and 3D. Efficient spatial queries without linear iteration.</p> <p>Learn more </p>"},{"location":"#20-editor-tools","title":"20+ Editor Tools","text":"<p>Automate sprite, animation, texture, and prefab workflows. Reduces manual repetitive tasks.</p> <p>Learn more </p>"},{"location":"#first-time-here","title":"First Time Here?","text":"<p>Pick your starting point based on your biggest pain point:</p> Your Problem Your Solution Time to Value Writing custom editors Inspector Tooling - Inspector attributes, free ~2 minutes Writing <code>GetComponent</code> everywhere Relational Components - Auto-wire with attributes ~2 minutes Need buffs/debuffs system Effects System - Designer-friendly ScriptableObjects ~5 minutes Slow spatial searches Spatial Trees - O(log n) queries ~5 minutes Random is too slow/limited Random Generators - 10-15x faster with weighted selection, Gaussian, Perlin noise ~1 minute Need save/load system Serialization - Unity types supported ~10 minutes Manual sprite workflows Editor Tools - 20+ automation tools ~3 minutes <p>Not sure where to start?</p> <p>The Getting Started Guide walks through the top 3 features in 5 minutes.</p>"},{"location":"#quick-examples","title":"Quick Examples","text":""},{"location":"#auto-wire-components","title":"Auto-Wire Components","text":"Player.cs<pre><code>using UnityEngine;\nusing WallstopStudios.UnityHelpers.Core.Attributes;\n\npublic class Player : MonoBehaviour\n{\n // Auto-finds on same GameObject\n [SiblingComponent] private SpriteRenderer spriteRenderer;\n\n // Auto-finds in parent hierarchy\n [ParentComponent] private Rigidbody2D rigidbody;\n\n // Auto-finds all in children\n [ChildComponent] private Collider2D[] childColliders;\n\n void Awake()\n {\n this.AssignRelationalComponents(); // One call wires all marked fields\n }\n}\n</code></pre>"},{"location":"#fast-random-generation","title":"Fast Random Generation","text":"LootDrop.cs<pre><code>using WallstopStudios.UnityHelpers.Core.Random;\nusing WallstopStudios.UnityHelpers.Core.Extension;\n\npublic class LootDrop : MonoBehaviour\n{\n void Start()\n {\n // 10-15x faster than UnityEngine.Random\n IRandom rng = PRNG.Instance;\n\n // Basic usage\n int damage = rng.Next(10, 20);\n float chance = rng.NextFloat();\n\n // Weighted random selection\n string[] loot = { \"Common\", \"Rare\", \"Epic\", \"Legendary\" };\n float[] weights = { 0.6f, 0.25f, 0.10f, 0.05f };\n int index = rng.NextWeightedIndex(weights);\n Debug.Log($\"Dropped: {loot[index]}\");\n }\n}\n</code></pre>"},{"location":"#inspector-attributes","title":"Inspector Attributes","text":"CharacterStats.cs<pre><code>using UnityEngine;\nusing WallstopStudios.UnityHelpers.Core.Attributes;\n\npublic class CharacterStats : MonoBehaviour\n{\n [WGroup(\"combat\", \"Combat Stats\", collapsible: true)]\n public float maxHealth = 100f;\n [WGroupEnd(\"combat\")]\n public float defense = 10f;\n\n public enum WeaponType { Melee, Ranged, Magic }\n public WeaponType weaponType;\n\n [WShowIf(nameof(weaponType), WShowIfComparison.Equal, WeaponType.Ranged)]\n public int ammoCapacity = 30;\n\n [WButton(\"Heal to Full\", groupName: \"Debug\")]\n private void HealToFull() { maxHealth = 100f; }\n}\n</code></pre>"},{"location":"#production-ready","title":"Production Ready","text":""},{"location":"#8000-tests","title":"8,000+ Tests","text":"<p>8,000+ automated tests.</p>"},{"location":"#shipped-in-commercial-games","title":"Shipped in Commercial Games","text":"<p>Used in commercial game releases.</p>"},{"location":"#il2cpp-webgl-compatible","title":"IL2CPP & WebGL Compatible","text":"<p>Compatible with IL2CPP and WebGL. Includes optimizations for AOT compilation.</p>"},{"location":"#schema-evolution","title":"Schema Evolution","text":"<p>Forward and backward compatible serialization \u2014 add new fields without breaking existing saves.</p>"},{"location":"#documentation","title":"Documentation","text":"<ul> <li>Getting Started - Quick start guide (5 minutes)</li> <li>Feature Index - Alphabetical reference of all features</li> <li>Glossary - Term definitions</li> <li>Roadmap - Upcoming features and priorities</li> </ul>"},{"location":"#features","title":"Features","text":"<ul> <li>Inspector Tooling - Attributes, buttons, validation</li> <li>Relational Components - Auto-wire with attributes</li> <li>Effects System - Data-driven buffs/debuffs</li> <li>Spatial Trees - Fast spatial queries</li> <li>Serialization - JSON and Protobuf with Unity types</li> <li>Data Structures - Heaps, tries, and more</li> <li>Random Generators - High-performance PRNGs</li> <li>Editor Tools - Sprite, animation, texture automation</li> </ul>"},{"location":"#performance","title":"Performance","text":"<ul> <li>Random Performance</li> <li>Spatial Tree 2D Performance</li> <li>Spatial Tree 3D Performance</li> <li>Relational Components Performance</li> </ul>"},{"location":"#license","title":"License","text":"<p>Unity Helpers is released under the MIT License. Use it freely in commercial and personal projects.</p> <p>Ready to get started?</p> <p>Getting Started Guide View on GitHub</p>"},{"location":"404/","title":"Page Not Found","text":"<p>The page you're looking for doesn't exist or has been moved.</p>"},{"location":"404/#what-can-you-do","title":"What can you do?","text":"<ul> <li>Use the search in the header to find what you're looking for</li> <li>Go back to the home page</li> <li>Check out the Getting Started guide</li> <li>Browse the Features documentation</li> </ul> <p>If you believe this is an error, please open an issue.</p>"},{"location":"readme/","title":"Unity Helpers","text":"<p>\ud83e\udd16 AI Assistance Disclosure:</p> <p>Recent versions of this project have utilized AI assistance for feature development, bug detection, performance optimization, and documentation.</p> <p>The original codebase was developed entirely by humans over several years.</p> <p> </p> <p>Reduces boilerplate code for common Unity patterns.</p> <p>Unity Helpers reduces repetitive work with tested utilities. Benchmarks show 10-15x faster random generation than Unity.Random and significant speedups for common reflection operations (see performance docs). From auto-wiring components to efficient spatial queries, this toolkit provides tools for Unity development.</p>"},{"location":"readme/#quick-install","title":"\ud83d\udce6 Quick Install","text":"Source Install Method OpenUPM (Recommended) <code>openupm add com.wallstop-studios.unity-helpers</code> Git URL Package Manager \u2192 Add from git URL \u2192 <code>https://github.com/wallstop/unity-helpers.git</code> NPM Add scoped registry <code>https://registry.npmjs.org</code> \u2192 search <code>com.wallstop-studios.unity-helpers</code> Source Import <code>.unitypackage</code> or clone repo <p>\ud83d\udc49 Full installation instructions with step-by-step guides for each method.</p> <p>Key Features:</p> <ul> <li>\ud83c\udfa8 Inspector tooling - Grouping, buttons, conditional display, toggle grids (free and open-source) \u2014 Migration Guide</li> <li>\u26a1 10-15x faster random generation than Unity.Random in benchmarks</li> <li>\ud83d\udd0c Reduced boilerplate component wiring with attributes</li> <li>\ud83c\udfae Designer-friendly effects system (buffs/debuffs as ScriptableObjects)</li> <li>\ud83c\udf33 O(log n) spatial queries instead of O(n) loops</li> <li>\ud83d\udee0\ufe0f 20+ editor tools that automate sprite/animation workflows</li> <li>\u2705 8,000+ tests</li> </ul> <p>\ud83d\uddfa\ufe0f Roadmap Snapshot \u2014 See the Roadmap for prioritized details.</p> <ul> <li>Inspector tooling: inline nested editors, tabbed navigation, live instrumentation, disable-if/layer attributes</li> <li>Editor automation: Animation Creator and Sprite Sheet Animation Creator enhancements, timeline-ready Event Editor upgrades, and new automation dashboards</li> <li>Random/statistics: CI statistical harness, automated quality reports, scenario samplers, job-safe stream schedulers</li> <li>Spatial trees: graduate the 3D variants, add incremental updates, physics-shape parity, and streaming builders</li> <li>UI Toolkit: control pack (dockable panes, data grids), theming samples, and performance patterns</li> <li>Utilities: cross-system bridges plus new math/combinatorics and service-pattern helpers</li> <li>Performance: automated benchmarks, Burst/Jobs rewrites of hot paths, and allocation analyzers</li> <li>Attributes & tags: effect visualization tools, attribute graphs, and migration/versioning helpers</li> <li>Relational components: cached reflection, source generators, editor-time validation, and interface-based resolution</li> </ul> <p>\ud83d\udcda New to Unity Helpers? Start here: Getting Started Guide</p> <p>\ud83d\udd0d Looking for something specific? Check the Feature Index</p> <p>\u2753 Need a definition? See the Glossary</p>"},{"location":"readme/#first-time-here","title":"\ud83d\udc4b First Time Here?","text":"<p>Choose your starting point:</p> Your Problem Your Solution Time to Value \ud83c\udfa8 Writing custom editors Inspector Tooling - Odin-level features, free ~2 minutes \ud83d\udc0c Writing <code>GetComponent</code> everywhere Relational Components - Auto-wire with attributes ~2 minutes \ud83c\udfae Need buffs/debuffs system Effects System - Designer-friendly ScriptableObjects ~5 minutes \ud83d\udd0d Slow spatial searches Spatial Trees - O(log n) queries ~5 minutes \ud83c\udfb2 Random is too slow/limited PRNG.Instance - 10-15x faster in benchmarks ~1 minute \ud83d\udcbe Need save/load system Serialization - Unity types just work ~10 minutes \ud83d\udee0\ufe0f Manual sprite workflows Editor Tools - 20+ automation tools ~3 minutes <p>Not sure where to start? \u2192 Getting Started Guide walks through the top 3 features in 5 minutes.</p>"},{"location":"readme/#top-time-savers","title":"\u26a1 Top Time-Savers","text":"<p>These features reduce entire categories of repetitive work. Pick one that solves your immediate pain:</p>"},{"location":"readme/#1-inspector-tooling","title":"1. \ud83c\udfa8 Inspector Tooling","text":"<p>\u23f1\ufe0f 5-10 min/script \u00d7 200 scripts = ~20 hours saved on custom editors</p> <p>Declarative inspector attributes reduce the need for custom PropertyDrawers and EditorGUI code:</p> C#<pre><code>// \u274c OLD WAY: 100+ lines of custom editor code\n[CustomEditor(typeof(CharacterStats))]\npublic class CharacterStatsEditor : Editor {\n // ... SerializedProperty declarations ...\n // ... OnEnable setup ...\n // ... OnInspectorGUI with EditorGUI.BeginFoldoutHeaderGroup ...\n // ... Custom button rendering ...\n // ... Conditional field display logic ...\n}\n\n// \u2705 NEW WAY: Declarative attributes, zero custom editors\npublic class CharacterStats : MonoBehaviour\n{\n [WGroup(\"combat\", \"Combat Stats\", collapsible: true)]\n public float maxHealth = 100f;\n [WGroupEnd(\"combat\")] // defense IS included, then group closes\n public float defense = 10f;\n\n [WGroup(\"abilities\", \"Abilities\", collapsible: true, startCollapsed: true)]\n [System.Flags] public enum Powers { None = 0, Fly = 1, Strength = 2, Speed = 4 }\n [WEnumToggleButtons(showSelectAll: true, buttonsPerRow: 3)]\n [WGroupEnd(\"abilities\")] // currentPowers IS included, then group closes\n public Powers currentPowers;\n\n public enum WeaponType { Melee, Ranged, Magic }\n public WeaponType weaponType;\n\n [WShowIf(nameof(weaponType), WShowIfComparison.Equal, WeaponType.Ranged)]\n public int ammoCapacity = 30;\n\n [WButton(\"Heal to Full\", groupName: \"Debug\")]\n private void HealToFull() { maxHealth = 100f; }\n}\n</code></pre> <p>Features:</p> <ul> <li>WGroup - Boxed sections with auto-inclusion, collapsible headers, and animations when enabled</li> <li>WButton - Method buttons with history, async support, cancellation</li> <li>WShowIf - Conditional visibility (9 comparison operators)</li> <li>WEnumToggleButtons - Flag enums as visual toggle grids</li> <li>SerializableDictionary, SerializableSet, WGuid, SerializableType - Collections Unity can't serialize</li> </ul> <p>\ud83d\udcd6 Complete Inspector Guide | \ud83d\udd04 Odin Migration Guide</p>"},{"location":"readme/#2-auto-wire-components","title":"2. \ud83d\udd0c Auto-Wire Components","text":"<p>\u23f1\ufe0f 10-20 min/script \u00d7 100 scripts = ~20 hours saved</p> <p>Reduces GetComponent boilerplate with attribute-based auto-wiring. Replace 20+ lines with 3 attributes:</p> C#<pre><code>// \u274c OLD WAY: 20+ lines per script\nvoid Awake() {\n sprite = GetComponent<SpriteRenderer>();\n if (sprite == null) Debug.LogError(\"Missing SpriteRenderer!\");\n\n rigidbody = GetComponentInParent<Rigidbody2D>();\n if (rigidbody == null) Debug.LogError(\"Missing Rigidbody2D!\");\n\n colliders = GetComponentsInChildren<Collider2D>();\n // 15 more lines...\n}\n\n// \u2705 NEW WAY: 4 lines total\n[SiblingComponent] private SpriteRenderer sprite;\n[ParentComponent] private Rigidbody2D rigidbody;\n[ChildComponent] private Collider2D[] colliders;\nvoid Awake() => this.AssignRelationalComponents();\n</code></pre> <p>Bonus: Works with VContainer/Zenject/Reflex for automatic DI + relational wiring!</p> <p>\ud83d\udcd6 Learn More | See <code>Samples~/DI - VContainer</code>, <code>Samples~/DI - Zenject</code>, and <code>Samples~/DI - Reflex</code> folders in the repository for DI examples</p>"},{"location":"readme/#3-data-driven-effects","title":"3. \ud83c\udfae Data-Driven Effects","text":"<p>\u23f1\ufe0f 2-4 hours/effect \u00d7 50 effects = ~150 hours saved</p> <p>Designers create buffs/debuffs as ScriptableObjects. Zero programmer time after 20-minute setup:</p> C#<pre><code>// Create once (ScriptableObject in editor):\n// - HasteEffect: Speed \u00d7 1.5, duration 5s, tag \"Haste\", particle effect\n\n// Use everywhere:\nplayer.ApplyEffect(hasteEffect); // Apply buff\nif (player.HasTag(\"Stunned\")) return; // Query state\nplayer.RemoveEffects(player.GetHandlesWithTag(\"Haste\")); // Batch removal\n</code></pre> <p>What you get:</p> <ul> <li>Automatic stacking & duration management</li> <li>Reference-counted tags for gameplay queries</li> <li>Cosmetic VFX/SFX that spawn/despawn automatically</li> <li>Designer-friendly iteration without code changes</li> </ul> <p>Beyond buffs: Tags become a flexible capability system for AI decisions, permission gates, state management, and complex gameplay interactions (invulnerability, stealth, elemental systems).</p> <p>\ud83d\udcd6 Full Guide | \ud83d\ude80 5-Minute Tutorial</p>"},{"location":"readme/#4-unity-aware-serialization","title":"4. \ud83d\udcbe Unity-Aware Serialization","text":"<p>\u23f1\ufe0f 40+ hours on initial implementation + prevents player data loss</p> <p>JSON/Protobuf that understands <code>Vector3</code>, <code>GameObject</code>, <code>Color</code> - no custom converters needed:</p> C#<pre><code>// Vector3, Color, GameObject references just work:\nvar saveData = new SaveData {\n playerPosition = new Vector3(1, 2, 3),\n playerColor = Color.cyan,\n inventory = new List<GameObject>()\n};\n\n// One line to save:\nbyte[] data = Serializer.JsonSerialize(saveData);\n\n// Schema evolution = never break old saves:\n[ProtoMember(1)] public int gold;\n[ProtoMember(2)] public Vector3 position;\n// Adding new field? Old saves still load!\n[ProtoMember(3)] public int level; // Safe to add\n</code></pre> <p>Real-world impact: Ship updates without worrying about corrupting player saves.</p> <p>\ud83d\udcd6 Serialization Guide</p>"},{"location":"readme/#5-object-pooling","title":"5. \ud83c\udfb1 Object Pooling","text":"<p>\u23f1\ufe0f Reduces GC spikes = 5-10 FPS improvement in complex scenes</p> <p>Zero-allocation queries with automatic cleanup. Thread-safe pooling in one line:</p> C#<pre><code>// Get pooled buffer - automatically returned on scope exit\nvoid ProcessEnemies(QuadTree2D<Enemy> enemyTree) {\n using var lease = Buffers<Enemy>.List.Get(out List<Enemy> buffer);\n\n // Use it for spatial query - zero allocations!\n enemyTree.GetElementsInRange(playerPos, 10f, buffer);\n\n foreach (Enemy enemy in buffer) {\n enemy.TakeDamage(5f);\n }\n\n // Buffer automatically returned to pool here - no cleanup needed\n}\n</code></pre> <p>Why this matters:</p> <ul> <li>Stable 60 FPS under load (no GC spikes)</li> <li>AI systems querying hundreds of neighbors per frame</li> <li>Particle systems with thousands of particles</li> <li>Works for List, HashSet, Stack, Queue, and Arrays</li> </ul> <p>\ud83d\udcd6 Buffering Pattern</p>"},{"location":"readme/#6-editor-tools-suite","title":"6. \ud83d\udee0\ufe0f Editor Tools Suite","text":"<p>\u23f1\ufe0f 1-2 hours/operation \u00d7 weekly use = ~100 hours/year</p> <p>20+ tools that automate sprite cropping, animation creation, atlas generation, prefab validation:</p> <p>Common workflows:</p> <ul> <li>Sprite Cropper: Add or remove transparent pixels from 500 sprites \u2192 1 click (was: 30 minutes in Photoshop)</li> <li>Animation Creator: Bulk-create clips from naming patterns (<code>walk_0001.png</code>) \u2192 1 minute (was: 20 minutes)</li> <li>Prefab Checker: Validate 200 prefabs for missing references \u2192 1 click (was: manual QA)</li> <li>Atlas Generator: Create sprite atlases from regex/labels \u2192 automated (was: manual setup)</li> </ul> <p>\ud83d\udcd6 Editor Tools Guide</p>"},{"location":"readme/#batteries-included-extensions","title":"\ud83c\udf81 Batteries-Included Extensions","text":"<p>Unity Helpers includes 200+ extension methods for common Unity operations:</p>"},{"location":"readme/#unity-type-extensions","title":"Unity Type Extensions","text":"C#<pre><code>// Color averaging (4 methods: LAB, HSV, Weighted, Dominant)\nColor teamColor = sprite.GetAverageColor(ColorAveragingMethod.LAB); // Perceptually accurate\n\n// Collider auto-fitting\npolygonCollider.UpdateShapeToSprite(); // Instant sprite \u2192 collider sync\n\n// Smooth direction rotation (returns rotated direction vector)\nVector2 facing = Helpers.GetAngleWithSpeed(targetDirection, currentFacing, rotationSpeed);\n\n// Safe destruction (works in editor AND runtime)\ngameObject.SmartDestroy(); // No more #if UNITY_EDITOR everywhere\n\n// Camera world bounds\nBounds visibleArea = Camera.main.OrthographicBounds(); // For culling/spawning\n\n// Predictive targeting (intercept moving targets)\nVector2 aimPoint = target.PredictCurrentTarget(shooter.position, projectileSpeed, predictiveFiring: true, targetVelocity);\nturret.transform.up = (aimPoint - (Vector2)shooter.position).normalized;\n</code></pre>"},{"location":"readme/#math-that-should-be-built-in","title":"Math That Should Be Built-In","text":"C#<pre><code>// Positive modulo (no more negative results!)\nint index = (-1).PositiveMod(array.Length); // 4, not -1\n\n// Wrapped add for ring buffers\nindex = index.WrappedAdd(2, capacity); // Handles overflow correctly\n\n// Approximate equality with tolerance\nif (transform.position.x.Approximately(target.x, 0.01f)) { /* close enough */ }\n\n// Polyline simplification (Douglas\u2013Peucker)\nList<Vector2> simplified = LineHelper.Simplify(path, epsilon: 0.5f); // Reduce pathfinding waypoints\n</code></pre>"},{"location":"readme/#collection-utilities","title":"Collection Utilities","text":"C#<pre><code>// Infinite iterator (no extra allocation)\nforeach (var item in itemList.Infinite()) { /* cycles infinitely */ }\n\n// Aggregate bounds from multiple renderers\nBounds? combined = renderers.Select(r => r.bounds).GetBounds();\n\n// String similarity for fuzzy search\nint distance = playerName.LevenshteinDistance(\"jon\"); // \"john\" = 1, close match!\n\n// Case conversions (6 styles: Pascal, Camel, Snake, Kebab, Title, Constant)\nstring apiKey = \"user_name\".ToPascalCase(); // \"UserName\"\n</code></pre> <p>Full list: Math & Extensions Guide | Reflection Helpers</p>"},{"location":"readme/#additional-utilities","title":"\ud83d\udc8e Additional Utilities","text":"<p>These utilities solve specific problems that waste hours if you implement them yourself:</p> Feature What It Does Time Saved Predictive Targeting Accurate ballistics for turrets/missiles in one call 2-3 hours per shooting system Coroutine Jitter Prevents 100 enemies polling on same frame Reduces frame spikes IL-Emitted Reflection Up to 12x faster than System.Reflection for method invocations, IL2CPP safe Critical for serialization/modding SmartDestroy() Editor/runtime safe destruction (no scene corruption) Prevents countless debugging hours Convex/Concave Hulls Generate territory borders from point clouds 4-6 hours per hull algorithm Logging Extensions Rich tags, thread-aware logs, per-object toggles Keeps consoles readable + actionable"},{"location":"readme/#design-philosophy","title":"Design Philosophy","text":"<p>Unity Helpers reduces repetitive work by providing tested utilities for common Unity patterns, including GetComponent boilerplate, spatial query loops, and save/load systems.</p> <p>Built for Real Projects:</p> <ul> <li>\u2705 Tested in shipped commercial games</li> <li>\u2705 8,000+ automated tests catch edge cases before you hit them</li> <li>\u2705 Minimal external dependencies - depends on protobuf-net for binary serialization</li> <li>\u2705 IL2CPP/WebGL ready with optimized SINGLE_THREADED paths</li> <li>\u2705 MIT Licensed - use freely in commercial projects</li> </ul> <p>Who This Is For:</p> <ul> <li>Indie devs who need tools without enterprise overhead</li> <li>Teams who value performance and want their junior devs to use tested code</li> <li>Senior engineers who want to avoid re-implementing the same utilities every project</li> </ul>"},{"location":"readme/#installation","title":"Installation","text":"<p>Unity Helpers is available from multiple sources. Choose the one that best fits your workflow:</p> Source Best For Auto-Updates OpenUPM Most users, easy version management \u2705 Yes Git URL Latest commits, CI/CD pipelines \u2705 Yes NPM Registry Teams already using NPM \u2705 Yes Source Offline, modifications needed \u274c Manual"},{"location":"readme/#from-openupm-recommended","title":"From OpenUPM (Recommended)","text":"<p>OpenUPM is the recommended installation method for easy version management and updates.</p>"},{"location":"readme/#option-a-via-package-manager-ui","title":"Option A: Via Package Manager UI","text":"<ol> <li>Open Edit \u2192 Project Settings \u2192 Package Manager</li> <li>Under Scoped Registries, click + to add a new registry:</li> <li>Name: <code>OpenUPM</code></li> <li>URL: <code>https://package.openupm.com</code></li> <li>Scope(s): <code>com.wallstop-studios</code></li> <li>Click Save</li> <li>Open Window \u2192 Package Manager</li> <li>Change the dropdown to My Registries</li> <li>Find and install <code>Unity Helpers</code></li> </ol>"},{"location":"readme/#option-b-via-openupm-cli","title":"Option B: Via OpenUPM CLI","text":"<p>If you have the OpenUPM CLI installed:</p> Bash<pre><code>openupm add com.wallstop-studios.unity-helpers\n</code></pre>"},{"location":"readme/#option-c-manual-manifestjson","title":"Option C: Manual manifest.json","text":"<p>Add to your <code>Packages/manifest.json</code>:</p> JSON<pre><code>{\n \"scopedRegistries\": [\n {\n \"name\": \"OpenUPM\",\n \"url\": \"https://package.openupm.com\",\n \"scopes\": [\"com.wallstop-studios\"]\n }\n ],\n \"dependencies\": {\n \"com.wallstop-studios.unity-helpers\": \"3.1.0\"\n }\n}\n</code></pre>"},{"location":"readme/#from-git-url","title":"From Git URL","text":"<p>Install directly from GitHub for the latest version:</p> <ol> <li>Open Window \u2192 Package Manager</li> <li>Click + \u2192 Add package from git URL...</li> <li>Enter: <code>https://github.com/wallstop/unity-helpers.git</code></li> </ol> <p>OR add to your <code>Packages/manifest.json</code>:</p> JSON<pre><code>{\n \"dependencies\": {\n \"com.wallstop-studios.unity-helpers\": \"https://github.com/wallstop/unity-helpers.git\"\n }\n}\n</code></pre> <p>Tip: To lock to a specific version, append <code>#3.1.0</code> to the URL.</p>"},{"location":"readme/#from-npm-registry","title":"From NPM Registry","text":"<ol> <li>Open Edit \u2192 Project Settings \u2192 Package Manager</li> <li>Under Scoped Registries, click + to add a new registry:</li> <li>Name: <code>NPM</code></li> <li>URL: <code>https://registry.npmjs.org</code></li> <li>Scope(s): <code>com.wallstop-studios</code></li> <li>Click Save</li> <li>Open Window \u2192 Package Manager</li> <li>Change the dropdown to My Registries</li> <li>Find and install <code>com.wallstop-studios.unity-helpers</code></li> </ol>"},{"location":"readme/#from-source","title":"From Source","text":""},{"location":"readme/#option-a-import-unity-package","title":"Option A: Import Unity Package","text":"<ol> <li>Download the latest <code>.unitypackage</code> from GitHub Releases</li> <li>In Unity, go to Assets \u2192 Import Package \u2192 Custom Package...</li> <li>Select the downloaded <code>.unitypackage</code> file and import</li> </ol>"},{"location":"readme/#option-b-clone-or-download-repository","title":"Option B: Clone or Download Repository","text":"<ol> <li>Clone or download the repository</li> <li>Copy the contents to your project's <code>Assets/</code> or <code>Packages/</code> folder</li> <li>Unity will automatically import the package</li> </ol>"},{"location":"readme/#compatibility","title":"Compatibility","text":"Unity Version Built-In URP HDRP 2021 Likely, but untested Likely, but untested Likely, but untested 2022 \u2705 Compatible \u2705 Compatible \u2705 Compatible 2023 \u2705 Compatible \u2705 Compatible \u2705 Compatible Unity 6 \u2705 Compatible \u2705 Compatible \u2705 Compatible"},{"location":"readme/#platform-support","title":"Platform Support","text":"<p>Unity Helpers is multiplatform compatible including:</p> <ul> <li>\u2705 WebGL - Full support with optimized SINGLE_THREADED hot paths</li> <li>\u2705 IL2CPP - Tested and compatible with ahead-of-time compilation</li> <li>\u2705 Mobile (iOS, Android) - Compatible with IL2CPP</li> <li>\u2705 Desktop (Windows, macOS, Linux) - Full threading support</li> <li>\u2705 Consoles - IL2CPP compatible</li> </ul> <p>Requirements:</p> <ul> <li>.NET Standard 2.1 - Required for core library features</li> </ul>"},{"location":"readme/#webgl-and-single-threaded-optimization","title":"WebGL and Single-Threaded Optimization","text":"<p>Unity Helpers includes a <code>SINGLE_THREADED</code> scripting define symbol for WebGL and other single-threaded environments. When enabled, the library automatically uses optimized code paths that eliminate threading overhead:</p> <p>Optimized systems with SINGLE_THREADED:</p> <ul> <li>Buffers & Pooling - Uses <code>Stack<T></code> and <code>Dictionary<T></code> instead of <code>ConcurrentBag<T></code> and <code>ConcurrentDictionary<T></code></li> <li>Random Number Generation - Static instances instead of <code>ThreadLocal<T></code></li> <li>Reflection Caches - Non-concurrent dictionaries for faster lookups</li> <li>Thread Pools - SingleThreadedThreadPool disabled (not needed on WebGL)</li> </ul> <p>How to enable:</p> <p>Unity automatically defines <code>UNITY_WEBGL</code> for WebGL builds. To enable SINGLE_THREADED optimization:</p> <ol> <li>Go to Project Settings > Player > Other Settings > Scripting Define Symbols</li> <li>Add <code>SINGLE_THREADED</code> for WebGL platform</li> <li>Or use in your <code>csc.rsp</code> file: <code>-define:SINGLE_THREADED</code></li> </ol> <p>Performance impact: 10-20% faster hot path operations on single-threaded platforms by avoiding unnecessary synchronization overhead.</p>"},{"location":"readme/#il2cpp-and-code-stripping-considerations","title":"IL2CPP and Code Stripping Considerations","text":"<p>\u26a0\ufe0f Important for IL2CPP builds (WebGL, Mobile, Consoles):</p> <p>Some features in Unity Helpers use reflection internally (particularly Protobuf serialization and ReflectionHelpers). IL2CPP's managed code stripping may remove types/members that are only accessed via reflection, causing runtime errors.</p> <p>Symptoms of stripping issues:</p> <ul> <li><code>NullReferenceException</code> or <code>TypeLoadException</code> during deserialization</li> <li>Missing fields after Protobuf deserialization</li> <li>Reflection helpers failing to find types at runtime</li> </ul>"},{"location":"readme/#solution-use-linkxml-to-preserve-required-types","title":"Solution: Use link.xml to preserve required types","text":"<p>Create a <code>link.xml</code> file in your <code>Assets</code> folder to prevent stripping:</p> XML<pre><code><linker>\n <!-- Preserve your serialized types -->\n <assembly fullname=\"Assembly-CSharp\">\n <type fullname=\"MyNamespace.PlayerSave\" preserve=\"all\"/>\n <type fullname=\"MyNamespace.InventoryData\" preserve=\"all\"/>\n <!-- Add all Protobuf-serialized types here -->\n </assembly>\n\n <!-- Preserve Unity Helpers if needed -->\n <assembly fullname=\"WallstopStudios.UnityHelpers.Runtime\" preserve=\"all\"/>\n</linker>\n</code></pre> <p>Best practices:</p> <ul> <li>\u2705 Always test IL2CPP builds - Development builds don't use stripping, so bugs only appear in release builds</li> <li>\u2705 Test on target platform - WebGL stripping behaves differently than iOS/Android</li> <li>\u2705 Use link.xml for all Protobuf types - Any type with <code>[ProtoContract]</code> should be preserved</li> <li>\u2705 Verify after every schema change - Adding new serialized types requires updating link.xml</li> <li>\u2705 Check logs for stripping warnings - Unity logs which types are stripped during build</li> </ul> <p>When you don't need link.xml:</p> <ul> <li>JSON serialization (uses source-generated converters, not reflection)</li> <li>Spatial trees and data structures (no reflection used)</li> <li>Most helper methods (compiled ahead-of-time)</li> </ul> <p>Related documentation:</p> <ul> <li>Unity Manual: Managed Code Stripping</li> <li>Protobuf-net and IL2CPP</li> <li>Serialization Guide: IL2CPP Warning</li> <li>Reflection Helpers: IL2CPP Warning</li> </ul>"},{"location":"readme/#quick-start-guide","title":"Quick Start Guide","text":"<p>\ud83d\udca1 First time? Skip to section #2 (Relational Components) - it has the biggest immediate impact.</p> <p>Already read the Top 5 Time-Savers? Jump directly to the Core Features reference below, or check out the Getting Started Guide.</p>"},{"location":"readme/#core-features","title":"Core Features","text":""},{"location":"readme/#random-number-generators","title":"Random Number Generators","text":"<p>Unity Helpers includes 15 high-quality random number generators, all implementing a rich <code>IRandom</code> interface:</p>"},{"location":"readme/#available-generators","title":"Available Generators","text":"<p>The tables below are auto-generated by the performance benchmark. Run <code>RandomPerformanceTests.Benchmark</code> in the Unity Test Runner to refresh them.</p> <p>No benchmark data available yet. Run <code>RandomPerformanceTests.Benchmark</code> to populate these tables.</p>"},{"location":"readme/#rich-api","title":"Rich API","text":"<p>All generators implement <code>IRandom</code> with the following functionality:</p> C#<pre><code>IRandom random = PRNG.Instance;\n\n// Basic types\nint i = random.Next(); // int in [0, int.MaxValue]\nint range = random.Next(10, 20); // int in [10, 20)\nuint ui = random.NextUint(); // uint in [0, uint.MaxValue]\nfloat f = random.NextFloat(); // float in [0.0f, 1.0f]\ndouble d = random.NextDouble(); // double in [0.0d, 1.0d]\nbool b = random.NextBool(); // true or false\n\n// Unity types\nVector2 v2 = random.NextVector2(); // Random 2D vector\nVector3 v3 = random.NextVector3(); // Random 3D vector\nColor color = random.NextColor(); // Random color\nQuaternion rot = random.NextRotation(); // Random rotation\n\n// Distributions\nfloat gaussian = random.NextGaussian(mean: 0f, stdDev: 1f);\n\n// Collections\nT item = random.NextOf(collection); // Random element\nT[] shuffled = random.Shuffle(array); // Fisher-Yates shuffle\nint weightedIndex = random.NextWeightedIndex(weights);\n\n// Special\nGuid uuid = random.NextGuid(); // UUIDv4\nT enumValue = random.NextEnum<T>(); // Random enum value\nfloat[,] noise = random.NextNoiseMap(width, height); // Perlin noise\n</code></pre>"},{"location":"readme/#deterministic-gameplay","title":"Deterministic Gameplay","text":"<p>All generators are seedable for replay systems:</p> C#<pre><code>// Create seeded generator for deterministic behavior\nIRandom seededRandom = new IllusionFlow(seed: 12345);\n\n// Same seed = same sequence\nIRandom replay = new IllusionFlow(seed: 12345);\n// Both will generate identical values\n</code></pre> <p>Threading:</p> <ul> <li>Do not share a single RNG instance across threads.</li> <li>Use <code>PRNG.Instance</code> for a thread-local default, or use each generator's <code>TypeName.Instance</code> (e.g., <code>IllusionFlow.Instance</code>, <code>PcgRandom.Instance</code>).</li> <li>Alternatively, create one separate instance per thread.</li> </ul> <p>\ud83d\udcca Performance Comparison</p>"},{"location":"readme/#spatial-trees","title":"Spatial Trees","text":"<p>Efficient spatial data structures for 2D and 3D games.</p>"},{"location":"readme/#2d-spatial-trees","title":"2D Spatial Trees","text":"<ul> <li>QuadTree2D - Best general-purpose choice</li> <li>KDTree2D - Fast nearest-neighbor queries</li> <li>RTree2D - Optimized for bounding boxes</li> </ul> C#<pre><code>using WallstopStudios.UnityHelpers.Core.DataStructure;\n\n// Create from collection\nGameObject[] objects = FindObjectsOfType<GameObject>();\nQuadTree2D<GameObject> tree = new(objects, go => go.transform.position);\n\n// Query by radius\nList<GameObject> nearby = new();\ntree.GetElementsInRange(playerPos, radius: 10f, nearby);\n\n// Query by bounds\nBounds searchArea = new(center, size);\ntree.GetElementsInBounds(searchArea, nearby);\n\n// Find nearest neighbors (approximate, but fast)\ntree.GetApproximateNearestNeighbors(playerPos, count: 5, nearby);\n</code></pre>"},{"location":"readme/#3d-spatial-trees","title":"3D Spatial Trees","text":"<p>Note: KdTree3D, OctTree3D, and RTree3D are under active development. SpatialHash3D is stable and production\u2011ready.</p> <ul> <li>OctTree3D - Best general-purpose choice for 3D</li> <li>KDTree3D - Fast 3D nearest-neighbor queries</li> <li>RTree3D - Optimized for 3D bounding volumes</li> <li>SpatialHash3D - Efficient for uniformly distributed moving objects (stable)</li> </ul> C#<pre><code>// Same API as 2D, but with Vector3\nVector3[] positions = GetAllPositions();\nOctTree3D<Vector3> tree = new(positions, p => p);\n\nList<Vector3> results = new();\ntree.GetElementsInRange(center, radius: 50f, results);\n</code></pre>"},{"location":"readme/#when-to-use-spatial-trees","title":"When to Use Spatial Trees","text":"<p>\u2705 Good for:</p> <ul> <li>Many objects (100+)</li> <li>Frequent spatial queries</li> <li>Static or slowly changing data</li> <li>AI awareness systems</li> <li>Visibility culling</li> <li>Collision detection optimization</li> </ul> <p>\u274c Not ideal for:</p> <ul> <li>Few objects (<50)</li> <li>Constantly moving objects</li> <li>Single queries</li> <li>Already using Unity's physics system</li> </ul> <p>\ud83d\udcca 2D Benchmarks | \ud83d\udcca 3D Benchmarks</p> <p>For behavior details and edge cases, see: Spatial Tree Semantics</p>"},{"location":"readme/#relational-components","title":"Relational Components","text":"<p>Auto-wire components using attributes to reduce GetComponent boilerplate.</p> <p>Key attributes:</p> <ul> <li><code>[SiblingComponent]</code> - Find components on same GameObject</li> <li><code>[ParentComponent]</code> - Find components in parent hierarchy</li> <li><code>[ChildComponent]</code> - Find components in children</li> <li><code>[ValidateAssignment]</code> - Validate at edit time, show errors in inspector</li> <li><code>[WNotNull]</code> - Must be assigned in inspector</li> <li><code>[WReadOnly]</code> - Read-only display in inspector</li> <li><code>[WInLineEditor]</code> - Inline inspector editing for object references</li> <li><code>[WShowIf]</code> - Conditional display based on field values</li> </ul> <p>Quick example:</p> C#<pre><code>using WallstopStudios.UnityHelpers.Core.Attributes;\n\npublic class Enemy : MonoBehaviour\n{\n // Find on same GameObject\n [SiblingComponent]\n private Animator animator;\n\n // Find in parent\n [ParentComponent]\n private EnemySpawner spawner;\n\n // Find in children\n [ChildComponent]\n private List<Weapon> weapons;\n\n // Optional component (no error if missing)\n [SiblingComponent(Optional = true)]\n private AudioSource audioSource;\n\n // Only search direct children/parents\n [ParentComponent(OnlyAncestors = true)]\n private Transform[] parentHierarchy;\n\n // Include inactive components\n [ChildComponent(IncludeInactive = true)]\n private ParticleSystem[] effects;\n\n private void Awake()\n {\n this.AssignRelationalComponents();\n }\n}\n</code></pre> <p>See the in-depth guide: Relational Components. Performance snapshots: Relational Component Performance Benchmarks.</p>"},{"location":"readme/#effects-attributes-and-tags","title":"Effects, Attributes, and Tags","text":"<p>Create data-driven gameplay effects that modify stats, apply tags, and drive cosmetics.</p> <p>Key pieces:</p> <ul> <li><code>AttributeEffect</code> \u2014 ScriptableObject that bundles stat changes, tags, cosmetics, and duration.</li> <li><code>EffectHandle</code> \u2014 Unique ID for one application instance; remove/refresh specific stacks.</li> <li><code>AttributesComponent</code> \u2014 Base class for components that expose modifiable <code>Attribute</code> fields.</li> <li><code>TagHandler</code> \u2014 Counts and queries string tags for gating gameplay (e.g., \"Stunned\").</li> <li><code>CosmeticEffectData</code> \u2014 Prefab-like container of behaviors shown while an effect is active.</li> </ul> <p>Quick example:</p> C#<pre><code>using WallstopStudios.UnityHelpers.Tags;\n\n// 1) Define stats on a component\npublic class CharacterStats : AttributesComponent\n{\n public Attribute Health = 100f;\n public Attribute Speed = 5f;\n}\n\n// 2) Author an AttributeEffect (ScriptableObject) in the editor\n// - modifications: [ { attribute: \"Speed\", action: Multiplication, value: 1.5f } ]\n// - durationType: Duration, duration: 5\n// - effectTags: [ \"Haste\" ]\n// - cosmeticEffects: [ a prefab with CosmeticEffectData + Particle/Audio components ]\n\n// 3) Apply and later remove\nGameObject player = ...;\nAttributeEffect haste = ...; // ScriptableObject reference\nEffectHandle? handle = player.ApplyEffect(haste);\nif (handle.HasValue)\n{\n // Remove early if needed\n player.RemoveEffect(handle.Value);\n}\n\n// Query tags anywhere\nif (player.HasTag(\"Stunned\")) { /* disable input */ }\n</code></pre> <p>Details at a glance:</p> <ul> <li><code>ModifierDurationType.Instant</code> \u2014 applies permanently; returns null handle.</li> <li><code>ModifierDurationType.Duration</code> \u2014 temporary; expires automatically; reapply can reset if enabled.</li> <li><code>ModifierDurationType.Infinite</code> \u2014 persists until <code>RemoveEffect(handle)</code> is called.</li> <li><code>AttributeModification</code> order: Addition \u2192 Multiplication \u2192 Override.</li> <li><code>CosmeticEffectData.RequiresInstancing</code> \u2014 instance per application or reuse shared presenters.</li> </ul> <p>Power Pattern: Tags aren't just for buffs\u2014use them to build capability systems for invulnerability, AI decision-making, permission gates, state management, and elemental interactions. See Advanced Scenarios for patterns.</p> <p>Further reading: see the full guide Effects System.</p>"},{"location":"readme/#serialization","title":"Serialization","text":"<p>Fast, compact serialization for save systems, config, and networking.</p> <p>This package provides three serialization technologies:</p> <ul> <li><code>Json</code> \u2014 Uses System.Text.Json with built\u2011in converters for Unity types.</li> <li><code>Protobuf</code> \u2014 Uses protobuf-net for compact, fast, schema\u2011evolvable binary.</li> <li><code>SystemBinary</code> \u2014 Uses .NET BinaryFormatter for legacy/ephemeral data only.</li> </ul> <p>All are exposed via <code>WallstopStudios.UnityHelpers.Core.Serialization.Serializer</code>.</p>"},{"location":"readme/#json-profiles","title":"JSON Profiles","text":"<ul> <li>Normal \u2014 default settings (case-insensitive, includes fields, comments/trailing commas allowed)</li> <li>Pretty \u2014 human-friendly, indented</li> <li>Fast \u2014 strict, minimal with Unity converters (case-sensitive, strict numbers, no comments/trailing commas, IncludeFields=false)</li> <li>FastPOCO \u2014 strict, minimal, no Unity converters; best for pure POCO graphs</li> </ul>"},{"location":"readme/#when-to-use-what","title":"When To Use What","text":"<ul> <li>Use Json for:</li> <li>Player or tool settings, human\u2011readable saves, serverless workflows.</li> <li>Interop with tooling, debugging, or versioning in Git.</li> <li>Use Protobuf for:</li> <li>Network payloads, large save files, bandwidth/storage\u2011sensitive data.</li> <li>Situations where you expect schema evolution across versions.</li> <li>Use SystemBinary only for:</li> <li>Transient caches in trusted environments where data and code version match.</li> <li>Never for untrusted data or long\u2011term persistence.</li> </ul>"},{"location":"readme/#json-example","title":"JSON Example","text":"C#<pre><code>using System.Collections.Generic;\nusing UnityEngine;\nusing WallstopStudios.UnityHelpers.Core.Serialization;\n\npublic class SaveData\n{\n public Vector3 position;\n public Color playerColor;\n public List<GameObject> inventory;\n}\n\nvar data = new SaveData\n{\n position = new Vector3(1, 2, 3),\n playerColor = Color.cyan,\n inventory = new List<GameObject>()\n};\n\n// Serialize to UTF\u20118 JSON bytes (Unity types supported via built\u2011in converters)\nbyte[] jsonBytes = Serializer.JsonSerialize(data);\n\n// Deserialize from string\nstring jsonText = Serializer.JsonStringify(data, pretty: true);\nSaveData fromText = Serializer.JsonDeserialize<SaveData>(jsonText);\n\n// File helpers\nSerializer.WriteToJsonFile(data, path: \"save.json\", pretty: true);\nSaveData fromFile = Serializer.ReadFromJsonFile<SaveData>(\"save.json\");\n\n// Generic entry points (choose format at runtime)\nbyte[] bytes = Serializer.Serialize(data, SerializationType.Json);\nSaveData loaded = Serializer.Deserialize<SaveData>(bytes, SerializationType.Json);\n</code></pre>"},{"location":"readme/#protobuf-example","title":"Protobuf Example","text":"C#<pre><code>using ProtoBuf; // protobuf-net\nusing UnityEngine;\nusing WallstopStudios.UnityHelpers.Core.Serialization;\n\n[ProtoContract]\npublic class NetworkMessage\n{\n [ProtoMember(1)] public int playerId;\n [ProtoMember(2)] public Vector3 position; // Vector3 works in Protobuf via built-in surrogates\n}\n\nvar message = new NetworkMessage { playerId = 7, position = new Vector3(5, 0, -2) };\n\n// Protobuf bytes (small + fast)\nbyte[] bytes = Serializer.ProtoSerialize(message);\nNetworkMessage decoded = Serializer.ProtoDeserialize<NetworkMessage>(bytes);\n\n// Generic entry points\nbyte[] bytes2 = Serializer.Serialize(message, SerializationType.Protobuf);\nNetworkMessage decoded2 = Serializer.Deserialize<NetworkMessage>(bytes2, SerializationType.Protobuf);\n\n// Buffer reuse (reduce GC for hot paths)\nbyte[] buffer = null;\nint len = Serializer.Serialize(message, SerializationType.Protobuf, ref buffer);\nNetworkMessage again = Serializer.Deserialize<NetworkMessage>(buffer.AsSpan(0, len).ToArray(), SerializationType.Protobuf);\n</code></pre> <p>Notes:</p> <ul> <li>Protobuf\u2011net requires stable field numbers. Annotate with <code>[ProtoMember(n)]</code> and never reuse or renumber.</li> <li>Unity types supported via surrogates: Vector\u2154, Vector2Int/3Int, Quaternion, Color/Color32, Rect/RectInt, Bounds/BoundsInt, Resolution.</li> </ul> <p>Features:</p> <ul> <li>Custom converters for Unity types (Vector\u2154/4, Color, GameObject, Matrix4x4, Type)</li> <li>Protobuf (protobuf\u2011net) support for compact binary</li> <li>LZMA compression utilities (see <code>Runtime/Utils/LZMA.cs</code>)</li> <li>Type\u2011safe serialization and pooled buffers/writers to reduce GC</li> </ul> <p>Full guide: Serialization</p>"},{"location":"readme/#data-structures","title":"Data Structures","text":"<p>Additional high-performance data structures:</p> Structure Use Case CyclicBuffer Ring buffer, sliding windows BitSet Compact boolean storage ImmutableBitSet Read-only bit flags Heap Priority queue operations PriorityQueue Event scheduling Deque Double-ended queue DisjointSet Union-find operations Trie String prefix trees SparseSet Fast add/remove with iteration TimedCache Auto-expiring cache C#<pre><code>// Cyclic buffer for damage history\nCyclicBuffer<float> damageHistory = new(capacity: 10);\ndamageHistory.Add(25f);\ndamageHistory.Add(30f);\nfloat avgDamage = damageHistory.Average();\n\n// Priority queue for event scheduling (priority determined by comparer)\nPriorityQueue<GameEvent> eventQueue = new(\n Comparer<GameEvent>.Create((a, b) => b.Priority.CompareTo(a.Priority)) // Higher first\n);\neventQueue.Enqueue(spawnEvent);\neventQueue.Enqueue(bossEvent);\nif (eventQueue.TryDequeue(out GameEvent next)) { /* process event */ }\n\n// Trie for autocomplete\nTrie commandTrie = new();\ncommandTrie.Insert(\"teleport\");\ncommandTrie.Insert(\"tell\");\ncommandTrie.Insert(\"terrain\");\nList<string> matches = commandTrie.GetWordsWithPrefix(\"tel\");\n// Returns: [\"teleport\", \"tell\"]\n</code></pre> <p>Full guide: Data Structures</p>"},{"location":"readme/#core-math-extensions","title":"Core Math & Extensions","text":"<p>Numeric helpers, geometry primitives, Unity extensions, colors, collections, strings, directions.</p> <p>See the guide: Core Math & Extensions.</p>"},{"location":"readme/#at-a-glance","title":"At a Glance","text":"<ul> <li><code>PositiveMod</code>, <code>WrappedAdd</code> \u2014 Safe cyclic arithmetic for indices/angles.</li> <li><code>LineHelper.Simplify</code> \u2014 Reduce polyline vertices with Douglas\u2013Peucker.</li> <li><code>Line2D.Intersects</code> \u2014 2D segment intersection and closest-point helpers.</li> <li><code>RectTransform.GetWorldRect</code> \u2014 Axis-aligned world bounds for rotated UI.</li> <li><code>Camera.OrthographicBounds</code> \u2014 Compute visible world bounds for ortho cameras.</li> <li><code>Color.GetAverageColor</code> \u2014 LAB/HSV/Weighted/Dom