Skip to content
This repository was archived by the owner on Jan 13, 2026. It is now read-only.

Repository files navigation

🎮 GameLovers Configs Provider

Type-safe, high-performance configuration management for Unity games

Unity 6000.0+MIT LicenseVersion 0.2.0C# 8.0+

FeaturesInstallationQuick StartDocumentationExamplesContributing


🎯 Why GameLovers Configs Provider?

Managing game configuration data shouldn't be a hassle. This library solves common Unity config challenges:

Type Safety - No more casting or string-based lookups
Designer Friendly - Edit configs in Unity Inspector with ScriptableObjects
Performance - O(1) lookups with pre-built dictionaries
Flexibility - Support for singletons, collections, and custom types
Backend Ready - Built-in serialization for server sync
Version Control - Track and update configs atomically

Perfect for managing enemy stats, item databases, level configurations, game balance values, and any other design data in your Unity projects.


✨ Features

Lightweight, type-safe configuration storage for Unity that lets you load, query, version, and serialize your game configs (design data, tuning values, asset references, etc.) in a predictable and efficient way.

Core Features:

  • 🔍 Single or multiple configs per type - Singleton pattern or id-indexed collections
  • 🚀 Fast lookups - In-memory dictionaries for O(1) performance
  • 📝 Versioning and atomic updates - Track changes and update safely
  • 🔄 JSON serialization/deserialization - Perfect for client/server sync
  • 📦 ScriptableObject containers - Designer-friendly key/value pairs
  • 🎯 Type-safe queries - No casting or string-based lookups
  • 🌐 Backend integration - Optional remote config fetching

📑 Table of Contents


📦 Requirements

  • Unity 6.0 or newer ("unity": "6000.0")
  • Namespace: GameLovers.ConfigsProvider
  • For JSON serialization: Newtonsoft.Json (Unity package com.unity.nuget.newtonsoft-json)
  • Uses Pair<TKey, TValue> from GameLovers.DataExtensions (already referenced by the assembly definition)

📦 Installation

Option 1: Unity Package Manager (Recommended)

  1. Open Unity Package Manager (WindowPackage Manager)
  2. Click the + button → Add package from git URL...
  3. Enter: https://github.com/CoderGamester/Unity-ConfigsProvider.git#0.2.0
  4. Click Add

Option 2: Manual Git URL

Add this line to your Packages/manifest.json:

{
"dependencies": {
"com.gamelovers.configsprovider": "https://github.com/CoderGamester/Unity-ConfigsProvider.git#0.2.0"
}
}

Dependencies

This package automatically handles most dependencies, but you may need:

  • Newtonsoft.Json (for serialization) - Install via Package Manager: com.unity.nuget.newtonsoft-json
  • GameLovers.DataExtensions - Automatically included via assembly definition

🔍 Verify Installation

After installation, you should see:

  • GameLovers.ConfigsProvider namespace available
  • ✅ No compilation errors in Console
  • ✅ Runtime scripts accessible in your code

🚀 Quick Start

Basic Setup in 3 Steps

Step 1: Define Your Config Classes

Create a new script GameConfigs.cs:

