# 2. RemoteConfig & AB Testing

It is a sub-plugin used to help the game perform AB Testing and Remote Config easily. The configs will be declared locally and registered on the server, for details on how to register, please refer to the [Guide to Create A/B Testing.](https://falcon-game-studio.gitbook.io/falcon-sdk/falcon-core/broken-reference)

## 1. Config declaration

To initialize the configs used, the user needs to create an abstract class extension class FalconConfig, then declare attributes representing the remoteConfig declared from the server (can also declare initialization values).&#x20;

<figure><img src="https://content.gitbook.com/content/jXDVMhWRiIUCExjfRIcD/blobs/JK3P4IC2odWi6pSTci4o/image.png" alt=""><figcaption></figcaption></figure>

In the image above, as can be seen, we declare the remoteConfig "config1" (int) and "config2" (String).

<mark style="color:yellow;">Note:</mark>

* The names of remoteConfigs, declared on the client side in the class and initialized on the server side, must be absolutely the same.&#x20;
* remoteConfigs require a public access modifier.&#x20;
* The data type of the remoteConfig must be appropriate (declare at the server as string, the client must also be string, the declaration at the server is int, the client must be int/long/string/..., etc), if the value sent to the client does not match, making the client unable to process, the client will drop this value, do not save.&#x20;
* Configs can only have primitive data types (string, float, DateTime, Boolean), so assigning Object, Array, List, ... will not be possible.
* Initializing values is performed when calling FalconMain.Init(), and connecting to the server to receive the latest value takes time, so it is necessary to check the value of FalconConfig.UpdateFromNet.

```
if (FalconConfig.UpdateFromNet == ExecState.Succeed)
{
    CustomConfig newestConfigFromServer = FalconConfig.Instance<CustomConfig>;
} else {
    CustomConfig defaultOrPreviousSessionConfig = FalconConfig.Instance<CustomConfig>;
}
```

## 2. SDK running process

When run, the SDK will:

* If it is the first run, immediately use the initialization values (above config1 = 5 and config2 = "ahihi do ngok").
* &#x20;The SDK will immediately send a request to the server to retrieve the latest remoteConfig values (during which time the remoteConfig values will be initialized). When the server returns successfully, the remoteConfig will be reset (you can check the [UpdatedFromNet ](#3.1.-updatedfromnet)value in the config to see if the config has been updated).&#x20;
* After receiving the new value from the server, the SDK saves the new values and uses this value instead of the initialization value on subsequent runs.

## 3. Basic methods

### 3.0. Get remoteConfig instance

Get an instance of remote config by calling:

```
FalconConfig.Instance<<Tên class config>>();
```

VD: `RealConfig config = FalconConfig.Instance<RealConfig>();`

### 3.1. UpdatedFromNet

Indicates whether the remoteConfig has been successfully updated from the server, including 4 basic states:

* `NotStarted`
* `Processing`
* `Succeed`
* `Failed`

VD:&#x20;

```
while (FalconConfig.UpdatedFromNet != ExecState.Succeed)
{
    Debug.Log("Value of remoteConfig has not been updated ._.");
    yield return null;
}

Debug.Log("Values remoteConfig has just been updated ^w^");
```

### 3.2. RunningABTesting

Returns the ID of ABTesting campaign that is running.

VD:

```
Debug.Log( FalconConfig.RunningABTesting);
```

### 3.3. Accessing remoteConfig

The values of config are accessed as regular properties of the class:

VD:

```
Debug.Log( FalconConfig.Instance<RealConfig>().config1);

Debug.Log( FalconConfig.Instance<RealConfig>().config2);
```

### 3.4. OnUpdateFromNet

The EventHandler is called when the RemoteConfig value is successfully updated from the server, which is Invoke in the secondary thread. FalconConfig initialization is called from FalconMain.Init before the first scene loads (details can be found in [FalconMain.Init](https://falcon-game-studio.gitbook.io/falcon-sdk/falcon-core/1.-configuration-and-installation/about-falconmain.init-and-init-sdk)), so if you want to assign an event, you need to use the RuntimeInitializeOnLoadMethod attribute with the RuntimeInitializeLoadType before BeforeSceneLoad.

```
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSplashScreen)]
static void OnBeforeSplashScreen()
{
    FalconConfig.OnUpdateFromNet+= ((sender, args) => 
        Debug.Log("This will be printed right after FalconConfig 
        is updated <3"));
}
```

## 4. Changes in FalconCore 3.0.4

### 4.1. Filters

* Old Filters;

<table><thead><tr><th width="155">Name</th><th>Source</th><th>Description</th></tr></thead><tbody><tr><td>platform</td><td>FDeviceInfoRepo.Platform</td><td>android/ios/....</td></tr><tr><td>appversion</td><td>FDeviceInfoRepo.AppVersion</td><td>current version of the app</td></tr><tr><td>deviceName</td><td>FDeviceInfoRepo.DeviceName</td><td>exp: "desktop-nrqdcnnrqdcn7"</td></tr><tr><td>firstLogin</td><td>FPlayerInfoRepo.FirstLogInMillis</td><td>Sdk sends timeMillis</td></tr><tr><td>level</td><td>FPlayerInfoRepo.MaxPassedLevel</td><td>Player max passed level<br>Auto updated if use level log of Falcon Analytic </td></tr><tr><td>firstLoginDate</td><td>Server convert from firstLogin</td><td>Date , UTC</td></tr><tr><td>country</td><td>Detected on server side</td><td>Country code ISO 3163166 - 2 upper case letters</td></tr></tbody></table>

( numberOfVideos field has been removed)

* New Filters in FalconCore 3.0.4

<table><thead><tr><th width="164">Name</th><th width="259">Source</th><th>Description</th></tr></thead><tbody><tr><td>deviceId</td><td>FDeviceInfoRepo.DeviceId</td><td>exp: 969eff3f753e627ef1882beb94dd3d1c07095aac</td></tr><tr><td>deviceOs</td><td>FDeviceInfoRepo.DeviceOs</td><td>exp: windows 11 (10.0.22631) 64bit</td></tr><tr><td>installVersion</td><td>FPlayerInfoRepo.InstallVersion</td><td></td></tr><tr><td>accountId</td><td>FPlayerInfoRepo.AccountID</td><td></td></tr><tr><td>adLtv</td><td>FPlayerInfoRepo.Ad.AdLtv</td><td>Total LTV derived from a player's ad viewing, in USD<br>Aggregated automatically if using AdLog has adLtv input with Falcon Analytic</td></tr><tr><td>interAdCount</td><td>FPlayerInfoRepo.Ad.AdCountOf(AdType.Interstitial)</td><td>Number of times players view inter-advertisements <br>Aggregated automatically if using Falcon Analytic's Ad Log</td></tr><tr><td>rewardAdCount</td><td>FPlayerInfoRepo.Ad.AdCountOf(AdType.Reward)</td><td>Number of times players view reward ads <br>Aggregated automatically if using Falcon Analytic's Ad Log</td></tr><tr><td>inAppCount</td><td>FPlayerInfoRepo.InApp.InAppCount</td><td>Number of times a player makes inApp deposits <br>Aggregated automatically if using Falcon Analytic's InApp log</td></tr><tr><td>inAppMax</td><td>FPlayerInfoRepo.InApp.InAppLtIv.max</td><td>The largest inApp deposit value that a player has ever deposited, according to local denomination <br>Aggregated automatically if using Falcon Analytic's InApp log</td></tr><tr><td>inAppMaxUsd</td><td>Detected on server side</td><td>Convert inAppMax from Local denomination to USD</td></tr><tr><td>inAppTotal</td><td>FPlayerInfoRepo.InApp.InAppLtv.toal</td><td>Total player deposit, according to local denomination <br>Aggregated automatically if using Falcon Analytic's InApp log</td></tr><tr><td>inAppTotalUsd</td><td>Detected on server side</td><td>Convert inAppTotal from Local denomination to USD</td></tr><tr><td>inAppCurrency</td><td>FPlayerInfoRepo.InApp.InAppLtv.isoCurrencyCode</td><td>Deposit currency at the player's local</td></tr><tr><td>retentionDay</td><td>FTime.DateSinceEpoch(FTime.CurrentTimeMillis()) - FTime.DateSinceEpoch(FPlayerInfoRepo.FirstLogInMillis)</td><td></td></tr></tbody></table>

* Filter fields supported if using FalconAnalytic 3.0.7 or greater:

<table><thead><tr><th width="150">Name</th><th width="328">Source</th><th>Description</th></tr></thead><tbody><tr><td>firebaseToken</td><td>FalconFirebase.firebaseToken</td><td></td></tr><tr><td>advertisingId</td><td>FalconAdvertisingId.falconAdvertisingId</td><td></td></tr></tbody></table>

### 4.2. Changes compared to the old version

The values ​​of the class that inherits FalconConfig are now assigned using Json, this makes it possible to later assign values ​​of a collection, array, object,... to fields in the class (we will notify and open the feature on the web when the feature is completed, so you don't have to update the SDK :>>>>>).&#x20;

However, for the classes that inherit FalconConfig to be processed optimally(especially with IL2CPP building), the following conditions should be met:

* If you want to assign a value to a static field, you need the \[JsonProperty] attribute.
* Fields assigned values ​​need to be public (even better if the class has \[Serializable] attribute)
* The field in the class must reasonable value ​​with the value ​​declared on the server (both must be the number/ both string/ both bool/...)
