Search Unity

Unified Settings & Game Options

Discussion in 'Assets and Asset Store' started by _geo__, Jan 6, 2023.

  1. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Links: Asset Store, Manual

    A settings template with one unified interface for all render pipelines (URP, HDRP, Built-in) and input systems (old and new).
    CoverImage_1950x1300.png

    Screenshot1_2048x1152.png Screenshot2_2048x1152.png Screenshot3_2048x1152.png Screenshot4_2048x1152.png



    Features

    ✔️ URP, HDRP and Built-in supported

    ✔️ Old and new input system supported

    ✔️ Lots of predefined settings (full list below)

    ✔️ Mouse & keyboard, controller & gamepad, touch supported

    ✔️ Edit and save key-bindings (supports the OLD and the NEW input system)

    ✔️ No coding skills required (Scriptable Object based workflow)

    ✔️ Prefab based UI (easy to tweak). In fact you are getting a whole modular UI library. You don't like it? Well, okay, no problem. It's built to be ripped out if need be.

    ✔️ UI Toolkit Support

    ✔️ Localization built-in (easy to extend with assets like "I2 Localization")

    ✔️ Saves the user settings in PlayerPrefs (easy to change via code if needed)

    ✔️ Scripting API (for the coders among you)

    ✔️ Full Source Code included!

    ✔️ Supports Unity 2020, 2021, 2022, ... (It may work in Unity 2019 too but that's not officially supported.)


    List of Settings
    There is an extensive list of predefined custom settings. You can also invent your own or simply hook up a primitive type with any method in your game. All of them support HDRP, URP and Built-in renderers.


    • Basic Types: Bool, Int, Float, String - Generic settings to easily create custom settings.
    • Colors - Save and load any color value.
    • ColorOptions - Let the user pick from a list of colors.
    • Options - If you want the player to choose only from a limited set. You give it a list of names (A, B, C) and it tells you with an index (0,1,2) which option the player selected.
    • Key Combination - Used for key-bindings for example. Supports old and new key codes and key combinations.
    • Ambient Light - Controls the ambient light intensity.
    • Ambient Occlusion (SSAO) - On/Off for Screen Space Ambient Occlusion. Please check the manual, there are some caveats with this one.
    • Anti Aliasing - Selectable options are based on your renderer settings.
    • Audio Paused - On/Off for Audio: Pauses the Audio Listener (useful for global audio on/off).
    • Audio Volume - Controls the Audio Listener volume (useful for global audio volume).
    • Audio Source Volume - Controls the volume of one or more specific AudioSource Components.
    • Bloom - On/Off for the bloom post processing effect.
    • Depth Of Field - On/Off for the depth of field post processing effects.
    • Frame Rate - Options to control the target frame rate. Default options are: 30, 60 and 120.
    • Full Screen - On/Off of for full screen mode.
    • Gamma - Range for the gamma correction post processing effect (-1 to +1).
    • Motion Blur - On/Off for the motion blur post processing effect. Notice: URP does not have a per-object motion blur. More on that in the manual.

    • Monitor - Allows you to switch the display monitor of the main window. ⚠️ NOTICE: This requires Unity 2021.2 or higher since that's when Unity added the monitor switching API.

    • Quality - Changes the global quality setting. Options are taken from the graphics quality settings automatically.
    • Refresh Rate - Options for monitor refresh rates. Options are taken from the refresh rates supported by the monitor.
    • Resolution - Options for the game resolution. Options are taken from the resolutions supported by the monitor.
    • Shadow - On/Off for shadows (and contact shadows if you use HDRP).
    • Shadow Distance - Options for max shadow distance. The options are based on your graphics quality settings.
    • Shadow Resolution - Options for max shadow map resolutions. The options are based on your graphics quality settings. Notice: the shadow resolution is spread out over the shadow distance. Thus the highest shadow resolution with the lowest shadow distance gives the best quality (that's a little counter intuitive, I know).
    • Textfield - Let the player enter a name or something else.
    • Texture Resolution - Options for texture resolutions. The default options are: full-res, 1/2 res, 1/4 res, 1/8 res.
    • Vignette - On/Off for the vignette post processing effect.
    • V-Sync - On/Off for vertical sync.
    • Window Mode - Use this if you need more control than just "full screen on/off". Otherwise use the "Full Screen" setting. You rarely need this.
    Hope you like it :)
     
    Last edited: Mar 2, 2023
    hjohnsen likes this.
  2. Weendie-Games

    Weendie-Games

    Joined:
    Feb 17, 2015
    Posts:
    75
    Congrats on the release. Maybe i'll buy this because right now i'm reworking all the settings / quality scripts from my game, but i have a couple of questions.

    - The key binding works with Rewired? If not, how hard is to integrate with it?

    - Is possible to use some kind of "Preset" dropdown? Which change all the others quality / settings controls?
     
    _geo__ likes this.
  3. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi, thanks for your interest in the asset :)

    The key bindings work with Rewired?

    > Not out of the box, sorry, though it should work fine along side Rewired or InControl.
    It converts old and new key codes into a unified key code enum (basically an int) and then uses that enum internally. So if you write some code that converts from Rewired button codes to Universal key codes it should work just fine. Might be a nice feature for my next update.

    If you want to take a stab at it yourself then look into the "InputUtils" classes. That's where the key code conversions are done. Especially "InputUtils.InputSystem.cs" should be of interest to you as it uses the new InputSystem which borrows a lot of naming conventions from Rewired and InControl. If you add a Rewired define then you should be able to add your own InputUtils.Rewired.cs specifically for Rewired (that's how I would do it).

    Is possible to use some kind of "Preset" dropdown?

    > Hm, interesting. I fear I also have to answer this with "Not out of the box". But the good news is that you can definitely build this via the scripting API.
    The default "quality" dropdown uses the settings from the QualitySetting set in the project settings, but I don't think you mean that. Each settings also has a default value which you can reset it to (if the users messes things up). But I think that's not what you need either.

    Can you please describe what exactly you want to use this for. I am curious. Do you really want to change ALL the settings with a preset?

    All the settings have a scripting API, so you can make a "presets" dropdown (Options setting) and then react to changes to that. A change can then trigger any code you want. You would have to manage the preset values (which to set the settings to) yourself. You then look them up and assign them to each setting in a loop (don't forget to call RefreshRegisteredResolvers() to update the UI).
    Theoretically you could also use multiple Settings.asset files for that and just swap them out and then pull the settings (haven't tested that tbh). It's an interesting use case. I'll look into that (bit short on time at the moment, so don't hold your breath).

    For graphics settings I'd recommend to stick with the Quality Settings workflow in the project settings. Especially if you are on URP or HDRP. The render pipelines are tightly coupled with the renderer assets. Unity really encourages everyone to use those for presets. Read "encourages" as "makes it hard to do anything else by keeping parts of the API private". Also shader stripping (usually a good thing) makes this hard, especially for PostProcessing effects. It's a bit sad but if you try to ship your own graphics presets outside of the renderer assets you will run into trouble quickly (SSAO being a prime example). I have a section in the manual on that specifically.

    I hope I've answered your questions.
     
    Last edited: Jan 10, 2023
    Weendie-Games likes this.
  4. Weendie-Games

    Weendie-Games

    Joined:
    Feb 17, 2015
    Posts:
    75

    For real, i'm just trying to get my head around the quality settings on SRP (HDRP in my case).

    I have 5 Render Pipeline asset (potato, low, med, high and custom), i was thinking about preventing players from change settings on all quality levels but "custom" one. I find not very intuitive that each quality level can have many options to tweak like shadow resolution, light etc.

    But anyway i'll give a try to implement your asset, i guess this is the right way to choose quality settings on SRP
     
  5. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    In that case I would listen to changes to the quality settings option and lock/disable the UI of all the other settings.

    Look into the QualityConnection.cs (resp. the QualityConnection.asset). You can listen to changes in any connection via
    AddChangeListener(IConnection<TValue>.OnChangedDelegate listener)
    (see Connection.cs).
     
    Weendie-Games likes this.
  6. drhousemd

    drhousemd

    Joined:
    Dec 6, 2012
    Posts:
    25
    looks interesting, I was wondering about 3 things:
    - does this work with Android? how would it be different between PC and mobile, what changes for mobile?
    - when showing the key remapping feature, does that work out of the box (keyboard, controller, touchscreen) or do we need to implement Rewired/InControl?
    - can this be used with Visual Scripting (formerly Bolt)?
     
    _geo__ likes this.
  7. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi, thanks for asking.

    Does this work with Android?
    Yes
    , it does not use any platform specific code.Therefore it should work on any platform. I have tested it on: Win, Mac, Android, iOS. Caveat: For mobile be aware that the PostProcessing is tricky (especially if you use the Built-In render pipeline, most Buillt-In PostPro effects don't work there, use URP instead).

    Does the key remapping feature work out of the box?
    Yes
    , it works right out of the box. I have tested it with Keyboard + Mouse, Touch and an xbox controller.

    Do we need to implement Rewired / InControl?
    The answer depends on whether you are using the old or the new InputSystem.

    Old Input System: It supports the xbox controller right out of the box and uses that mapping for all other controllers too (so there may be a mismatch of some buttons but in general it should work). I have not tested it with VR controllers (due to a lack of owing some), not sure how they behave. If anyone knows I'd be glad to know.

    New Input System: That's the recommended way as it has a solid input abstraction built in (basically what Rewired and InControl did for the old system). Though I understand if you want to keep using Rewired as switching integrations is always a pain.

    Having Rewired and InControl integrated out of the box is something I will be looking into.

    Can this be used with Visual Scripting
    Yes
    , but at the moment it requires some manual setup (let BOLT know the Settings exist). I am looking into how to automate this.

    Here are the setup steps:
    1) Add Kamgam.SettingsGenerator to the "Node Library"
    2) Add the Settings Types (SettingsProvider, Settings, all the Setting..) to the "Type Options"
    3) Hit "Regenerate Nodes" to apply the changes.
    upload_2023-1-13_11-15-42.png

    You can then retrieve any setting via its ID.
    It looks like this (a simple example which disables the object if audio is disabled):
    upload_2023-1-13_11-8-19.png


    If you want you can also add each Connection individually. Though that's very cumbersome as you would have to add each Connection type to the types list by hand.
    upload_2023-1-13_10-51-54.png

    I hope I have answered everything. If you have further questions please don't hesitate to ask again :)
     
    Last edited: Jan 13, 2023
    drhousemd likes this.
  8. jnbbender

    jnbbender

    Joined:
    May 25, 2017
    Posts:
    487
    I have not purchased yet but I am most interested in the HDRP settings. How easy is it to add settings for things like Dynamic Resolution (DLSS, FSR), Microshadows, etc.
     
    _geo__ likes this.
  9. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Thanks for your interest. Interesting topic.

    If your question is if there already is some premade code for DLSS and FSR modification then I am sorry. I have not (yet) implemented DLSS or FSR. However you can add custom connections easily. UPDATE: It now supports DLSS and FSR via a third party integration (Alterego Games).

    I'll try to give you a tutorial. I think I'll also add a section to the manual since that's still not explained there (though there is a fully documented sample scene with scripts in the asset).

    First, there are two ways to connect a setting to your custom code (A and B).

    A: Custom Code Tutorial (using the GetSetConnection<T>)

    There is a premade Connection called GetSetConnection. You can use it to register two methods. One to get the value from the setting and one to send the value to the setting.

    The code would look like this (from the code example in the asset):
    Code (CSharp):
    1. /// <summary>
    2.  
    3. /// A simple int for a slider from 0 to 100 (the range is defined in the UI).
    4. /// It defines a percentage of how strong the health regeneration should be.
    5. /// </summary>
    6. protected int _healthRegeneration; // Instead of healthRegeneration this could be super-sampling scale factor X.
    7.  
    8. protected void addHealthRegenerationPercentage(Settings settings)
    9. {
    10.     // This setting will react to changes in the setting and propagate those
    11.     // to a local field "_healthRegeneration".
    12.     //
    13.     // To connect a setting (data) with some logic we use Connection objects.
    14.     // These are very simple. They have a Get() and a Set(value) method.
    15.     //
    16.     // Get() means getting a value from the connection and saving it within the setting (pull).
    17.     // Set(value) means sending a new value to the connection (push).
    18.     // There are many specialized predefined Connections (like the "FrameRateConnection").
    19.     //
    20.     // For this example we use a simple generic GetSetConnection<T> connection.
    21.     // This connection does nothing except forward Get() and Set(value) calls to
    22.     // some other methods (getter and setter).
    23.  
    24.     var connection = new GetSetConnection<int>(
    25.         getter: getHealthRegeneration, // executed if connection.Get() is called.
    26.         setter: setHealthRegeneration  // executed if connection.Set(value) is called.
    27.     );
    28.  
    29.     // Now that we have our connection we need to hook it up with our setting.
    30.     // In fact at first boot we also have to create our setting. Luckily there
    31.     // is a handy GetOrCreateInt() method so we don't have to worry about that.
    32.     var healthSetting = settings.GetOrCreateInt(
    33.  
    34.         // Each setting needs an ID.
    35.         id: "healthRegeneration",
    36.  
    37.         // The default value is the fallback default value used if no connection is
    38.         // set. In this case we are using a connection and the default value is pulled
    39.         // initially from that connection. Therefore we actually don't need to specify it.
    40.         // defaultValue: false
    41.  
    42.         // We want to use a connection to get/set the values.
    43.         connection: connection
    44.     );
    45.  
    46.     // If all you need is to listen for changes in a setting then you may not even need a
    47.     // Connection object. There is a healthSetting.AddChangeListener() method which you
    48.     // can use for that.
    49. }
    50.  
    51. // This simply returns the current state of "_healthRegeneration".
    52. // This getter is called at the very first use of the setting
    53. // and the return value will be stored as the default value (used
    54. // if you call setting.ResetToDefault()).
    55. //
    56. // It may also be called at any time by the settings system and
    57. // should return the current state of the value in your game.
    58. //
    59. // If this value is changed from outside the settings system, then
    60. // you need to call setting.PullFromConnection() to update the interal
    61. // value of the setting.
    62. //
    63. // "Pull" in this context is meant as from the view point of the setting.
    64. // I.e. "pull the value from the connection into the setting and update the UI".
    65. // During this pull process connection.Get() is called which calls
    66. // this getter.
    67. //
    68. // There is also a setting.PushToConnection() method which does to opposite.
    69. // It pushes the value from the setting into the connection (connection.Set())
    70. protected int getHealthRegeneration()
    71. {
    72.     // This is where you would have to reduce the current DLSS and/or FSR state into one number (scale for example).
    73.     return _healthRegeneration;
    74. }
    75.  
    76. // This simply sets the local field and logs the new value.
    77. protected void setHealthRegeneration(int value)
    78. {
    79.     // This is where you would have to modify the current DLSS and/or FSR state based on the given value.
    80.     _healthRegeneration = value;
    81.     Debug.Log("Health regeneration has been set to: " + value);
    82. }

    B: Custom Code Tutorial (making a custom Connection class)
    The settings system reduces any setting into basic types (bool, Color, float, int, string, ...). To connect a setting to some custom code you have to implement an interface called IConnection<T>.

    The interface is really simple:
    Code (CSharp):
    1.  
    2.     public interface IConnection<TValue> : IConnection
    3.     {
    4.         public delegate void OnChangedDelegate(TValue value);
    5.  
    6.        // This is where all the magic happens.
    7.         public TValue Get();
    8.         public void Set(TValue value);
    9.  
    10.        // Don't worry. There is a base class implementing these for you (see below).
    11.         public void AddChangeListener(OnChangedDelegate listener);
    12.         public void RemoveChangeListener(OnChangedDelegate listener);
    13.     }
    14.  
    You need to create a new Connection class implementing that interface. All the premade connections are made like this too. Here is the VSync connection for example:
    Code (CSharp):
    1. public class VSyncConnection : Connection<bool>
    2.     {
    3.         public override bool Get()
    4.         {
    5.             return QualitySettings.vSyncCount != 0;
    6.         }
    7.  
    8.         public override void Set(bool vSyncEnabled)
    9.         {
    10.             QualitySettings.vSyncCount = vSyncEnabled ? 1 : 0;
    11.             NotifyListenersIfChanged(vSyncEnabled);
    12.         }
    13.     }
    You may have noticed that it does not implement the IConnection interface directly but instead extends a generic class
    Connection<bool>
    (where bool is the type of what the
    Get()
    method returns and what the
    Set(value)
    takes as parameter).

    Using the generic base class spares you the work of implementing
    AddChangeListener()
    etc. . Just override Get and Set(value) and you have a fully functional connection.

    Now this is a complete Connection and you can use it in code. BUT you can not yet use your new Connection in the ScriptableObject Assets (Settings.asset). To enable this you will also have to implement a Scriptable Object for your Connection. We can use some of our base classes to spare us typing all the repetitive code.
    Here is how the SO class for the VSyncConnection looks like:
    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. namespace Kamgam.SettingsGenerator
    4. {
    5.     [CreateAssetMenu(fileName = "VSyncConnection", menuName = "SettingsGenerator/Connection/VSyncConnection", order = 1)]
    6.     public class VSyncConnectionSO : BoolConnectionSO
    7.     {
    8.         protected VSyncConnection _connection;
    9.  
    10.         public override IConnection<bool> GetConnection()
    11.         {
    12.             if(_connection == null)
    13.                 Create();
    14.  
    15.             return _connection;
    16.         }
    17.  
    18.         public void Create()
    19.         {
    20.             _connection = new VSyncConnection();
    21.         }
    22.     }
    23. }
    24.  
    Now you can create an SO Asset and use it for any setting matching the type (bool in this case).

    If you are not a coder then maybe you are able to do it with the VisualScripting package and the GetSetConnection, though it's cumbersome compared to the code solution.

    Now back to the question of "DLSS and FSR". To support those you would have to make a connection and then access the HDRP API for those features in the Get() or Set() method. Get() has to return the current state baked into a simple type (int, float, ...) and Set() has to take that simple value and then change the state accordingly.

    I hope that was understandable.
    If you have any further questions then please don't hesitate to ask again.

    If I find the time I'll take a look into adding DLSS and FSR out of the box (no promises though, am pretty busy at the moment). If you happen to implement these connections yourself I'd be very interested in how the "connection workflow" worked for you.

    Thank you
     
    Last edited: Apr 21, 2024 at 10:18 PM
  10. fiz192

    fiz192

    Joined:
    Jan 22, 2021
    Posts:
    3
    Hi, Bought this awesome product. Very easy to setup and covers most of the settings in standard game.

    Hooking up the connections is also easy.

    I have one problem. I want to enable player to change which monitor they want to use but I'm not able to find any solution at the moment. I get to the point that it enables a second display with

    Display.displays[1].Activate();
    Camera.main.targetDisplay = 1;

    But these only enables multi-display. How do make it switch instead of just activating an extra monitor?
     
    _geo__ likes this.
  11. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi,
    thank you for using my asset :)

    1) Welcome to the Unity forum !

    2) Switching monitors has been a difficulty thing to implement in Unity for a long time. A proper API landed in a preview version (2021.2.0a16) about two years ago. Here is the thread about it: https://forum.unity.com/threads/switch-monitor-at-runtime.501336/#post-7087321

    I think this is the right API to use:
    https://docs.unity3d.com/ScriptReference/Screen.MoveMainWindowTo.html

    Here you can find the original code sample the Unity employee posted: https://github.com/Unity-Technologies/DesktopSamples/tree/master/MoveWindowSample

    I'd recommend reading through the whole forum thread. There still seems to be some area of debate.

    Adding a "switch monitor" connection it pretty high up on my to-do list (am looking at it right now). Stay tuned ;-)
     
    fiz192 likes this.
  12. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Okay, this took longer than I thought but here it is:
    https://kamgam.com/unity/SG-1.4.1-MonitorConnection.unitypackage

    CAVEAT: Works only with Unity 2021.2+ since that's when Unity added the proper API.

    You can download and import that packge. It contains the two script files and the connection asset. If you hook it up with and OPTIONS settings you will get a dropdown with a list of the connected monitors + resolution to choose from.
    upload_2023-2-11_16-39-49.png

    It'd recommend you set "Apply Immediately" to OFF for this one (just like the resolution setting).
    upload_2023-2-11_16-39-0.png

    Please let me know if that works for you. Oh and if you can please leave a review in the Asset Store (it really helps).

    The Monitor Connection will be available to all in the 1.4.1 Update which I just submitted. Usually that's online in about 5 days.

    Here is the changelog of 1.4.1:
    • New Switch Monitor Connection ("MonitorConnection") - Allows you to switch monitors in-game. CAVEAT: This requires Unity 2021.2 or never since that's when Unity added the API.
    • Disabling Domain-Reload is now supported, enjoy :).
    • Fixed an error when fetching default values from connections (thanks to zhepama for reporting it).
    • Fixed the "AmbientOcclusion renamed to ScreenSpaceAmbientOcclusion" warning in 2022.2+
    • Settings now have a SetDefault(value) method so you can override default values if needed.
    • Connections now have an explict Destroy() method which you can override for reset purposes if Domain-Reload is deactivated.
    • The Localization Inspector now shows the current active language.
    • Connections now have a GetDefault() method which can be overridden if needed.
    • InitializeConnection() does no longer call PullConnection() and therefore does no longer trigger event listeners.
    Cheers!
     
    Last edited: Feb 11, 2023
    fiz192 likes this.
  13. fiz192

    fiz192

    Joined:
    Jan 22, 2021
    Posts:
    3
    Yes this works very well. :D I had to modified the referesh rate connection a bit so it could update upon changing the to different monitor.

    Thank you for guiding this through
     
    _geo__ likes this.
  14. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Glad it's working :)

    Oh, what exactly didn't work as it should? I think the resolution options might need to be refreshed once the monitor was changed, was that it? Would you mind sharing the fix?
     
    Last edited: Feb 12, 2023
  15. fiz192

    fiz192

    Joined:
    Jan 22, 2021
    Posts:
    3
    Yes it just requires refreshing after the monitor was changed. I just removed the == null check. Since its not checked every frame figure its not going to cause much problem

    Here is my code. And yea I had to use the override version on

    Code (CSharp):
    1. public partial class RefreshRateConnectionOverride : RefreshRateConnection
    2.     {
    3.         protected override List<int> getRefreshRatesForCurrentResolution()
    4.         {
    5.  
    6.    
    7.             // if (_values == null)
    8.             // {
    9.             //     _values = new List<int>();
    10.             //     _values.Add(Screen.currentResolution.refreshRate);
    11.  
    12.             //     var resolutions = Screen.resolutions;
    13.             //     foreach (var res in resolutions)
    14.             //     {
    15.             //         if (res.width == Screen.currentResolution.width
    16.             //             && res.height == Screen.currentResolution.height
    17.             //             && !_values.Contains(Screen.currentResolution.refreshRate))
    18.             //         {
    19.             //             _values.Add(Screen.currentResolution.refreshRate);
    20.             //         }
    21.             //     }
    22.             // }
    23.  
    24.             //setting up this way so it refreshes when required
    25.             _values = new List<int>();
    26.             _values.Add(Screen.currentResolution.refreshRate);
    27.  
    28.             var resolutions = Screen.resolutions;
    29.             foreach (var res in resolutions)
    30.             {
    31.                 if (res.width == Screen.currentResolution.width
    32.                     && res.height == Screen.currentResolution.height
    33.                     && !_values.Contains(Screen.currentResolution.refreshRate))
    34.                 {
    35.                     _values.Add(Screen.currentResolution.refreshRate);
    36.                 }
    37.             }
    38.  
    39.             return _values;
    40.         }
    41.  
    42.         public override List<string> GetOptionLabels()
    43.         {
    44.             // if (_labels == null)
    45.             // {
    46.             //     _labels = new List<string>();
    47.  
    48.             //     var refreshRates = getRefreshRatesForCurrentResolution();
    49.             //     foreach (var rate in refreshRates)
    50.             //     {
    51.             //         string name = rate.ToString() + " " + _rateNameInOptionLabel;
    52.             //         _labels.Add(name);
    53.             //     }
    54.             // }
    55.             _labels = new List<string>();
    56.  
    57.             var refreshRates = getRefreshRatesForCurrentResolution();
    58.             foreach (var rate in refreshRates)
    59.             {
    60.                 string name = rate.ToString() + " " + _rateNameInOptionLabel;
    61.                 _labels.Add(name);
    62.             }
    63.  
    64.             return _labels;
    65.         }
    66.     }
    67.  

    and this is the modification on ConnectionSO

    Code (CSharp):
    1. namespace Kamgam.SettingsGenerator
    2. {
    3.     [CreateAssetMenu(fileName = "RefreshRateConnection", menuName = "SettingsGenerator/Connection/RefreshRateConnection", order = 4)]
    4.     public class RefreshRateConnectionSO : OptionConnectionSO
    5.     {
    6.         protected RefreshRateConnectionOverride _connection;
    7.  
    8.         public override IConnectionWithOptions<string> GetConnection()
    9.         {
    10.             if(_connection == null)
    11.                 Create();
    12.  
    13.             return _connection;
    14.         }
    15.  
    16.         public void Create()
    17.         {
    18.             _connection = new RefreshRateConnectionOverride();
    19.         }
    20.     }
    21. }
    22.  
     
    _geo__ likes this.
  16. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Thank you, yes once you mentioned it I thought that might be it. The system does not yet have a mechanism to trigger a change in another setting if one setting changes. I'll have to think about that. Thanks for sharing.
     
    Last edited: Feb 14, 2023
    fiz192 likes this.
  17. Da_Neel

    Da_Neel

    Joined:
    Dec 29, 2013
    Posts:
    15
    Hi. For some reason, only single one audio source could be controlled with audioMusicVolume ID of AudioSourceVolumeConnectionComponent.
    What am I missing here?

    Invoice No. IN010102065397
     
    _geo__ likes this.
  18. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi,
    thanks for using my asset. Oh, you are right. It updates only one if the sources are spread across multiple objects.

    I have made a patch for you now (just two files):
    https://kamgam.com/unity/SG-1.5.1-AutioVolume-patch.unitypackage

    I'll still have to test it thoroughly but it seems to work in the quick example test I made.

    For anyone interested. These are the cases that did work:

    One audio scource (working):
    upload_2023-2-24_22-24-24.png

    Two audio sources one the same object (also working):
    upload_2023-2-24_22-23-30.png

    It failed if there were more than one GAME OBJECT which had AudioSourceVolumeComponents on them with the same ID. That's fixed in the patch. Once I have the confirmation from Da_Neel I'll submit it for review.

    Thanks for reporting this @Da_Neel .
    I hope the patch works for you (please let me know).
     
  19. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Good news everyone, UI Toolkit support has been added. I've submitted it for review today (should be available in a couple of days). You can already take a look at how it works in the manual :cool:
     
  20. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Here is an implementation for an AudioMixer Connection. I was asked if I could provide one. It will be added in the next release.

    It requires you to expose the parameters for modification and you will need one Connection per parameter.
    upload_2023-3-20_10-48-58.png
    If you double-click the parameter in the dropdown you can rename it.
    upload_2023-3-20_10-49-31.png
    The connection will need the name of the parameter so it can find it.
    upload_2023-3-20_10-49-54.png

    upload_2023-3-20_10-50-25.png

    Be careful with the values you plugin into it. Don't start off with 20dB Volume! Your audio equippement may not like that too much.

    Here is the code. Two classes to copy & paste.

    AudioMixerParameterConnection.cs
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Audio;
    4.  
    5. namespace Kamgam.SettingsGenerator
    6. {
    7.     public class AudioMixerParameterConnection : Connection<float>
    8.     {
    9.         /// <summary>
    10.         /// The mixer that should be controlled by this connection.
    11.         /// </summary>
    12.         public AudioMixer Mixer;
    13.  
    14.         /// <summary>
    15.         /// The name of the exposed parameter.
    16.         /// </summary>
    17.         public string ExposedParameterName;
    18.  
    19.         public AudioMixerParameterConnection(AudioMixer mixer, string exposedParameterName)
    20.         {
    21.             Mixer = mixer;
    22.             ExposedParameterName = exposedParameterName;
    23.         }
    24.  
    25.         public override float Get()
    26.         {
    27.             float value;
    28.             if (Mixer.GetFloat(ExposedParameterName, out value))
    29.             {
    30.                 return value;
    31.             }
    32.             else
    33.             {
    34.                 return 0f;
    35.             }
    36.         }
    37.  
    38.         public override void Set(float value)
    39.         {
    40.             Mixer.SetFloat(ExposedParameterName, value);
    41.         }
    42.     }
    43. }
    44.  
    45.  

    AudioMixerParameterConnectionSO.cs
    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using UnityEngine.Audio;
    4.  
    5. namespace Kamgam.SettingsGenerator
    6. {
    7.     [CreateAssetMenu(fileName = "AudioMixerParameterConnection", menuName = "SettingsGenerator/Connection/AudioMixerParameterConnection", order = 4)]
    8.     public class AudioMixerParameterConnectionSO : FloatConnectionSO
    9.     {
    10.         [Tooltip("The mixer that should be controlled by this connection.")]
    11.         public AudioMixer Mixer;
    12.  
    13.         [Tooltip("The name of the exposed parameter.")]
    14.         public string ExposedParameterName;
    15.  
    16.         protected AudioMixerParameterConnection _connection;
    17.  
    18.         public override IConnection<float> GetConnection()
    19.         {
    20.             if(_connection == null)
    21.                 Create();
    22.  
    23.             return _connection;
    24.         }
    25.  
    26.         public void Create()
    27.         {
    28.             _connection = new AudioMixerParameterConnection(Mixer, ExposedParameterName);
    29.         }
    30.  
    31.         public override void DestroyConnection()
    32.         {
    33.             if (_connection != null)
    34.                 _connection.Destroy();
    35.  
    36.             _connection = null;
    37.         }
    38.     }
    39. }
    40.  
    41.  
     
  21. seoyeon222222

    seoyeon222222

    Joined:
    Nov 18, 2020
    Posts:
    187
    I sent you an email about the resolution list issue, is there any information about this?
    The list provided by the editor, build version, and Windows setting list all appears differently.
     
  22. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi,
    thank you for posting here :).

    I have just tried to find it in the office@kamgam.com mail account but couldn't. Spam seems empty too. Can you please resend it in the forum as a PM or just post it here? Maybe there was a typo in the email adress or I have a broken support link somewhere. Do you remember where you got the contact info from?

    Sadly, I have very limited time this week so in-depth replies may actually take acouple of days (sorry).

    The resolutions list is based on the one Unity is reporting to the settings so I am not sure the settings system can resolve any differences between targets if Unitys list differs (not sure, just speculation). It's hard to tell without all the infos.

    Thank you for your patience.
     
    Last edited: Mar 21, 2023
  23. seoyeon222222

    seoyeon222222

    Joined:
    Nov 18, 2020
    Posts:
    187
    I sent a new email in the form of a reply to the previous email. (2022.03.14)
    (KAMGAM <office@kamgam.com>)
    There is not much additional information.
    unity version : 2023.2.8f1
    os : windows 10 21H2
    Tested monitor: 4k monitor

    How to reproduce issue
    1. Check the Resolution List in the Unity Editor Playmode
    2. Check the Resolution List after Build
    3. Check the resolution List provided in the window display settings
    All three results are different.
     
    _geo__ likes this.
  24. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi, thank you for your patience with the issue.

    I have been able (with the help of my hosting support) to dip up one of your emails (14.3.2023). Your newest e-mail still seems to be missing but I assume it contains the same info as the first one and maybe it's just delayed and will show up later. Not sure what happened there but let's try to continue via email *fingers crossed*.
     
  25. kanitabe

    kanitabe

    Joined:
    Apr 6, 2018
    Posts:
    2
    Thank you for responding to my request.
    I tried it out right away, but with this script, the mixer only changes between 0 and 20 when I move the slider, and even if I minimize the volume, the sound continues to play because it is 0. (0 is the default volume on the mixer).
    I have fixed it, so please use it.

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Audio;
    3.  
    4. namespace Kamgam.SettingsGenerator
    5. {
    6.     public class AudioMixerParameterConnection : Connection<float>
    7.     {
    8.         /// <summary>
    9.         /// The mixer that should be controlled by this connection.
    10.         /// </summary>
    11.         public AudioMixer Mixer;
    12.  
    13.         /// <summary>
    14.         /// The name of the exposed parameter.
    15.         /// </summary>
    16.         public string ExposedParameterName;
    17.  
    18.         public AudioMixerParameterConnection(AudioMixer mixer, string exposedParameterName)
    19.         {
    20.             Mixer = mixer;
    21.             ExposedParameterName = exposedParameterName;
    22.         }
    23.  
    24.         public override float Get()
    25.         {
    26.             float value;
    27.             if (Mixer.GetFloat(ExposedParameterName, out value))
    28.             {
    29.                 return Mathf.Pow(10f, value / 20f);
    30.             }
    31.             else
    32.             {
    33.                 return 0f;
    34.             }
    35.         }
    36.  
    37.         public override void Set(float value)
    38.         {
    39.             value /= 100f;
    40.            
    41.             // If the value of Slider is close to 0, set the volume to an infinitesimal decibel value
    42.             if (value <= 0.001f)
    43.             {
    44.                 Mixer.SetFloat(ExposedParameterName, -80f);
    45.             }
    46.             else
    47.             {
    48.                 // Converts Slider values to decibel units and applies them to AudioMixer's master volume parameters
    49.                 Mixer.SetFloat(ExposedParameterName, Mathf.Log10(value) * 20);
    50.             }
    51.         }
    52.     }
    53. }
    54.  




     
    _geo__ likes this.
  26. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi, it depends on the value range you have set on your slider. The mixer volume usually offers a range from -80 dB to +20 dB. If you set your slider to values from -80 to +20 then you should be able to mute it. At least that's what I did in the demo. The connection does set the value as if you would directly set the volume parameter on the slider. I think from an API perspective that's a reasonable assumption, especially since it can handle any parameter, not just volumes. Each of these may require different scaling.

    Of course for the volume that may be a bit strange since the range can be negative and uses log scaling. I see you compensated for that in your adaptation. Though I would rather add this as a separate AudioMixerVolumeConnection :)

    The mapping or scaling of values from a UI input to the actual connection is something I have been thinking about. I think rather than making a fixed solution for each connection I will add some sort of adapter object which can be plugged into the connections to change the values. That way it would be more flexible and allow users to choose whether they want the values to be changed or not. I think an audio expert for example would rather change the raw dB values than values from 0 to 100. A normal player on the other hand will most likely prefer a more easily understandable range like in your example.

    I have no ETA yet on this but it definitely is something I am thinking about.
    Thanks for the feedback!

    @kanitabe: Oh and welcome to the Unity forum!
     
    Last edited: Apr 6, 2023
  27. strelitziareg

    strelitziareg

    Joined:
    Dec 20, 2020
    Posts:
    1
    Should we expect such settings in the future as?
    DLSS/FSR
    RayTraccing ?
    AO Quality
    Contact Shadow Quality
    Micro Shadows
    ScreenSpaceReflection Quality
    ScreenSpaceReflection Metod
    ScreenSpaceGI Quality
     
    _geo__ likes this.
  28. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi,
    thank you for asking. Oh and welcome to the Unity forum :)

    Features are added based on demand, meaning the more people ask for a certain feature the more likely it is that it will be added.

    However, it also depends on whether unity supports that feature universally (in Built-In, URP and HDRP). Things that are available in all renderers are prioritized over others because I want the asset to remain as "universal" as possible.

    So, are any of the features you mentioned planned at the moment, sadly no, but that does not mean they will never be added. I have just not seen enough demand for them.

    I hope that answers your question.
     
    Last edited: Apr 16, 2023
  29. dam54

    dam54

    Joined:
    Sep 21, 2013
    Posts:
    12
    Using Unity version 2021.3.22f1

    Hello, I have just started with the Settings Generator using the included resources. I added a simple ToggleUGUI control for the Audio however, even though I have it set to IsOn, when it displays it is Off and Audio is playing. If I tick the checkbox to turn it on and then untick it again, the Audio then toggles correctly. I haven't dug into it, but I'm wondering if it has something to do with having multiple Audio Sources.

    Also, on start up of the application I receive the following error and was wondering if this was a known issue. I have not connected any Shadow related options and I'm using the Settings (Template) included in Resources.

    ArgumentNullException: Value cannot be null.
    Parameter name: key
    System.Collections.Generic.Dictionary`2[TKey,TValue].FindEntry (TKey key) (at <88e4733ac7bc4ae1b496735e6b83bbd3>:0)
    System.Collections.Generic.Dictionary`2[TKey,TValue].ContainsKey (TKey key) (at <88e4733ac7bc4ae1b496735e6b83bbd3>:0)
    Kamgam.SettingsGenerator.ShadowConnection.remember () (at Assets/Kamgam/SettingsGenerator/Runtime/Scripts/Connections/Implementations/ShadowConnection.URP.cs:77)
    Kamgam.SettingsGenerator.ShadowConnection.Get () (at Assets/Kamgam/SettingsGenerator/Runtime/Scripts/Connections/Implementations/ShadowConnection.URP.cs:34)
    Kamgam.SettingsGenerator.Connection`1[TValue].GetDefault () (at Assets/Kamgam/SettingsGenerator/Runtime/Scripts/Connections/Connection.cs:37)
    Kamgam.SettingsGenerator.SettingWithValue`1[TValue].SetDefaultFromConnection (Kamgam.SettingsGenerator.IConnection`1[TValue] connection) (at Assets/Kamgam/SettingsGenerator/Runtime/Scripts/Setting/SettingWithValue.cs:152)
    Kamgam.SettingsGenerator.SettingWithValue`1[TValue].InitializeConnection () (at Assets/Kamgam/SettingsGenerator/Runtime/Scripts/Setting/SettingWithValue.cs:106)
    Kamgam.SettingsGenerator.Settings.postLoad () (at Assets/Kamgam/SettingsGenerator/Runtime/Scripts/Settings.cs:205)
    Kamgam.SettingsGenerator.Settings.LoadFromPlayerPrefs (System.String playerPrefsKey) (at Assets/Kamgam/SettingsGenerator/Runtime/Scripts/Settings.cs:188)
    Kamgam.SettingsGenerator.SettingsProvider.get_Settings () (at Assets/Kamgam/SettingsGenerator/Runtime/Scripts/SettingsProvider.cs:58)
    MenuManager.Awake () (at Assets/Scripts/MenuManager.cs:35)

    Thanks
     
    Last edited: Apr 20, 2023
    _geo__ likes this.
  30. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi,
    thank you for posting here :)

    About the toggle issue:

    The initial state of the toggle (if connected to a setting) is determined by the settings default value (or the connections default if there is a connection used) at the time when the settings system is accessed for the very first time (usually in Awake or Start). The ui (visible toogle) is then updated to match the settings value. It does not care what you've set the ui to initially. If you want to change the default then please change either the default value of the setting (on the settings asset) or (if a connection is used) set the audio to playing (play on awake).

    My initial guess was that you only set the gui toggle state to "on". If the setting default (or connection) returned false then it would be logical (and correct) to show as off. However, the fact that you reported it as showing off while the audio is playing is odd. I have two theories why this is happening:

    a) You have multiple Audio Sources (as you mentioned) and some of them are playing by default and others are not which makes the initial state ambiguous. Iirc it would just use the state of the first it finds.

    b) You are changing the play state of the sound source outside of the settings system after(!) it has been initialized without informing the settings about it. In that case you would have to call Refresh on the settings to sync them again with the current state (pull from connections).

    But these are just guesses.

    On the shadows issue:

    Can you please check it the shadow setting is still listed in the settings asset that you are using. If it is please try to remove it. I'd be interested if that resolves the issue.


    Can you please send me your scene (plus the used settings asset) to office@kamgam.com. I'd love to take a look tomorrow (need to get some sleep now).

    Thank you for your patience!
     
  31. dam54

    dam54

    Joined:
    Sep 21, 2013
    Posts:
    12
    Thanks for the quick reply!

    Actually, I just loaded the "SettingsFromAssetDemo" from the examples and it acts the same way. The Audio checkbox is unchecked but audio is playing, and I get the exact same error message as above. Just FYI, I deleted my entire library folder and reimported the SettingsGenerator before I tested this.

    No rush, get some sleep! I forget about the time difference :)
     
    _geo__ likes this.
  32. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi, GOOD NEWS, I have been able to reproduce it (took me a while).

    TLDR > Get the patch here:
    https://kamgam.com/unity/SG-1.7.0-RP-assets-patch.unitypackage

    Why this was happening:
    I am pretty sure that in your the Graphics Settings (Edit > Project Settings > Graphics) you have not Scriptable Render Pipeline Settings assigned. Yet under Quality (Edit > Project Settings > Quality) there are render pipeline assets assigned to each quality level.

    As per Unity documentation that is okay, since this is how Unity detects the active render pipeline:
    • If the current Quality Settings level > Render Pipeline references a Render Pipeline Asset, Unity uses that value.
    • Otherwise:
      • If Graphics Settings > Scriptable Render Pipeline Setting references a Render Pipeline Asset, Unity uses that value.
      • Otherwise, Unity uses the Built-in Render Pipeline.
    I had forgotten to account for that in the ShadowConnection. I simply checked GraphicsSettings.defaultRenderPipeline and assumed Built-In was used if it was null (that's what the docs say). However if GraphicsSettings.defaultRenderPipeline is null we still need to check if maybe there is a render pipeline asset assigned to a quality level and if yes, then use that.

    Maybe that info is helpful to others, took me a bit by surprise.

    The Audio Toggle was just a mere side effect of the first error. The settings did (of course) stop initializing after the ShadowConnection threw the error and thus the toggle (and some other UIs) never got updated to the proper state.

    I hope this resolves the problem. I'll submit the patch today and hopefully it will be available to all soon.
    Thanks again @dam54 for reporting this :)
     
    Last edited: Apr 21, 2024 at 10:24 PM
  33. dam54

    dam54

    Joined:
    Sep 21, 2013
    Posts:
    12
    You are right, that's exactly what it was! Nice work!

    I applied the patch and that solved the problem. Everything works as it should now and no error message.

    Thanks for finding it so quickly!
     
    _geo__ likes this.
  34. dam54

    dam54

    Joined:
    Sep 21, 2013
    Posts:
    12
    Hello, I was looking for a connection to control two particular audio sources, one for the game sound and one for the menu sound. I see something that looks like what I need in Runtime/Scripts/Connections/Implementations/AudioSourceVolumeConnectionComponent, however there is not a matching asset in Resources/Connections. I would also be interested in enabling/disabling/pausing the individual Audio Sources in addition to controlling the volumes separately. Thanks.
     
  35. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi,
    good question.

    The AudioSourceVolumeConnectionComponent is a Component which needs to go on a GameObject.
    You can see how it is used in the SettingsFromAssetDemo scene (the Audio Effect):

    upload_2023-5-2_19-3-31.png

    Notice how the component has a field for the SettingsProvider and the Setting ID (a float setting). The component will react to any changes in the setting and update the volume accordingly. That way you can control one or more volumes with one slider.

    I hope that answers your question.
    Fell free to ask again if you need more infos :)

    UPDATE: Just noticed you also asked about pausing them. I do not yet have ready-made connection components for that but by duplicating the "AudioSourceVolumeConnectionComponent" you should be able to change it from modifying the volume to modifying the state. - I'll put it on my (things to look at) list, no promises though.
     
    Last edited: Apr 21, 2024 at 10:26 PM
  36. dam54

    dam54

    Joined:
    Sep 21, 2013
    Posts:
    12
    Thanks! I totally missed how those other Audio Sources were connected up there. I should be able to do what I need by following that.
     
  37. Tenzho

    Tenzho

    Joined:
    Feb 15, 2015
    Posts:
    4
    is the Rewired integration coming anytime soon? I'm having trouble trying to integrate Rewired to the key binding system
     
  38. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi,

    I have thought about this for a while now since it keeps getting asked. I have arrived at the conclusions that I would recommend to use the Rewired Control Mapper for your Input Rebinding UI if you are using Rewired.

    Since Rewired is an explicit Input System it already should cover all your needs in terms of input binding and is even more advanced than the settings system (multi user bindings, input calibration for thumb sticks, ...).

    You can mix the Settings System and Rewired. Rewired for the Input UI and the settings for the rest.

    I think this is the best approach if you are already using Rewired in your project. Adding a wrapper around it would only add some new complexity and it would always be behind in features compared to Rewired. If Rewired did not have it's own save and UI system then it would make sense to add one in the settings system. But since Rewired already has one I don't think it is a worthwhile endeavour to try to replace it.

    You can install the Mapper via Window > Rewired > Extras > Control Mapper > Install

    If you just rip out the input controls from the Settings System UI and add in the Rewired Control Mapper (ControlMapper Prefab) you should be ready to go (in case you have Rewired setup up already).

    I know this may not be the answer you wanted but I really think adding yet another layer of abstraction around Rewired is not the way to go. If you are using Rewired, best use it all the way.

    If you are not sure how to add Rewired to your existing settings UI then here is the ..



    Tutorial on how to integrate Rewired

    1) Install the Mapper via Window > Rewired > Extras > Control Mapper > Install

    2) Remove the existing inputs. Select them in the UI and delete them:
    upload_2023-5-22_11-19-53.png

    You may also want to delete the reset controls button (or your chagne it to access the rewired ControlMapper).

    3) Copy the rewired parts from the ControlMapper demo. You probably already have a "Rewired Input Manager" and a "RewiredEventSystem". If you do then use them instead. The important part of the UI is the ControlMapper Prefab.
    upload_2023-5-22_11-26-0.png

    4) Now, sadly, we have to UNPACK the prefab. We have to do that because the Prefab root uses a Transform instead of a RectTransform, yet we need it to have a rect transfrom to integrate it into our canvas.
    4.1) Right-Click the prefab and choose Prefab > Unpack
    4.2) Right on top the the Control Mapper create a new empty object and name it "ControlMapper".
    4.3) Copy the control mapper component from the unpacked ControlMapper onto the new object.
    4.4) Move (don't copy!) the whole Canvas from the unpacked ControlMapper into the new object.
    4.5) Delete the old ControlMapper Prefab.

    Now you should have something looking like in the image below.

    5) Make sure the canvases all have proper rect transfrom sizes and scales (they tend to reset to 0/0/0 when copied or moved). Also make sure the internal data of the new ControlMapper (scroll way down) are linked to the right canvas elements.

    upload_2023-5-22_11-49-0.png


    In the end, if you hit play then your UI should look like this:

    upload_2023-5-22_11-52-54.png

    Here are the docs on how to design (theme) the Rewired UI. The creator of Rewired opted to use the Unity UI theming system instead of a prefabs based approach like the settings system uses.

    And that's it.
    I hope this helps you with integrating the Settings System with Rewired :)
     

    Attached Files:

    Last edited: May 30, 2023
    andreiagmu and mbussidk like this.
  39. AlexanderMerk

    AlexanderMerk

    Joined:
    Nov 9, 2016
    Posts:
    16
    Hello!
    Do you have road map of upcoming settings?
    For example, I would like to see settings for Lift and Gain in Lift, Gamma, Gain pp URP.

    Best regards!
     
  40. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi,
    there is no public road map. I do keep a backlog which I fill up based on people asking for features (to which I have now added some more ;-). In general, features that are requested often and exist in all render pipelines have a better chance of getting added than RP specific ones. Bugs are always prioritized over features.

    A Gamma setting is already included. You can take a look at the GammaConnection (GammaConnection.URP.cs). In URP it actually uses the LiftGammaGain component. You could copy it, rename it to Gain and change the "_effect.gamma" to "_effect.gain" in the code.

    I hope that answers your question.
     
  41. AlexanderMerk

    AlexanderMerk

    Joined:
    Nov 9, 2016
    Posts:
    16
    Thanks for answering!
    Yeah, I already using Gamma component, but I wanted to add abillity to controll separetally Gain and Lift too

    Will look into code
     
  42. AlexanderMerk

    AlexanderMerk

    Joined:
    Nov 9, 2016
    Posts:
    16
    Is there any way to change specific settings based on current selected quality level?
    For example:
    upload_2023-5-31_18-51-33.png
    I have 3 quality settings presets, which player can choose from
    1) Low
    2) Medium
    3) High

    And I would like to change grass draw distance based on that presset
    1) Low - 0 draw distance
    2) Medium - 50 draw distance
    3) High - 100 draw distance

    Hope that make sense

    P.S. I already made custom connection for grass draw distane.
    P.S.S. URP
     

    Attached Files:

  43. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Good question, yes that is possible, though it will require some coding in your connection. Each Connection and each Setting implements the IQualityChangedReceiver interface, which looks like this:

    Code (CSharp):
    1. namespace Kamgam.SettingsGenerator
    2. {
    3.     public interface IQualityChangeReceiver
    4.     {
    5.         /// <summary>
    6.         /// Called after the quality level has been changed but before the setting connections are pulled.<br />
    7.         /// Useful for changing setting values in reaction to quality changes (in case the setting is independent
    8.         /// of the default quality settings).
    9.         /// </summary>
    10.         /// <param name="qualityLevel"></param>
    11.         void OnQualityChanged(int qualityLevel);
    12.     }
    13. }

    If you look at the "ShadowDistanceConnection.HDRP.cs" for example then you will see it uses this to react to quality changes and updates the shadow distance accordingly. Notice the usage of the "QualitySettingUtils" class. I made it to make dealing with the quality levels easier (they are tricky beasts).

    Code (CSharp):
    1. public override void OnQualityChanged(int qualityLevel)
    2. {
    3.     int optionCount = getDistances().Count;
    4.     int index = QualitySettingUtils.MapQualityLevelToRange(qualityLevel, 0, optionCount-1);
    5.     Set(index);
    6. }

    In order for your grass distance to support something similar you would have to override the OnQualityChanged() method in your connection and then use the Set() method to apply the changes.

    In the SRPs (URP, HDRP) the official Unity way would be not to change individual settings but instead use render pipeline assets. However, I have not yet seen any terrain settings in those so I think your approach my be the only viable solution.

    If you don't mind, it would be great if you could share your connection code here. I understand if you want to keep it private. Just asking so the whole community can benefit from it :)

    I hope this answers your question. Changing terrain settings is a neat idea to save performance. I am taking notes.
     
    Last edited: Jun 1, 2023
  44. AlexanderMerk

    AlexanderMerk

    Joined:
    Nov 9, 2016
    Posts:
    16

    Thank you for answering!

    I might be doing something wrong:
    https://pastebin.com/9jkQqhLu

    but it doesn't work (debug log doesn't calls).

    "If you don't mind, it would be great if you could share your connection code here"
    Its basically code above, but except floatVar I store value in scriptable var, which applies to grass render distance in another script.
     
  45. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Ah, I see. Your code is an interesting (neat) construct.

    Btw., you can add code here in the forum, no need for pastebin ;-)
    upload_2023-6-1_16-17-1.png
    Your code for future reference:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. namespace Kamgam.SettingsGenerator
    5. {
    6.     public class SettingTest : MonoBehaviour, IQualityChangeReceiver
    7.     {
    8.         public SettingsProvider provider;
    9.         public string Id;
    10.         public float floatVar;
    11.         private void Start()
    12.         {
    13.             var settings = provider.Settings;
    14.             addFloatVariableHook(settings);
    15.         }
    16.         protected void addFloatVariableHook(Settings settings)
    17.         {
    18.             var connection = new GetSetConnection<float>(
    19.                 getter: getFloatValue, // executed if connection.Get() is called.
    20.                 setter: setFloatValue  // executed if connection.Set(value) is called.
    21.             );          
    22.             var floatSettings = settings.GetOrCreateFloat(
    23.                 id: Id,
    24.                 connection: connection
    25.             );
    26.         }
    27.         protected float getFloatValue()
    28.         {
    29.             return floatVar;
    30.         }
    31.         // This simply sets the local field and logs the new value.
    32.         protected void setFloatValue(float value)
    33.         {
    34.             floatVar = value;
    35.         }
    36.         public void OnQualityChanged(int qualityLevel)
    37.         {
    38.             Debug.Log("OnQualityChanged on SettingTest.cs");
    39.         }      
    40.     }
    41. }

    What you did is create a MonoBehaviour which uses a GetSetConnection. You would have had to extend either a Setting or a Connection (and override the OnQualityChanged method) in order to get notified via the interface.

    The settings system does not know anything about the existence of your "SettingTest" object. It only knows about the "connection" and the "floatSettings" setting you've created. That's why the OnQualityChanged is never called. Adding the IQualityChangeReceiver interface does nothing in that case.

    Seeing your code I had an idea to actually enable your workflow. You can update the GetSetConnection to expose the OnQualityChanged callback as an event, like this (copy this code into the GetSetConnection.cs):
    Code (CSharp):
    1. using System;
    2.  
    3. namespace Kamgam.SettingsGenerator
    4. {
    5.     public class GetSetConnection<T> : Connection<T>
    6.     {
    7.         public event Func<T> Getter;
    8.         public event Action<T> Setter;
    9.  
    10.         public event Action<int> QualityChanged;
    11.  
    12.         protected T _value;
    13.        
    14.         public GetSetConnection(Func<T> getter, Action<T> setter)
    15.         {
    16.             Getter += getter;
    17.             Setter += setter;
    18.         }
    19.  
    20.         public override T Get()
    21.         {
    22.             if(Getter != null)
    23.                 _value = Getter.Invoke();
    24.  
    25.             return _value;
    26.         }
    27.  
    28.         public override void Set(T value)
    29.         {
    30.             _value = value;
    31.  
    32.             if(Setter != null)
    33.                 Setter.Invoke(value);
    34.         }
    35.  
    36.         public T GetLastKnownValue()
    37.         {
    38.             return _value;
    39.         }
    40.  
    41.         public void SetLastKnownValue(T value)
    42.         {
    43.             _value = value;
    44.         }
    45.  
    46.         public override void OnQualityChanged(int qualityLevel)
    47.         {
    48.             base.OnQualityChanged(qualityLevel);
    49.             QualityChanged?.Invoke(qualityLevel);
    50.         }
    51.     }
    52. }
    53.  

    Having done that you should be able to hook into that event like this:
    Code (csharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4. namespace Kamgam.SettingsGenerator
    5. {
    6.     public class SettingTest : MonoBehaviour // , IQualityChangeReceiver // Notice we don't need this anymore.
    7.     {
    8.         public SettingsProvider provider;
    9.         public string Id;
    10.         public float floatVar;
    11.         private void Start()
    12.         {
    13.             var settings = provider.Settings;
    14.             addFloatVariableHook(settings);
    15.         }
    16.         protected void addFloatVariableHook(Settings settings)
    17.         {
    18.             var connection = new GetSetConnection<float>(
    19.                 getter: getFloatValue, // executed if connection.Get() is called.
    20.                 setter: setFloatValue  // executed if connection.Set(value) is called.
    21.             );
    22.             connection.QualityChanged += onQualityChanged; // Here we hook into the quality changed event.
    23.  
    24.             var floatSettings = settings.GetOrCreateFloat(
    25.                 id: Id,
    26.                 connection: connection
    27.             );
    28.         }
    29.         protected float getFloatValue()
    30.         {
    31.             return floatVar;
    32.         }
    33.         // This simply sets the local field and logs the new value.
    34.         protected void setFloatValue(float value)
    35.         {
    36.             floatVar = value;
    37.         }
    38.         protected void onQualityChanged(int qualityLevel)
    39.         {
    40.             Debug.Log("OnQualityChanged on SettingTest.cs");
    41.         }
    42.     }
    43. }

    Please note that I have not yet tested this code but it should get you on the right track.

    I think I'll actually add this
    public event Action<int> QualityChanged;
    to the GetSetConnection in the next update. It is a neat feature and it reduces the dependcy on inheritance (always a good thing).

    I hope my explanation on why your current setup does not work was understandable. If not then please don't hesitate to ask again.
     
  46. AlexanderMerk

    AlexanderMerk

    Joined:
    Nov 9, 2016
    Posts:
    16

    It works perfectly, thank you!
     
    _geo__ likes this.
  47. whkona

    whkona

    Joined:
    Jul 9, 2018
    Posts:
    10
    Hey There,

    I have been enjoying your Settings Asset quite a bit recently. And in particular, it has been working well with gamepad control. I did run into an issue with binding that I was hoping you might have an idea with. I'm using an Xbox controller, and the d-pad up/down/left/right do not register as expected. In "Controls Having to Match" string field, I did the standard <Gamepad>/* and when I would then go to rebind that item, I get just DPAD and not, for instance, what I want to see, which is dpad/up. I then tried <Gamepad>/*/* and it would register dpad/up perfectly, but I lock out all other buttons with this string. I tried the string field as empty as well, and it only chose DPAD. I've played with a few other patterns as well but with no success. It seems dpad is 2 deep "dpad/right" where as everything else that registers is one deep like "buttonSouth" Can you think of a way to set the Having to Match string field to allow all button and dpad buttons to be registered properly? I have a few rebindings where I would like to allow for a button or dpad.

    And since I have you. One other odd one is I have full rebinding for the keyboard and mouse as well as the gamepad. I keep these in separate tabs in Settings and notice if I go to a keyboard binding with the gamepad and select say: "Jump" then the "Press Now" shows up but there is no button/trigger/Select/bumper press to escape and get focus back. The opposite is true as well if I go to gamepad rebinding with a mouse click. It just locks up. The issue is a bigger deal though when your gamepad controller is then locked. And I've played with some patterns within the Ignore Control Path and in particular the Abort Control Paths with no luck. For instance, in the first scenario, I put in "<Keyboard>/escape" for the gamepad Abort Control Paths, and it did not allow the escape. I of course can turn off the tab for the device you are not using. But if anyone else is like me on Steam, I sometimes start on the keyboard to make the world name and the character, then move to the gamepad. And then a little back and forth until I figure out which input device seems to play better for that game. I did play a bit with your script: SelectIfNull.cs I have found a few moments of unexpected results when just freely enabled in the Settings menu. Yet I haven't put too much time into trying all its options.

    Any help with these issues would be appreciated.
     
  48. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    Hi, glad you like my asset :)

    I am a bit short on time this weekend but here is quick answer to your questions (more details next week if needed).
    This uses the InputActionRebindingExtensions internally. Which itself is based on the ControlPaths, but I guess you are already familiar with those since you have been using some elaborate paths for testing. I am not sure if the rebinding allows multiple paths for one rebind.

    That's probalby because the button is triggered by the default "submit" action which reacts to all (gamepad, mouse, keyboard) but once you are in, it only listens for the one matching the ui (keyboard in your case). A quick solution would be to disable the button in the keyboard ui while a controller is used (as you yourself suggested). I agree, as a player you can (should be able to) use keyboard and controller at the same time, which makes these differentiations tricky. Often the solution to this is to register the last pressed input as being active and then take it from there. Thanks for reporting it. I'll have to think about that :)
     
  49. whkona

    whkona

    Joined:
    Jul 9, 2018
    Posts:
    10
    Thanks _geo__ for the reply. I had a feeling I would be cornered into finding a custom solution there. I had hoped the string comparison worked more like a Regex, but I think Unity makes the simple string comparison to identify the pattern. I'll look into it deeper, though. It would be nice if the "Controls Having To Match" was a list/array of strings like "Ignore Control Paths". But I realize this is an edge case, so I'll see if I can modify your code to run it that way. Thanks again. And have a great weekend.
     
  50. _geo__

    _geo__

    Joined:
    Feb 26, 2014
    Posts:
    1,338
    @whkona I have given it a try and it seems I can achieve what you want if I use "<Gamepad>/<Button>" AND "<Gamepad>/*/*" as multiple input match criteria (see patch below).

    NOTICE: <Gamepad>/* will not work as it will match (short circuit) any d-pad input before <Gamepad>/*/* has a chance to match. So we need to use the more specific <Gamepad>/<Button> instead to listen for the buttons.

    Could you please give this patch a try (it's just an updated version of "InputBindingForInputSystem.cs"):
    https://kamgam.com/unity/SG-multi-match-patch.unitypackage

    This is the setup I used:
    upload_2023-6-26_12-17-28.png

    The patch adds a new "MatchControlPaths" array to the list.

    To remain backwards compatible I kept the "Controls Having to Match" field. BOTH are used (combined) right now. It simply adds all of them to the matching list. I will mark "Controls Having to Match" as deprecated in upcoming releases.

    Hope this helps. If you confirm that it works then I will add it to the next regular patch release :)
     
    Last edited: Jun 26, 2023