User Data Store
The UserDataStore component can be used to easily save and load user control configuration data from Rewired. This component is a base class which you can extend to support any data storage format you like.
Rewired also comes with multiple implementations complete with source code which you can use as a template for designing your own custom data storage system using any storage medium (database, binary files, etc.). The components can also be used directly in your game.
Usage
Just add a component derived from UserDataStore to your Rewired Input Manager Game Object. When the Rewired Input Manager initializes, it will automatically initialize the UserDataStore component and make a reference to it accessible via the ReInput.UserDataStore property.
- To save all user data: ReInput.userDataStore.Save()
- To load all user data: ReInput.userDataStore.Load()
- UserDataStore API reference
If you need to add any custom members to your UserDataStore-based class, you can do so and simply cast the returned IUserDataStore object from ReInput.userDataStore to your concrete class and then access your custom members.
// A custom class that extends UserDataStore public class MyUserDataStore : Rewired.Data.UserDataStore { // Implement all required methods... public void MyCustomMethod() { // do something } } // In your code that calls your custom method (ReInuput.userDataStore as MyUserDataStore).MyCustomMethod(); // cast to concrete class and call the custom method
Included Component Implementations:
This is a user data storage component that uses Unity's PlayerPrefs class for storing data.
See this for information that applies to all included implementations of UserDataStore.
Limitations:
PlayerPrefs itself has significant limitations and negatives, for example, it isn't possible to clear only Rewired's save data from PlayerPrefs without wiping out all other PlayerPrefs data. If this is something you anticipate needing to do for whatever reason, do not use UserDataStore_PlayerPrefs and instead implement your own extension of the UserDataStore class that saves/loads data to whatever storage system you desire so you can have more control over how data is stored and managed.
PlayerPrefs may not work at all or using it may have unforseen consequences on certain console platforms due to limitations in Unity's design, so be aware of these possible issues when deciding how you want to store user data.
If you need to save which Controller Maps are currently assigned to a Player, for example if you've manually loaded an alternate layout at some point and you want that new layout to be loaded the next time you call UserDataStore.Load instead of the default defined in the Rewired Input Manager, you will have to make a new UserDataStore class extension that can handle these special needs. Copy the UserDataStore_PlayerPrefs, change the class name, and make any modifications necessary to what data is saved and loaded.
Clearing saved data:
Use the Clear All Player Prefs button in the Debug Options foldout on the UserDataStore_PlayerPrefs inspector. WARNING: This will clear ALL PlayerPrefs data for the current project. This is due to the limitation that there is no way to look up what keys exist in PlayerPrefs.
This is a user data storage component that uses a local file for storing data.
See this for information that applies to all included implementations of UserDataStore.
By default, data is saved as a JSON file to Application.persistentDataPath. If you need to store data in a different location (cloud storage, etc.), you can extend the class and change the save path and/or use your own data handler.
Data can be stored as text or binary (compressed text using LZF compression algorithm).
Extending the class:
If you want to save data to somewhere other than Application.persistentDataPath or you want to save data in a different format, you should extend the class and implement your own data handler.
If you need to save data in a different format or in different locations on different build targets, you can do that in your implementation.
A simple example implementation is as follows:
using UnityEngine; using Rewired.Data; using System.IO; using System; using System.Text; namespace MyNamespace { public class UserDataStore_CustomFile : UserDataStore_File, UserDataStore_File.IDataHandler { // Add a customizable sub directory for this example [SerializeField] private string _directoryName = "Rewired"; // Override this method to set your own custom values before initialization protected override void SetInitialValues() { base.SetInitialValues(); // Set a custom save directory if (!string.IsNullOrEmpty(_directoryName)) { directory = Path.Combine(Application.persistentDataPath, _directoryName); } // Set the data handler to handle load, save, and clear dataHandler = this; } // Implement your own Load, Save, and Clear handlers. // This example just saves as UTF-8 encoded text.
// Called when data is loaded public bool Load(string absoluteFilePath, out string data) { data = null; if (string.IsNullOrEmpty(absoluteFilePath)) return false; if (!File.Exists(absoluteFilePath)) return false; try { switch (dataFormat) { case Rewired.Data.UserDataStore_File.DataFormat.Binary: { data = Encoding.UTF8.GetString(File.ReadAllBytes(absoluteFilePath)); break; } case Rewired.Data.UserDataStore_File.DataFormat.Text: { data = File.ReadAllText(absoluteFilePath); break; } default: throw new NotImplementedException(); } return !string.IsNullOrEmpty(data); } catch (System.Exception ex) { UnityEngine.Debug.LogError(ex); return false; } } // Called when data is saved public bool Save(string absoluteFilePath, string data) { if (string.IsNullOrEmpty(absoluteFilePath)) return false; try { if (!Directory.Exists(Path.GetDirectoryName(absoluteFilePath))) { Directory.CreateDirectory(Path.GetDirectoryName(absoluteFilePath)); } switch (dataFormat) { case Rewired.Data.UserDataStore_File.DataFormat.Binary: { File.WriteAllBytes(absoluteFilePath, Encoding.UTF8.GetBytes(data)); Debug.Log("Wrote file: " + absoluteFilePath); return true; } case Rewired.Data.UserDataStore_File.DataFormat.Text: { File.WriteAllText(absoluteFilePath, data); Debug.Log("Wrote file: " + absoluteFilePath); return true; } default: throw new NotImplementedException(); } } catch (System.Exception ex) { UnityEngine.Debug.LogError(ex); return false; } } // Called when save data is cleared public bool Clear(string absoluteFilePath) { if (string.IsNullOrEmpty(absoluteFilePath)) return false; try { if (File.Exists(absoluteFilePath)) { File.Delete(absoluteFilePath); #if UNITY_EDITOR UnityEngine.Debug.Log("Deleted " + absoluteFilePath); #endif return true; } } catch (System.Exception ex) { UnityEngine.Debug.LogError(ex); } return false; } } }
Limitations:
Some some versions of Unity may not support saving local files on certain build targets. In addtion, if a platform requires data be saved to the cloud, this component cannot be used without extending the class and implementing your own data handler that does the saving/loading.
Does not support asynchronous file handling.
Clearing saved data:
Use the Clear Data button in the Debug Options foldout on the UserDataStore_File inspector in the editor, call UserDataStore_File.ClearSaveData in a script, or manually delete the file.
Important information common to all included UserDataStore component implementations:
Add one of the included component implementations of UserDataStore to the Rewired Input Manager Game Object to save and load user data.
Whenever a controller is attached, if any data has been saved before for that controller, it will be loaded. If the user has customized his control mappings, these will be loaded on a per-player, per-controller basis. Controller calibration settings and customized Input Behavior settings will also be loaded. Data will be saved manually when Save() is called or automatically when a controller is disconnected from the system.
If "Load Data on Start" is checked in the inspector, all controller data will be loaded at the beginning of the session. This is useful if you want the player's last settings to be loaded automatically for any controllers already attached to the system at runtime.
Limitations:
These component implementations are not the be-all, end-all, automatic data storage system. They have limitations. They do not fully automate everything so you can just set it and forget it. They provide an interface for you to save/load data as necessary for the needs of your game. This sometimes requires manual calls to functions to make data save or load at a particular time. Functionality beyond what is described above is up to the user to implement if desired. These implementations are minimum viable products designed for the most common use case needs and was primarily designed for Control Mapper.
Data that is saved and loaded
These implementations do not take a snapshot of the entire current Player state.
Saved data does not include:
- The current list of what Controller Maps are loaded in the Player.
- The enabled state of these Controller Maps.
These implementations save:
- Joystick calibration settings for attached Joysticks.
- Input Behavior settings for each Player.
- Bindings for each Controller Map found in each Player.
- Optionally, controller assignments for mouse, keyboard, and joysticks for each Player.
These implementations load:
- Joystick calibration settings for attached Joysticks.
- Input Behavior settings for each Player.
- All saved Controller Maps found for each Player.
- Optionally, controller assignments for mouse, keyboard, and joysticks for each Player.
When do these implementations automatically load data:
- If "Load Data on Start" is enabled, on Awake.
- When a Joystick is connected. This only applies if Joystick Auto Assignment is enabled and the Joystick is assigned to the Player.
When do these implementations automatically save data:
- If one or more of "Load Joystick Assignments", "Load Keyboard Assignments", or "Load Mouse Assignments" and "Load Data on Start" are enabled, on Awake, controller assignments will be saved after data has been loaded.
- When a Joystick is disconnected.
Warning:
Loading saved data is subject to the normal functioning of the Controller Map system. As is documented, Joystick Maps cannot exist in a Player unless that Joystick is connected and assigned to that Player at the time of loading. That means, if saved user data is loaded when a Joystick is not currently assigned to the Player, no saved data will be loaded for that Joystick. Only if the Joystick is first assigned to the Player will the data be loaded for that Joystick in that Player when Load is called. Joystick Maps are not automatically loaded from saved user data when you assign a Joystick to a Player or change Joystick assignments between Players.
IMPORTANT: Saved data is not updated when you make changes to the Rewired Input Manager
UserDataStore does not manage changes between the Rewired Input Manager and data that is already saved. If you make changes to the Rewired Input Manager settings such as adding new controls to a Joystick Map, these new changes will not be preserved when loading saved data. The only automated solutions would be to either clear the saved data so that the Rewired Input Manager defaults are used instead, or load the default maps in the Player for any controllers that changed and save those, overwriting the existing saved mappings.
Management of saved user data is up to the developer. If you have special needs beyond the basic use cases, you should extend and replace the UserDataStore component with a new component that meets your specific needs.
During development, you may run into a situation where your controls don't seem to make sense. This may happen when you make some runtime control changes, save them, and then proceed to change your mappings in the Rewired Input Manager. Because the included implementations of UserDataStore are configured to save controller data on disconnect and load controller data on start and controller connect, the loaded settings will override new changes you make to the default mappings in the Rewired Input Manager.
During development, it may be useful to disable or remove the UserDataStore component. If you've already saved controller settings and want to remove them, you can delete the saved data. See the documentation for the specific implementation you are using for more information.