Search Unity

Feedback Thoughts on Remote Config & default values

Discussion in 'Unity Remote Config' started by mozzer7, Nov 9, 2021.

  1. mozzer7

    mozzer7

    Joined:
    May 18, 2013
    Posts:
    12
    Hello! Been messing around with remote config a bit, and it's super useful, BUT, it's also really quite annoying to use sometimes... It might be that I'm using it 'wrong', or that I'm missing something, but I just wanted to offer my thoughts / get some answers on a few things. Disclaimer : I don't want this to feel like a rant, but rather opinions on using a feature in live production of a product and what it feels like from a user perspec

    Having got everything up and running, and then decided that remote configs would be really useful, I then set about looking at how it handles no connection on first load of the app...In truth, I didn't think about this earlier because, well, my own fault really, I thought the remote config system would handle it gracefully.

    what happens when it can't access remote config and there is no cache? Short answer, nothing. Longer answer 'default values'. In theory, this works, in practice, it's not really that useful in projects of any size larger than...well, a prototype.

    All of my configs are JSON. Why? IMO, It's easier to manage, and my settings can be grouped in to localisation, input, styles etc... Better to keep things organised. Also, each controller responsible for that setting can just grab the json setting it needs. Simple. So, when it comes to default values, I could just pass the json from a text file...but this is the thing that's a bit annoying - Remote config only cares for a small part of your app; when conditions are perfect, when it's not, I need something else.... I know game dev is a hugely broad thing, and you as a team inside Unity can't write code to make everyone happy, but offering a solution that only solves half the problem isn't ideal. As a supplier of a solution, it's nice to take the responsibility of updating settings remotely, but as a user, to be expected to then manage potentially hundreds of settings when it doesn't work makes the whole feature's promise seem disingenuous.

    Using JSON in the remote config settings gives an option to use a JSON object, which the remote config will grab the text from, which is useful in theory, but in practice is annoying, because every time I change the json setting or close and open it up again, the object is cleared. Is it supposed to be a temporary reference to just grab some json? Why can't I just use a text file at all times for that setting?1. that would be useful and a nice workflow. 2. I can version the settings through my VCS. And then, why can't this be my default value - having remote config fall back to this would be super useful as it's already referenced...? My bigger question I guess though is, why can't I take a cache of the remote values during the build process? The editor is grabbing the values from somewhere...

    It feels like all the pieces are there, but they just don't talk to each other.Is this something that's being worked on? Can we expect a better experience for managing default values? The current default value workflow, technically, does work, but in practice, used in anger, it's a real pain.
     
  2. mozzer7

    mozzer7

    Joined:
    May 18, 2013
    Posts:
    12
    As a quick follow up, a way around this, at least from my perspective, is to have a defaultConfig file, which I can load locally, and always use as the default value. As I'm only using JSON configs, this makes it easier as I don't have to work around different setting types..
    Here's a little snapshot of what I'm doing...

    Screenshot 2021-11-09 at 12.11.30.png

    I have a RemoteConfigController, which is where I request my data from Remote Config...

    In order to handle defaultValues easier, I have a local json file in the project that has the location and ID of all local json files that are my defaultValues. I load this in to the RemoteConfigController, and when I request something from remote config, I grab the data from the configDefaults entry with the matching ID...

    It's not ideal, but it works. I now have to make a decision around I still manage my content through the RemtoeConfig window and then update the local files, or do I just update the local files and then update remote content? I feel like the latter, so that I can manage local changes before pushing them to the remote config...it would just be nice to keep the service and local data in sync easier with changes I want to make ... Hope that's useful for people...
     
  3. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    @mozzer7 You can set default values like the following:

    int myDefaultValue = 1;

    enemyHealth = ConfigManager.appConfig.GetInt ("enemyHealth", myDefaultValue);
     
  4. Dzistu

    Dzistu

    Joined:
    May 25, 2018
    Posts:
    2
    Hi, about using remote config and JSONs, are there any limits on how long the JSON can be for a single entry or how many entries can I have in total? Or how "big" the whole remote config can be?
    Couldn't find anything about that kind of limitations in documentation
     
  5. mozzer7

    mozzer7

    Joined:
    May 18, 2013
    Posts:
    12
    @Jeff
    oh yeh, I know that, but it's more the fact that it's not a very workable solution if you're going to try and use remote configs in a way that you can manage a large proportion of your project - it's there as an example, but it's not a good 'real world' example of the system being used 'well.

    My solution of my remote config manager access local versions and assigning those as default values has worked well and it saves me having to assign default values for single variables at a time when I can just have a local copy of data that I then push to the server...

    @Dzistu I've not come across a problem yet, but I've not got a huge amount of data. I've got about 15 JSON settings that I'm using. Each one probably holds about 100 lines of data. Parsing multiple small json files I figure is better than less larger ones....
     
  6. greg-harding

    greg-harding

    Joined:
    Apr 11, 2013
    Posts:
    524
    @JeffDUnity3D Hey Jeff, just pinging this thread with a similar question. I've been looking at RemoteConfig today (btw, the game services website configured a snippet for me using a very old v3.0.0-pre3 but it threw exceptions until I found v3.0.0-pre14 existed).

    I'm wondering about some of the flow of the services stuff. You mentioned using default values using what is now
    RemoteConfigService.Instance.appConfig.GetInt("myVar", defaultVal) which seems fine, and I've found
    RemoteConfigService.Instance.appConfig.origin as a way to see if default, cached or remote values are in the appConfig container. So far so good.

    But, the service initialisation example in the docs has a snippet for detecting an internet connection. The comments and pattern shown suggests that the service fetches shouldn't be used if there's no internet connection, so how are these values populated with defaults or cached values? Will they exist by default somehow when the RemoteConfigService.Instance is made, or does one of the RemoteConfigService.Instance.FetchConfigs() or Async() methods need to be called to trigger a load from the cache and attempt a remote connection, triggering the callback or resuming after the await?

    Some of the current github examples show some of these things in isolation or are slightly out of date, so I thought I'd ask here while I slap various bits of code together. I'm just looking for a nice pattern to use to use/set defaults, use cached, or use the remote vars and respect the internet connection check etc.

    Edit: I tested accessing the RemoteConfigService.Instance.appConfig.GetInt("myVar", defaultVal) in an Awake before any service setup and it returned default values (no exceptions or nullrefs)... but it only returns origin default values, it never seems to return origin cached values even after successfully starting the service and fetching the remote values a few times.

    Cheers for any info!
     
    Last edited: Apr 1, 2022
  7. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    @greg-harding Be sure to be using the latest RC version (Show all versions in Package Manager), you are describing behavior of earlier versions. If there is no internet, the cached values will be used if the user has previously successfully connected. If this is the first time for the user and there is no internet, the default values will be used.
     
  8. greg-harding

    greg-harding

    Joined:
    Apr 11, 2013
    Posts:
    524
    hi Jeff, thanks for your reply. I'll check what the package manager sees again shortly and update if anything newer shows up. FYI the Game Services site page configured the packages snippet for me to get started yesterday which was really out of date, looking at the changelogs in the docs. I assumed I was getting the latest and just started working through the intro stuff until it threw exceptions and I checked the forums :)

    Code (CSharp):
    1. "com.unity.remote-config": "3.0.0-pre.3",
    2. "com.unity.services.analytics": "3.0.0-pre.4"
    Edit: The latest I can see (and installed earlier today) is Remote Config Version 3.0.0-pre.14 - March 28, 2022 which installs as a dependency Remote Config Runtime Version 3.0.0-pre.28 - March 28, 2022. (For reference, I'm on macOS Unity 2021.2.17.) I'm not seeing cached stuff returned but it could be my rookie async code.
     
    Last edited: Apr 1, 2022
  9. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
  10. greg-harding

    greg-harding

    Joined:
    Apr 11, 2013
    Posts:
    524
    hi Jeff, yep, I've been using those docs (the latest version I can see is Remote Config 3.0.0-pre14) and testing various things. I cannot get any cached values, only default or remote. I have two environments set up on the dashboard; "production" and "development", both with the same two test booleans. These booleans do successfully load via fetchconfigs when connected to the internet. I'm testing in the editor, not in player builds.

    I thought I'd test to see if I could read cached values after some previously successful remote loads. During Awake and/or before any other services initialisation, I tested reading data using RemoteConfigService.Instance.appConfig.GetBool(). It's returning origin default values, not cached values. This might be because at this point the authentication has not logged in an anonymous user. So, I also checked the appConfig.GetBool() after the core services were initialised and an anonymous user had logged in. Same result, default values. When should I expect to see origin cached values returned?

    I also just checked that the auth login AuthenticationService.Instance.SignInAnonymouslyAsync() returns the same PlayerId between different play/stops in the editor - seems to be consistent, so if the data is saved per-user then it should be ok.

    Apologies if I've misinterpreted some of the docs or am assuming some results when it's not designed that way. I'm happy to show you my wip code or test any suggestions out.
     
  11. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    @greg-harding Can you elaborate "origin default values, not cached values". What are the values are you actually seeing, and what are the cached values? Please share the code that you are using so I may test similarly here, with specific steps to reproduce, and your variable before and after values. And when you mention "origin default value", you mean the second parameter (the default value) from the GetBool method?

    bool myBool;

    bool myDefaultBool = true;

    myBool = ConfigManager.appConfig.GetBool("enemyStatus", myDefaultBool);

    With the above code, let's assume the user connected previously and received a false (the current and expected) value from our servers, and which is written to the local cache. If the user then disconnects from the Internet prior to the next game session, this method would return false. However, if this user did NOT connect previously (so no local cache), this method would return true. I hope this helps.
     
  12. greg-harding

    greg-harding

    Joined:
    Apr 11, 2013
    Posts:
    524
    hi Jeff, thanks very much for the followup. I got your DM and will try to set up the test project with some of my learning / test code.

    My default bool values included in the appConfig.GetBool() method are false, and values in both environments on the dashboard are true. I can successfully load the true values from the remote, but when I tested a few codepaths to try to see if I could read cached values in subsequent runs while not connected to the internet I only ever saw origin default false values (and by origin I mean RemoteConfigService.Instance.appConfig.origin).
     
  13. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    I received your project via private message. Please get the sample project I sent you working first as-is and confirm that our documented code works as expected. Please report back here once you are able to test. Once we confirm it is working as expected, then we can look at the additional async packages you are using to see if they might be breaking the flow.
     
  14. greg-harding

    greg-harding

    Joined:
    Apr 11, 2013
    Posts:
    524
    hi Jeff, yes I got the sample project working as is (no additional async, that was just in my other test project) and stuff works, but I never see any cached values returned at any stage.
     
  15. JeffDUnity3D

    JeffDUnity3D

    Joined:
    May 2, 2017
    Posts:
    14,446
    So we are using the following code (comment out the AuthenticationService lines for now). When I run this in the Editor with no network, I get the Debug.Log output "No settings loaded this session; using cached values from a previous session." Can you confirm you are seeing the same thing? Then we can look at variable values

    Code (CSharp):
    1.  void ApplyRemoteSettings(ConfigResponse configResponse)
    2.     {
    3.         // Conditionally update settings, depending on the response's origin:
    4.         switch (configResponse.requestOrigin)
    5.         {
    6.             case ConfigOrigin.Default:
    7.                 Debug.Log("No settings loaded this session; using default values.");
    8.                 break;
    9.             case ConfigOrigin.Cached:
    10.                 Debug.Log("No settings loaded this session; using cached values from a previous session.");
    11.                 break;
    12.             case ConfigOrigin.Remote:
    13.                 Debug.Log("New settings loaded this session; update values accordingly.");
    14.                 string myString = ConfigManager.appConfig.GetString("MyDescription");
    15.                 enemyDamage = ConfigManager.appConfig.GetFloat("MyNumber");
    16.                 assignmentId = ConfigManager.appConfig.assignmentId;
    17.  
    18.                 Debug.Log("MyString = " + myString.ToString());
    19.                 Debug.Log("MyNumber = " + enemyDamage.ToString());
    20.                 break;
    21.         }
    22.     }
     
  16. greg-harding

    greg-harding

    Joined:
    Apr 11, 2013
    Posts:
    524
    hi Jeff, yes, if I comment out the auth anonymous signin and disconnect from the network then after FetchConfigs times out the cached values are returned in the callback. All good.

    I don't think this was happening due to exceptions in the earlier versions installed the other day via the Game Services website (where it autoconfigures the package snippet for you) which is why I was wondering when cached values were actually going to appear.

    I was originally wondering if before attempting a call to FetchConfigs if accessing RemoteConfigService.Instance.appConfig.GetBool() would return previously loaded remote values as cached values or not. What I'm seeing is that the cached values are only returned when a call to FetchConfigs times out or fails for some reason, but until then whatever I pass as the default into the GetBool() method is used. If this is the intended behaviour then all good, it will be up to us to pass in a useful default, ie. hardcoded, or from a previous successful remote load.
     
    JeffDUnity3D likes this.
  17. fcloss

    fcloss

    Joined:
    Dec 1, 2011
    Posts:
    192
    It works exactly as you described and that's, in my opinion, a terrible design decision they made. The first step would be to load the cache so it is available at any time, not just when it fails. RemoteSettings was implemented correctly, RemoteConfig, besides a terrible documentation, has this design flaw.
     
    Last edited: Jun 29, 2023
    greg-harding likes this.
  18. fcloss

    fcloss

    Joined:
    Dec 1, 2011
    Posts:
    192
    @JeffDUnity3D, the cache, even if LoadCache is called when you call SetEnvironmentID, is not available on the appconfig variable because appConfig is only set after the async initialization of UnityServices, SignInAnonymouslyAsync and the call to FetchConfigs. I see it is a kind of disaster, I've debugged the class ConfigManagerImpl and the cache works exactly as described, unless I am completely lost.

    I see lots of conflicts and complication due to environments, user id, etc, so the cache timing is not good as it needs information that comes from async methods. The documentation is very very rough so basically, it is kind up to you to debug, read code and then load the cache json by yourself or create your own cache.
     
  19. fcloss

    fcloss

    Joined:
    Dec 1, 2011
    Posts:
    192
    Maybe it can be useful for someone, this is how I managed to have the cache from the start (sync):

    Code (CSharp):
    1. private static RuntimeConfig cachedConfig = null;
    2.  
    3. void Awake()
    4. {
    5.             string environmentId = "...";
    6.  
    7.             RemoteConfigService.Instance.SetEnvironmentID(environmentId);
    8.  
    9.             cachedConfig = RemoteConfigService.Instance.GetConfig("settings");
    10.  
    11.             if(!cachedConfig.environmentId.Equals(environmentId,StringComparison.InvariantCultureIgnoreCase))
    12.             {
    13.                 cachedConfig = null;
    14.             }
    15. }
    then I proceed with the regular initialization of the RemoteConfig, having a boolean to indicate if the fetchcompleted event has arrived, which means that RemoteConfig is initialized and the data is available. Otherwise initialized is false and the cache will be used.

    Then, in my wrapper, I implemented the methods like this one:

    Code (CSharp):
    1.  public static bool GetBool(string key, bool defaultValue)
    2. {
    3.             bool value;
    4.  
    5.             if (!initialized && cachedConfig!=null)
    6.             {
    7.                 value = cachedConfig.GetBool(key, defaultValue);
    8.             }
    9.             else
    10.             {
    11.                 value = RemoteConfigService.Instance.appConfig.GetBool(key, defaultValue);
    12.             }
    13.  
    14.            return value;
    15. }
    This way, If the appConfig is still not available (fetch not completed) I access the cachedConfig. This try to fix what I would have expected from RemoteConfig by default.
     
    BallistiX09 likes this.
  20. GabKBelmonte

    GabKBelmonte

    Unity Technologies

    Joined:
    Dec 14, 2021
    Posts:
    117
    Hey @mozzer7 ,

    With regards to this question

    It's not ideal, but it works. I now have to make a decision around I still manage my content through the RemtoeConfig window and then update the local files, or do I just update the local files and then update remote content? I feel like the latter, so that I can manage local changes before pushing them to the remote config...it would just be nice to keep the service and local data in sync easier with changes I want to make ... Hope that's useful for people...
    I want to point out that if you use the [UGS CLI], you can automate the process in either direction, using the
    "Deploy" and "Fetch" commands, which push config up to the server or back down.
    The Deployment package can also help you manage your usage from the editor, though it hasnt got "fetch" functionality implemented at the moment.
    If we get feedback, we could look into it though.

    Let me know if this helps