usingSystem;usingUnityEngine;namespaceMyGame.Configs{[Serializable]publicclassEnemyConfig{publicintId;publicstringName;publicintHealth;publicfloatMoveSpeed;publicGameObjectPrefab;// Unity asset references supported!}[Serializable]publicclassGameSettings{publicfloatMusicVolume=0.8f;publicfloatSfxVolume=1.0f;publicboolShowTutorials=true;}}

Step 2: Initialize the Provider

In your game initialization (e.g., GameManager.cs):

usingGameLovers.ConfigsProvider;usingMyGame.Configs;usingSystem.Collections.Generic;usingUnityEngine;publicclassGameManager:MonoBehaviour{privateIConfigsProvider_configs;voidStart(){// Create providervarprovider=newConfigsProvider();// Add enemy configs (multiple instances mapped by ID)provider.AddConfigs(
enemy =>enemy.Id,// Key selector functionnewList<EnemyConfig>{new(){Id=1,Name="Goblin",Health=50,MoveSpeed=3f},new(){Id=2,Name="Orc",Health=100,MoveSpeed=2f},new(){Id=3,Name="Dragon",Health=500,MoveSpeed=5f}});// Add game settings (singleton)provider.AddSingletonConfig(newGameSettings());_configs=provider;Debug.Log("Configs loaded successfully!");}}

Step 3: Use Configs Anywhere

usingGameLovers.ConfigsProvider;publicclassEnemySpawner:MonoBehaviour{[SerializeField]privateGameManager_gameManager;publicvoidSpawnEnemy(intenemyId){// Get specific enemy configvarenemyConfig=_gameManager.Configs.GetConfig<EnemyConfig>(enemyId);// Use the config datavarenemy=Instantiate(enemyConfig.Prefab);varhealthComponent=enemy.GetComponent<Health>();healthComponent.SetMaxHealth(enemyConfig.Health);Debug.Log($"Spawned {enemyConfig.Name} with {enemyConfig.Health} HP");}publicvoidShowAllEnemies(){// Get all enemiesforeach(varenemyin_gameManager.Configs.GetConfigsList<EnemyConfig>()){Debug.Log($"Enemy: {enemy.Name} (ID: {enemy.Id}) - {enemy.Health} HP");}}publicvoidApplyGameSettings(){// Get singleton settingsvarsettings=_gameManager.Configs.GetConfig<GameSettings>();AudioManager.SetVolume(settings.MusicVolume,settings.SfxVolume);TutorialManager.SetEnabled(settings.ShowTutorials);}}

📋 Core Concepts

Singleton vs Collection Configs

Singleton Configs - One instance per type:

// Perfect for game settings, global valuesprovider.AddSingletonConfig(newGameSettings());varsettings=provider.GetConfig<GameSettings>();

Collection Configs - Multiple instances mapped by ID:

// Perfect for items, enemies, levelsprovider.AddConfigs(item =>item.ItemId,itemList);varsword=provider.GetConfig<ItemConfig>(101);

Safe Querying

// Exception if not foundvarconfig=provider.GetConfig<EnemyConfig>(999);// Safe version - returns false if not foundif(provider.TryGetConfig<EnemyConfig>(999,outvarconfig)){// Use config safely}

🛠️ ScriptableObject Workflow

For designer-friendly configuration authoring, use ConfigsScriptableObject<TId, TAsset>. This stores key/value pairs as a serializable list and builds a dictionary on load.

Create the ScriptableObject

usingSystem;usingGameLovers.ConfigsProvider;usingUnityEngine;[Serializable]publicclassEnemyConfig{publicintId;publicstringName;publicintHealth;publicfloatMoveSpeed;publicGameObjectPrefab;}[CreateAssetMenu(fileName="Enemy Configs",menuName="Game/Enemy Configs")]publicclassEnemyConfigs:ConfigsScriptableObject<int,EnemyConfig>{}

Author Data in Inspector

  1. Right-click in Project → CreateGameEnemy Configs
  2. Select the created asset
  3. In Inspector, add entries to the Configs list
  4. Each entry has a Key (int) and Value (EnemyConfig)

Use in Runtime

publicclassConfigLoader:MonoBehaviour{[SerializeField]privateEnemyConfigs_enemyConfigs;privateIConfigsProvider_provider;voidStart(){varprovider=newConfigsProvider();// Option 1: Use ScriptableObject dictionary directlyvargoblin=_enemyConfigs.ConfigsDictionary[1];// Option 2: Feed into main provider for unified accessprovider.AddConfigs(
config =>config.Id,_enemyConfigs.Configs.Select(pair =>pair.Value).ToList());_provider=provider;}}

⚠️ Important Notes:

  • Duplicate keys will throw during deserialization
  • ConfigsDictionary is read-only and built in OnAfterDeserialize
  • Keys must be unique within each ScriptableObject

💾 Serialization & Versioning

Use ConfigsSerializer to serialize providers to JSON for storage or server transfer, with automatic version tracking.

Basic Serialization

usingGameLovers.ConfigsProvider;varserializer=newConfigsSerializer();// Serialize to JSON (e.g., to send to server or save locally)stringjsonData=serializer.Serialize(provider,version:"1.2.3");// Deserialize back into a new provider instancevarrestoredProvider=serializer.Deserialize<ConfigsProvider>(jsonData);Debug.Log($"Restored provider with version: {restoredProvider.Version}");

Exclude Types from Serialization

Mark types that should not be sent to clients/servers:

usingSystem;usingGameLovers.ConfigsProvider;[IgnoreServerSerialization][Serializable]publicclassEditorOnlyConfig{publicstringInternalNotes;publicboolDebugMode;}[Serializable]publicclassPlayerVisibleConfig{publicintMaxLevel;publicfloatExpMultiplier;}

Version Management

// Check current versionDebug.Log($"Current version: {provider.Version}");// Serialize with semantic versioningstringv1_0_0=serializer.Serialize(provider,"1.0.0");stringv1_1_0=serializer.Serialize(updatedProvider,"1.1.0");// Version is automatically converted to ulong for comparisonvarrestored=serializer.Deserialize<ConfigsProvider>(v1_1_0);// restored.Version will be a ulong representation of "1.1.0"

📋 Requirements:

  • Config types must be [Serializable] unless marked with [IgnoreServerSerialization]
  • Uses Newtonsoft.Json with TypeNameHandling.Auto and enum-as-string conversion

🌐 Backend Integration

Integrate with your backend using IConfigBackendService to poll for remote versions and perform atomic config updates.

Implement Backend Service

usingSystem.Threading.Tasks;usingGameLovers.ConfigsProvider;usingUnityEngine;usingUnityEngine.Networking;publicclassMyBackendService:IConfigBackendService{privateconststringBASE_URL="https://your-game-server.com/api/configs";publicasyncTask<ulong>GetRemoteVersion(){usingvarrequest=UnityWebRequest.Get($"{BASE_URL}/version");awaitrequest.SendWebRequest();if(request.result==UnityWebRequest.Result.Success){varversionData=JsonUtility.FromJson<VersionResponse>(request.downloadHandler.text);returnversionData.version;}thrownewSystem.Exception($"Failed to get remote version: {request.error}");}publicasyncTask<IConfigsProvider>FetchRemoteConfiguration(ulongversion){usingvarrequest=UnityWebRequest.Get($"{BASE_URL}/data/{version}");awaitrequest.SendWebRequest();if(request.result==UnityWebRequest.Result.Success){varserializer=newConfigsSerializer();returnserializer.Deserialize<ConfigsProvider>(request.downloadHandler.text);}thrownewSystem.Exception($"Failed to fetch remote config: {request.error}");}[System.Serializable]privateclassVersionResponse{publiculongversion;}}

Sync with Backend

publicclassConfigSyncManager:MonoBehaviour{[SerializeField]privatefloat_syncIntervalSeconds=300f;// 5 minutesprivateConfigsProvider_localProvider;privateIConfigBackendService_backendService;voidStart(){_localProvider=newConfigsProvider();_backendService=newMyBackendService();// Start periodic syncInvokeRepeating(nameof(SyncWithBackend),0f,_syncIntervalSeconds);}privateasyncvoidSyncWithBackend(){try{varremoteVersion=await_backendService.GetRemoteVersion();if(remoteVersion>_localProvider.Version){Debug.Log($"New config version available: {remoteVersion}");varremoteProvider=await_backendService.FetchRemoteConfiguration(remoteVersion);// Atomic update - copy data and bump version_localProvider.UpdateTo(remoteProvider.Version,remoteProvider.GetAllConfigs());Debug.Log($"Successfully updated to version {_localProvider.Version}");// Notify other systems of config updateOnConfigsUpdated?.Invoke();}}catch(System.Exceptionex){Debug.LogError($"Config sync failed: {ex.Message}");}}publicSystem.ActionOnConfigsUpdated;}

📚 API Reference

Core Interfaces

IConfigsProvider

Read-only access to configuration data.

MethodDescriptionExample
ulong Version { get; }Current version numbervar version = provider.Version;
T GetConfig<T>()Get singleton configvar settings = provider.GetConfig<GameSettings>();
T GetConfig<T>(int id)Get config by IDvar enemy = provider.GetConfig<EnemyConfig>(1);
bool TryGetConfig<T>(int id, out T config)Safe get by IDif (provider.TryGetConfig(1, out var enemy)) { }
List<T> GetConfigsList<T>()Get all configs of typevar allEnemies = provider.GetConfigsList<EnemyConfig>();
IReadOnlyDictionary<int, T> GetConfigsDictionary<T>()Get dictionary of configsvar enemyDict = provider.GetConfigsDictionary<EnemyConfig>();
IReadOnlyDictionary<Type, IEnumerable> GetAllConfigs()Get all config datavar allConfigs = provider.GetAllConfigs();

IConfigsAdder : IConfigsProvider

Write access for building configuration data.

MethodDescriptionExample
void AddSingletonConfig<T>(T config)Add singletonprovider.AddSingletonConfig(settings);
void AddConfigs<T>(Func<T, int> keySelector, IList<T> configs)Add collectionprovider.AddConfigs(e => e.Id, enemies);
void AddAllConfigs(IReadOnlyDictionary<Type, IEnumerable> configs)Add bulk configsprovider.AddAllConfigs(configDict);
void UpdateTo(ulong version, IReadOnlyDictionary<Type, IEnumerable> configs)Atomic updateprovider.UpdateTo(42, newConfigs);

ConfigsProvider

Default implementation using in-memory dictionaries.

IConfigsSerializer

JSON serialization interface.

MethodDescriptionExample
string Serialize(IConfigsProvider provider, string version)Serialize to JSONvar json = serializer.Serialize(provider, "1.0");
T Deserialize<T>(string json) where T : IConfigsAdderDeserialize from JSONvar provider = serializer.Deserialize<ConfigsProvider>(json);

ConfigsScriptableObject<TId, TAsset>

Unity-serializable container for designer-authored configs.

PropertyDescriptionExample
List<Pair<TId, TAsset>> ConfigsEditable config pairsEdit in Inspector
IReadOnlyDictionary<TId, TAsset> ConfigsDictionaryRuntime lookup dictionaryvar item = configs.ConfigsDictionary[itemId];

IConfigBackendService

Optional interface for remote config fetching.

MethodDescriptionExample
Task<ulong> GetRemoteVersion()Get latest version from servervar version = await service.GetRemoteVersion();
Task<IConfigsProvider> FetchRemoteConfiguration(ulong version)Fetch config datavar configs = await service.FetchRemoteConfiguration(42);

Helper Interfaces

  • IConfig - Simple interface with int ConfigId { get; }
  • IConfigsContainer<T>, ISingleConfigContainer<T> - Container patterns
  • IPairConfigsContainer<TKey, TValue>, IStructPairConfigsContainer<TKey, TValue> - Pair containers

🎮 Examples

Example 1: RPG Item Database

usingSystem;usingUnityEngine;usingGameLovers.ConfigsProvider;[Serializable]publicclassItemConfig{publicintItemId;publicstringItemName;publicItemTypeType;publicintValue;publicSpriteIcon;publicGameObjectPrefab;// Computed propertiespublicboolIsWeapon=>Type==ItemType.Weapon;publicboolIsConsumable=>Type==ItemType.Consumable;}publicenumItemType{Weapon,Armor,Consumable,Quest}[CreateAssetMenu(fileName="Item Database",menuName="Game/Item Database")]publicclassItemDatabase:ConfigsScriptableObject<int,ItemConfig>{}// Usage in gamepublicclassInventoryManager:MonoBehaviour{[SerializeField]privateItemDatabase_itemDatabase;publicvoidAddItemToInventory(intitemId,intquantity){if(_itemDatabase.ConfigsDictionary.TryGetValue(itemId,outvaritemConfig)){Debug.Log($"Added {quantity}x {itemConfig.ItemName} to inventory");// Add to player inventory...}else{Debug.LogError($"Item ID {itemId} not found in database!");}}}

Example 2: Dynamic Difficulty System

[Serializable]publicclassDifficultyConfig{publicDifficultyLevelLevel;publicfloatEnemyHealthMultiplier;publicfloatEnemyDamageMultiplier;publicfloatPlayerExpMultiplier;publicintMaxEnemiesPerWave;}publicenumDifficultyLevel{Easy=1,Normal=2,Hard=3,Nightmare=4}publicclassDifficultyManager:MonoBehaviour{privateIConfigsProvider_configs;privateDifficultyLevel_currentDifficulty=DifficultyLevel.Normal;voidStart(){varprovider=newConfigsProvider();provider.AddConfigs(d =>(int)d.Level,newList<DifficultyConfig>{new(){Level=DifficultyLevel.Easy,EnemyHealthMultiplier=0.7f,EnemyDamageMultiplier=0.8f,PlayerExpMultiplier=0.8f,MaxEnemiesPerWave=3},new(){Level=DifficultyLevel.Normal,EnemyHealthMultiplier=1.0f,EnemyDamageMultiplier=1.0f,PlayerExpMultiplier=1.0f,MaxEnemiesPerWave=5},new(){Level=DifficultyLevel.Hard,EnemyHealthMultiplier=1.5f,EnemyDamageMultiplier=1.3f,PlayerExpMultiplier=1.2f,MaxEnemiesPerWave=7},new(){Level=DifficultyLevel.Nightmare,EnemyHealthMultiplier=2.0f,EnemyDamageMultiplier=1.8f,PlayerExpMultiplier=1.5f,MaxEnemiesPerWave=10}});_configs=provider;}publicvoidChangeDifficulty(DifficultyLevelnewDifficulty){_currentDifficulty=newDifficulty;varconfig=_configs.GetConfig<DifficultyConfig>((int)newDifficulty);// Apply difficulty settingsEnemyManager.SetHealthMultiplier(config.EnemyHealthMultiplier);EnemyManager.SetDamageMultiplier(config.EnemyDamageMultiplier);ExperienceManager.SetExpMultiplier(config.PlayerExpMultiplier);WaveManager.SetMaxEnemies(config.MaxEnemiesPerWave);Debug.Log($"Difficulty changed to {newDifficulty}");}}

⚡ Performance

Benchmarks

  • Lookup Performance: O(1) for both singleton and ID-based configs
  • Memory Usage: ~50 bytes overhead per config + actual config size
  • Initialization: ~1ms for 1000 configs on average hardware
  • Serialization: ~10ms for 1000 configs to/from JSON

Best Practices

  • Load configs during loading screens - One-time initialization cost
  • Reuse IConfigsProvider instances - Don't recreate providers unnecessarily
  • Use TryGetConfig for optional configs - Avoid exceptions for missing data
  • Cache frequently accessed configs - Store references if accessed every frame
  • Use ScriptableObjects for large datasets - Better for authoring and iteration
  • Don't call GetConfigsList repeatedly - Cache the list if you need it multiple times
  • Don't modify configs at runtime - Treat them as immutable data

Memory Management

// Good: Cache frequently used configspublicclassEnemyAI:MonoBehaviour{privateEnemyConfig_config;// Cached referencevoidStart(){_config=ConfigManager.Instance.GetConfig<EnemyConfig>(enemyId);}voidUpdate(){// Use cached config - no lookup costtransform.Translate(Vector3.forward*_config.MoveSpeed*Time.deltaTime);}}// Bad: Lookup every framepublicclassSlowEnemyAI:MonoBehaviour{voidUpdate(){// DON'T DO THIS - expensive lookup every frame!varconfig=ConfigManager.Instance.GetConfig<EnemyConfig>(enemyId);transform.Translate(Vector3.forward*config.MoveSpeed*Time.deltaTime);}}

🔧 Troubleshooting

Common Issues & Solutions

InvalidOperationException when calling GetConfig<T>()

Problem: Type was not registered as a singleton
Solution: Use GetConfig<T>(id) for collection configs, or register as singleton with AddSingletonConfig<T>

// Wrong - EnemyConfig is a collection, not singletonvarenemy=provider.GetConfig<EnemyConfig>();// ❌ Throws exception// Correct waysvarenemy=provider.GetConfig<EnemyConfig>(1);// ✅ Get by IDvarallEnemies=provider.GetConfigsList<EnemyConfig>();// ✅ Get all

Duplicate Key Exception in ScriptableObject

Problem: Multiple entries with the same key in ConfigsScriptableObject
Solution: Ensure each key is unique in the Inspector

// In Inspector, make sure you don't have:// Key: 1, Value: Enemy1// Key: 1, Value: Enemy2 // ❌ Duplicate key!// Instead use unique keys:// Key: 1, Value: Goblin // ✅// Key: 2, Value: Orc // ✅

Serialization Fails for Custom Types

Problem: Config type is not marked as [Serializable]
Solution: Add [Serializable] attribute or exclude with [IgnoreServerSerialization]

// WrongpublicclassMyConfig{}// ❌ Not serializable// Correct options[Serializable]publicclassMyConfig{}// ✅ Will be serialized[IgnoreServerSerialization]publicclassEditorOnlyConfig{}// ✅ Will be excluded

Newtonsoft.Json Not Found

Problem: ConfigsSerializer requires Newtonsoft.Json
Solution: Install via Package Manager

  1. Open Package Manager
  2. Search for Newtonsoft Json
  3. Install com.unity.nuget.newtonsoft-json

Config Data Not Updating

Problem: ScriptableObject changes not reflected at runtime
Solution:

  • Check that you're loading the correct asset reference
  • Ensure the asset is saved after changes
  • For runtime changes, use ConfigsProvider.UpdateTo() instead

Performance Issues with Large Config Sets

Problem: Slow initialization with thousands of configs
Solution:

  • Use ConfigsScriptableObject for better loading performance
  • Consider lazy loading patterns for very large datasets
  • Split large config sets into multiple smaller ones

❓ FAQ

Q: What's the minimum Unity version?
A: The package.json specifies Unity 6000.0 (Unity 6), but it may work with earlier versions. The package uses standard C# features available in Unity 2021.3+.

Q: Can I use this with Addressables?
A: Yes! Load your ConfigsScriptableObject via Addressables and feed it to the provider:

varhandle=Addressables.LoadAssetAsync<EnemyConfigs>("enemy-configs");varconfigs=awaithandle.Task;provider.AddConfigs(e =>e.Id,configs.Configs.Select(p =>p.Value).ToList());

Q: How do I handle config validation?
A: Implement validation in your config classes or use Unity's OnValidate:

[Serializable]publicclassEnemyConfig{publicintHealth;publicboolIsValid=>Health>0;}// In ScriptableObjectpublicclassEnemyConfigs:ConfigsScriptableObject<int,EnemyConfig>{voidOnValidate(){foreach(varconfiginConfigs){if(!config.Value.IsValid)Debug.LogError($"Invalid config: {config.Key}");}}}

Q: Is this thread-safe?
A: No, the current implementation is not thread-safe. Use it from the main thread only or implement your own synchronization.

Q: Can I modify configs at runtime?
A: Configs should be treated as immutable. For dynamic changes, use UpdateTo() to replace the entire config set atomically.

Q: How do I handle missing optional configs?
A: Use TryGetConfig instead of GetConfig:

if(provider.TryGetConfig<BossConfig>(bossId,outvarbossConfig)){// Boss has custom configSpawnBoss(bossConfig);}else{// Use default boss behaviorSpawnDefaultBoss();}

Q: Can I nest config objects?
A: Yes, as long as all nested types are [Serializable]:

[Serializable]publicclassEnemyConfig{publicintId;publicStatsBaseStats;// ✅ Nested serializable objectpublicList<Ability>Abilities;// ✅ List of serializable objects}[Serializable]publicclassStats{publicintHealth;publicfloatSpeed;}

Q: How do I version my configs for compatibility?
A: Use the version string in serialization and implement migration logic:

varjson=serializer.Serialize(provider,"2.1.0");varrestored=serializer.Deserialize<ConfigsProvider>(json);// Check version and migrate if neededif(restored.Version<expectedVersion){MigrateConfigs(restored);}

🤝 Contributing

We welcome contributions! Here's how you can help:

🐛 Reporting Issues

  • Use GitHub Issues
  • Include Unity version, package version, and minimal reproduction steps
  • For performance issues, include profiler data if possible

🛠️ Development Setup

  1. Clone the repository
  2. Open in Unity 6000.0+
  3. Run tests in Tests/Editor/
  4. Make your changes
  5. Ensure all tests pass
  6. Submit a pull request

📋 Code Guidelines

  • Follow existing code style
  • Add unit tests for new features
  • Update documentation for API changes
  • Use clear, descriptive commit messages

🎯 Areas We Need Help With

  • Performance optimizations
  • Additional serialization formats
  • More comprehensive examples
  • Documentation improvements
  • Unit test coverage

📄 License

This project is licensed under the MIT License - see the LICENSE.md file for details.

What This Means

  • Commercial use - Use in commercial projects
  • Modification - Modify the source code
  • Distribution - Share with others
  • Private use - Use for personal projects
  • Liability - No warranty provided
  • Attribution - Must include license notice

Made with ❤️ for the Unity community

🌟 Star on GitHub🐛 Report Issues🤝 Contribute

About

This package helps manage the loading, unloading and setup of data configs into different set files (ex: ScriptableObjects)

Resources

Stars

1 star

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages