2026-06-04 17:16:17 +08:00
|
|
|
using System;
|
|
|
|
|
using System.Collections;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Globalization;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using Dirichlet.Mediation;
|
|
|
|
|
using Runtime.ADAggregator;
|
|
|
|
|
using UnityEngine;
|
|
|
|
|
|
|
|
|
|
public sealed class TapadnControllerOptions
|
|
|
|
|
{
|
|
|
|
|
public const string MediaNameKey = "tapadn.media_name";
|
|
|
|
|
public const string MediaIdKey = "tapadn.media_id";
|
|
|
|
|
public const string MediaKeyKey = "tapadn.media_key";
|
|
|
|
|
public const string ChannelKey = "tapadn.channel";
|
|
|
|
|
public const string SubChannelKey = "tapadn.sub_channel";
|
|
|
|
|
public const string DebugKey = "tapadn.debug";
|
|
|
|
|
public const string TapClientIdKey = "tapadn.tap_client_id";
|
|
|
|
|
public const string ShakeEnabledKey = "tapadn.shake_enabled";
|
|
|
|
|
public const string CustomConfigJsonKey = "tapadn.custom_config_json";
|
|
|
|
|
public const string DataJsonKey = "tapadn.data_json";
|
|
|
|
|
public const string ATagsKey = "tapadn.atags";
|
|
|
|
|
public const string AllowIdfaAccessKey = "tapadn.allow_idfa_access";
|
|
|
|
|
public const string RequestPermissionOnInitKey = "tapadn.request_permission_on_init";
|
|
|
|
|
public const string RewardedAutoLoadKey = "tapadn.rewarded_auto_load";
|
|
|
|
|
public const string RewardedPrewarmOnInitKey = "tapadn.rewarded_prewarm_on_init";
|
|
|
|
|
public const string RewardedMaxLoadAttemptsKey = "tapadn.rewarded_max_load_attempts";
|
|
|
|
|
public const string RewardedLoadRetryDelayMsKey = "tapadn.rewarded_load_retry_delay_ms";
|
|
|
|
|
public const string RewardedShowTimeoutMsKey = "tapadn.rewarded_show_timeout_ms";
|
2026-06-17 15:40:25 +08:00
|
|
|
public const string RewardedSceneSlotPrefix = "tapadn.rewarded_scene_slot.";
|
|
|
|
|
public const string RewardedSceneSlotsKey = "tapadn.rewarded_scene_slots";
|
|
|
|
|
public const string RewardedSceneSlotsJsonKey = "tapadn.rewarded_scene_slots_json";
|
|
|
|
|
public const string RewardedCacheMaxAgeSecondsKey = "tapadn.rewarded_cache_max_age_seconds";
|
2026-06-04 17:16:17 +08:00
|
|
|
public const string RewardNameKey = "tapadn.reward_name";
|
|
|
|
|
public const string RewardAmountKey = "tapadn.reward_amount";
|
|
|
|
|
public const string InterstitialAutoLoadKey = "tapadn.interstitial_auto_load";
|
|
|
|
|
public const string InterstitialPrewarmOnInitKey = "tapadn.interstitial_prewarm_on_init";
|
|
|
|
|
public const string InterstitialMaxLoadAttemptsKey = "tapadn.interstitial_max_load_attempts";
|
|
|
|
|
public const string InterstitialLoadRetryDelayMsKey = "tapadn.interstitial_load_retry_delay_ms";
|
|
|
|
|
public const string InterstitialShowTimeoutMsKey = "tapadn.interstitial_show_timeout_ms";
|
|
|
|
|
public const string SplashAutoLoadKey = "tapadn.splash_auto_load";
|
|
|
|
|
public const string SplashPrewarmOnInitKey = "tapadn.splash_prewarm_on_init";
|
|
|
|
|
public const string SplashMaxLoadAttemptsKey = "tapadn.splash_max_load_attempts";
|
|
|
|
|
public const string SplashLoadRetryDelayMsKey = "tapadn.splash_load_retry_delay_ms";
|
|
|
|
|
public const string SplashShowTimeoutMsKey = "tapadn.splash_show_timeout_ms";
|
2026-06-05 21:44:35 +08:00
|
|
|
public const string SmartPreloadEnabledKey = "tapadn.smart_preload_enabled";
|
|
|
|
|
public const string SmartPreloadConfigJsonKey = "tapadn.smart_preload_config_json";
|
|
|
|
|
public const string SmartPreloadConfigAssetPathKey = "tapadn.smart_preload_config_asset_path";
|
|
|
|
|
public const string SmartPreloadRemoteConfigJsonKey = "tapadn.smart_preload_remote_json";
|
2026-06-04 17:16:17 +08:00
|
|
|
public const string ExpressWidthKey = "tapadn.express_width";
|
|
|
|
|
public const string ExpressHeightKey = "tapadn.express_height";
|
|
|
|
|
|
|
|
|
|
public long MediaId { get; set; }
|
|
|
|
|
public string MediaName { get; set; }
|
|
|
|
|
public string MediaKey { get; set; }
|
|
|
|
|
public string Channel { get; set; } = "default";
|
|
|
|
|
public string SubChannel { get; set; }
|
|
|
|
|
public bool Debug { get; set; }
|
|
|
|
|
public string TapClientId { get; set; }
|
|
|
|
|
public bool ShakeEnabled { get; set; } = true;
|
|
|
|
|
public string CustomConfigJson { get; set; }
|
|
|
|
|
public string DataJson { get; set; }
|
|
|
|
|
public string ATags { get; set; }
|
|
|
|
|
public bool AllowIDFAAccess { get; set; } = true;
|
|
|
|
|
public bool RequestPermissionOnInit { get; set; }
|
2026-06-05 21:44:35 +08:00
|
|
|
public bool RewardedAutoLoad { get; set; } = false;
|
2026-06-04 17:16:17 +08:00
|
|
|
public bool RewardedPrewarmOnInit { get; set; }
|
|
|
|
|
public int RewardedMaxLoadAttempts { get; set; } = 1;
|
|
|
|
|
public int RewardedLoadRetryDelayMs { get; set; } = 500;
|
|
|
|
|
public int RewardedShowTimeoutMs { get; set; } = 20000;
|
2026-06-17 15:40:25 +08:00
|
|
|
public int RewardedCacheMaxAgeSeconds { get; set; } = 600;
|
|
|
|
|
public Dictionary<string, string> RewardedSceneSlotIds { get; private set; } = new Dictionary<string, string>(StringComparer.Ordinal);
|
2026-06-04 17:16:17 +08:00
|
|
|
public string RewardName { get; set; } = "reward";
|
|
|
|
|
public int RewardAmount { get; set; } = 1;
|
2026-06-05 21:44:35 +08:00
|
|
|
public bool InterstitialAutoLoad { get; set; } = false;
|
2026-06-04 17:16:17 +08:00
|
|
|
public bool InterstitialPrewarmOnInit { get; set; }
|
|
|
|
|
public int InterstitialMaxLoadAttempts { get; set; } = 1;
|
|
|
|
|
public int InterstitialLoadRetryDelayMs { get; set; } = 500;
|
|
|
|
|
public int InterstitialShowTimeoutMs { get; set; } = 20000;
|
2026-06-05 21:44:35 +08:00
|
|
|
public bool SplashAutoLoad { get; set; } = false;
|
2026-06-04 17:16:17 +08:00
|
|
|
public bool SplashPrewarmOnInit { get; set; }
|
|
|
|
|
public int SplashMaxLoadAttempts { get; set; } = 1;
|
|
|
|
|
public int SplashLoadRetryDelayMs { get; set; } = 500;
|
|
|
|
|
public int SplashShowTimeoutMs { get; set; } = 20000;
|
2026-06-05 21:44:35 +08:00
|
|
|
public bool SmartPreloadEnabled { get; set; } = false;
|
|
|
|
|
public string SmartPreloadConfigAssetPath { get; set; } = "TapadnSmartLoadPolicy_Default";
|
|
|
|
|
public string SmartPreloadConfigJson { get; set; }
|
|
|
|
|
public string SmartPreloadRemoteConfigJson { get; set; }
|
2026-06-04 17:16:17 +08:00
|
|
|
public int? ExpressWidth { get; set; }
|
|
|
|
|
public int? ExpressHeight { get; set; }
|
|
|
|
|
|
|
|
|
|
public static TapadnControllerOptions Resolve(ADConfig adConfig, object[] args)
|
|
|
|
|
{
|
|
|
|
|
var options = new TapadnControllerOptions();
|
|
|
|
|
options.ApplyAdConfig(adConfig);
|
|
|
|
|
options.ApplyLegacyArgs(args);
|
|
|
|
|
|
|
|
|
|
if (args == null)
|
|
|
|
|
{
|
|
|
|
|
return options;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var arg in args)
|
|
|
|
|
{
|
|
|
|
|
switch (arg)
|
|
|
|
|
{
|
|
|
|
|
case TapadnControllerOptions explicitOptions:
|
|
|
|
|
options.ApplyExplicitOptions(explicitOptions);
|
|
|
|
|
break;
|
|
|
|
|
case IDictionary dictionary:
|
|
|
|
|
options.ApplyDictionary(dictionary);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return options;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public DirichletAdConfig BuildSdkConfig()
|
|
|
|
|
{
|
|
|
|
|
return new DirichletAdConfig.Builder()
|
|
|
|
|
.WithMediaId(MediaId)
|
|
|
|
|
.WithMediaName(string.IsNullOrWhiteSpace(MediaName) ? Application.productName : MediaName)
|
|
|
|
|
.WithMediaKey(MediaKey)
|
|
|
|
|
.WithGameChannel(string.IsNullOrWhiteSpace(Channel) ? "default" : Channel)
|
|
|
|
|
.WithSubChannel(SubChannel)
|
|
|
|
|
.EnableDebug(Debug)
|
|
|
|
|
.WithTapClientId(TapClientId)
|
|
|
|
|
.ShakeEnabled(ShakeEnabled)
|
|
|
|
|
.WithCustomConfigJson(CustomConfigJson)
|
|
|
|
|
.WithDataJson(DataJson)
|
|
|
|
|
.AllowIDFAAccess(AllowIDFAAccess)
|
|
|
|
|
.WithATags(ATags)
|
|
|
|
|
.Build();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplyAdConfig(ADConfig adConfig)
|
|
|
|
|
{
|
|
|
|
|
if (adConfig == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MediaId = ParseLong(adConfig.Id) ?? MediaId;
|
|
|
|
|
MediaKey = string.IsNullOrWhiteSpace(adConfig.Key) ? MediaKey : adConfig.Key.Trim();
|
|
|
|
|
MediaName = string.IsNullOrWhiteSpace(adConfig.Key2) ? MediaName : adConfig.Key2.Trim();
|
|
|
|
|
ApplyCommonKeyValues(adConfig.CommonKeyValues);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplyCommonKeyValues(List<AdKeyValue> keyValues)
|
|
|
|
|
{
|
|
|
|
|
if (keyValues == null || keyValues.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
foreach (var keyValue in keyValues)
|
|
|
|
|
{
|
|
|
|
|
if (keyValue == null || string.IsNullOrWhiteSpace(keyValue.key))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
map[keyValue.key.Trim()] = keyValue.value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ApplyMap(map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplyLegacyArgs(object[] args)
|
|
|
|
|
{
|
|
|
|
|
if (args == null || args.Length == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (args.Length > 0 && args[0] is string channel)
|
|
|
|
|
{
|
|
|
|
|
Channel = channel;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (args.Length > 1 && TryConvertBool(args[1], out var debug))
|
|
|
|
|
{
|
|
|
|
|
Debug = debug;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplyExplicitOptions(TapadnControllerOptions incoming)
|
|
|
|
|
{
|
|
|
|
|
if (incoming == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MediaId = incoming.MediaId > 0 ? incoming.MediaId : MediaId;
|
|
|
|
|
MediaName = incoming.MediaName ?? MediaName;
|
|
|
|
|
MediaKey = incoming.MediaKey ?? MediaKey;
|
|
|
|
|
Channel = incoming.Channel ?? Channel;
|
|
|
|
|
SubChannel = incoming.SubChannel ?? SubChannel;
|
|
|
|
|
Debug = incoming.Debug;
|
|
|
|
|
TapClientId = incoming.TapClientId ?? TapClientId;
|
|
|
|
|
ShakeEnabled = incoming.ShakeEnabled;
|
|
|
|
|
CustomConfigJson = incoming.CustomConfigJson ?? CustomConfigJson;
|
|
|
|
|
DataJson = incoming.DataJson ?? DataJson;
|
|
|
|
|
ATags = incoming.ATags ?? ATags;
|
|
|
|
|
AllowIDFAAccess = incoming.AllowIDFAAccess;
|
|
|
|
|
RequestPermissionOnInit = incoming.RequestPermissionOnInit;
|
|
|
|
|
RewardedAutoLoad = incoming.RewardedAutoLoad;
|
|
|
|
|
RewardedPrewarmOnInit = incoming.RewardedPrewarmOnInit;
|
|
|
|
|
RewardedMaxLoadAttempts = incoming.RewardedMaxLoadAttempts;
|
|
|
|
|
RewardedLoadRetryDelayMs = incoming.RewardedLoadRetryDelayMs;
|
|
|
|
|
RewardedShowTimeoutMs = incoming.RewardedShowTimeoutMs;
|
2026-06-17 15:40:25 +08:00
|
|
|
RewardedCacheMaxAgeSeconds = incoming.RewardedCacheMaxAgeSeconds;
|
|
|
|
|
if (incoming.RewardedSceneSlotIds != null && incoming.RewardedSceneSlotIds.Count > 0)
|
|
|
|
|
{
|
|
|
|
|
RewardedSceneSlotIds = CloneSceneSlotMap(incoming.RewardedSceneSlotIds);
|
|
|
|
|
}
|
2026-06-04 17:16:17 +08:00
|
|
|
RewardName = incoming.RewardName ?? RewardName;
|
|
|
|
|
RewardAmount = incoming.RewardAmount;
|
|
|
|
|
InterstitialAutoLoad = incoming.InterstitialAutoLoad;
|
|
|
|
|
InterstitialPrewarmOnInit = incoming.InterstitialPrewarmOnInit;
|
|
|
|
|
InterstitialMaxLoadAttempts = incoming.InterstitialMaxLoadAttempts;
|
|
|
|
|
InterstitialLoadRetryDelayMs = incoming.InterstitialLoadRetryDelayMs;
|
|
|
|
|
InterstitialShowTimeoutMs = incoming.InterstitialShowTimeoutMs;
|
|
|
|
|
SplashAutoLoad = incoming.SplashAutoLoad;
|
|
|
|
|
SplashPrewarmOnInit = incoming.SplashPrewarmOnInit;
|
|
|
|
|
SplashMaxLoadAttempts = incoming.SplashMaxLoadAttempts;
|
|
|
|
|
SplashLoadRetryDelayMs = incoming.SplashLoadRetryDelayMs;
|
|
|
|
|
SplashShowTimeoutMs = incoming.SplashShowTimeoutMs;
|
2026-06-05 21:44:35 +08:00
|
|
|
SmartPreloadEnabled = incoming.SmartPreloadEnabled;
|
|
|
|
|
SmartPreloadConfigAssetPath = incoming.SmartPreloadConfigAssetPath ?? SmartPreloadConfigAssetPath;
|
|
|
|
|
SmartPreloadConfigJson = incoming.SmartPreloadConfigJson;
|
|
|
|
|
SmartPreloadRemoteConfigJson = incoming.SmartPreloadRemoteConfigJson;
|
2026-06-04 17:16:17 +08:00
|
|
|
ExpressWidth = incoming.ExpressWidth ?? ExpressWidth;
|
|
|
|
|
ExpressHeight = incoming.ExpressHeight ?? ExpressHeight;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplyDictionary(IDictionary dictionary)
|
|
|
|
|
{
|
|
|
|
|
if (dictionary == null || dictionary.Count == 0)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var map = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
|
|
|
|
foreach (DictionaryEntry entry in dictionary)
|
|
|
|
|
{
|
|
|
|
|
if (entry.Key == null)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
map[entry.Key.ToString()] = ConvertDictionaryValue(entry.Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ApplyMap(map);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplyMap(IDictionary<string, string> map)
|
|
|
|
|
{
|
|
|
|
|
MediaId = GetLong(map, MediaIdKey, "media_id") ?? MediaId;
|
|
|
|
|
MediaName = GetString(map, MediaNameKey, "media_name") ?? MediaName;
|
|
|
|
|
MediaKey = GetString(map, MediaKeyKey, "media_key") ?? MediaKey;
|
|
|
|
|
Channel = GetString(map, ChannelKey, "channel") ?? Channel;
|
|
|
|
|
SubChannel = GetString(map, SubChannelKey, "sub_channel") ?? SubChannel;
|
|
|
|
|
Debug = GetBool(map, DebugKey, "debug") ?? Debug;
|
|
|
|
|
TapClientId = GetString(map, TapClientIdKey, "tap_client_id") ?? TapClientId;
|
|
|
|
|
ShakeEnabled = GetBool(map, ShakeEnabledKey) ?? ShakeEnabled;
|
|
|
|
|
CustomConfigJson = GetString(map, CustomConfigJsonKey) ?? CustomConfigJson;
|
|
|
|
|
DataJson = GetString(map, DataJsonKey) ?? DataJson;
|
|
|
|
|
ATags = GetString(map, ATagsKey) ?? ATags;
|
|
|
|
|
AllowIDFAAccess = GetBool(map, AllowIdfaAccessKey) ?? AllowIDFAAccess;
|
|
|
|
|
RequestPermissionOnInit = GetBool(map, RequestPermissionOnInitKey) ?? RequestPermissionOnInit;
|
|
|
|
|
RewardedAutoLoad = GetBool(map, RewardedAutoLoadKey) ?? RewardedAutoLoad;
|
|
|
|
|
RewardedPrewarmOnInit = GetBool(map, RewardedPrewarmOnInitKey) ?? RewardedPrewarmOnInit;
|
|
|
|
|
RewardedMaxLoadAttempts = GetInt(map, RewardedMaxLoadAttemptsKey) ?? RewardedMaxLoadAttempts;
|
|
|
|
|
RewardedLoadRetryDelayMs = GetInt(map, RewardedLoadRetryDelayMsKey) ?? RewardedLoadRetryDelayMs;
|
|
|
|
|
RewardedShowTimeoutMs = GetInt(map, RewardedShowTimeoutMsKey) ?? RewardedShowTimeoutMs;
|
2026-06-17 15:40:25 +08:00
|
|
|
RewardedCacheMaxAgeSeconds = Math.Max(0, GetInt(map, RewardedCacheMaxAgeSecondsKey) ?? RewardedCacheMaxAgeSeconds);
|
|
|
|
|
ApplyRewardedSceneSlots(map);
|
2026-06-04 17:16:17 +08:00
|
|
|
RewardName = GetString(map, RewardNameKey) ?? RewardName;
|
|
|
|
|
RewardAmount = GetInt(map, RewardAmountKey) ?? RewardAmount;
|
|
|
|
|
InterstitialAutoLoad = GetBool(map, InterstitialAutoLoadKey) ?? InterstitialAutoLoad;
|
|
|
|
|
InterstitialPrewarmOnInit = GetBool(map, InterstitialPrewarmOnInitKey) ?? InterstitialPrewarmOnInit;
|
|
|
|
|
InterstitialMaxLoadAttempts = GetInt(map, InterstitialMaxLoadAttemptsKey) ?? InterstitialMaxLoadAttempts;
|
|
|
|
|
InterstitialLoadRetryDelayMs = GetInt(map, InterstitialLoadRetryDelayMsKey) ?? InterstitialLoadRetryDelayMs;
|
|
|
|
|
InterstitialShowTimeoutMs = GetInt(map, InterstitialShowTimeoutMsKey) ?? InterstitialShowTimeoutMs;
|
|
|
|
|
SplashAutoLoad = GetBool(map, SplashAutoLoadKey) ?? SplashAutoLoad;
|
|
|
|
|
SplashPrewarmOnInit = GetBool(map, SplashPrewarmOnInitKey) ?? SplashPrewarmOnInit;
|
|
|
|
|
SplashMaxLoadAttempts = GetInt(map, SplashMaxLoadAttemptsKey) ?? SplashMaxLoadAttempts;
|
|
|
|
|
SplashLoadRetryDelayMs = GetInt(map, SplashLoadRetryDelayMsKey) ?? SplashLoadRetryDelayMs;
|
|
|
|
|
SplashShowTimeoutMs = GetInt(map, SplashShowTimeoutMsKey) ?? SplashShowTimeoutMs;
|
2026-06-05 21:44:35 +08:00
|
|
|
SmartPreloadEnabled = GetBool(map, SmartPreloadEnabledKey) ?? SmartPreloadEnabled;
|
|
|
|
|
SmartPreloadConfigAssetPath = GetString(map, SmartPreloadConfigAssetPathKey) ?? SmartPreloadConfigAssetPath;
|
|
|
|
|
SmartPreloadConfigJson = GetString(map, SmartPreloadConfigJsonKey) ?? SmartPreloadConfigJson;
|
|
|
|
|
SmartPreloadRemoteConfigJson = GetString(map, SmartPreloadRemoteConfigJsonKey) ?? SmartPreloadRemoteConfigJson;
|
2026-06-04 17:16:17 +08:00
|
|
|
ExpressWidth = GetInt(map, ExpressWidthKey) ?? ExpressWidth;
|
|
|
|
|
ExpressHeight = GetInt(map, ExpressHeightKey) ?? ExpressHeight;
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-17 15:40:25 +08:00
|
|
|
public string ResolveRewardedSlotId(string defaultSlotId, string scenario)
|
|
|
|
|
{
|
|
|
|
|
var normalizedScenario = NormalizeScenario(scenario);
|
|
|
|
|
if (RewardedSceneSlotIds != null &&
|
|
|
|
|
RewardedSceneSlotIds.TryGetValue(normalizedScenario, out var mappedSlotId) &&
|
|
|
|
|
TapadnAdRequestFactory.TryParseSlotId(mappedSlotId, out _))
|
|
|
|
|
{
|
|
|
|
|
return mappedSlotId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return defaultSlotId;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void ApplyRewardedSceneSlots(IDictionary<string, string> map)
|
|
|
|
|
{
|
|
|
|
|
foreach (var entry in map)
|
|
|
|
|
{
|
|
|
|
|
if (entry.Key == null || !entry.Key.StartsWith(RewardedSceneSlotPrefix, StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var scene = entry.Key.Substring(RewardedSceneSlotPrefix.Length);
|
|
|
|
|
AddRewardedSceneSlot(scene, entry.Value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ParseSceneSlotPairs(GetString(map, RewardedSceneSlotsKey), AddRewardedSceneSlot);
|
|
|
|
|
ParseSceneSlotJson(GetString(map, RewardedSceneSlotsJsonKey), AddRewardedSceneSlot);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private void AddRewardedSceneSlot(string scene, string slotId)
|
|
|
|
|
{
|
|
|
|
|
scene = NormalizeScenario(scene);
|
|
|
|
|
if (string.IsNullOrWhiteSpace(slotId) || !TapadnAdRequestFactory.TryParseSlotId(slotId.Trim(), out _))
|
|
|
|
|
{
|
|
|
|
|
UnityEngine.Debug.LogWarning($"[TapADN] Ignore invalid rewarded scene slot. scene={scene}, slot={slotId}");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
RewardedSceneSlotIds[scene] = slotId.Trim();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void ParseSceneSlotPairs(string value, Action<string, string> add)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(value) || add == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
var pairs = value.Split(new[] { ',', ';', '\n', '\r', '|' }, StringSplitOptions.RemoveEmptyEntries);
|
|
|
|
|
foreach (var pair in pairs)
|
|
|
|
|
{
|
|
|
|
|
var separatorIndex = pair.IndexOf('=');
|
|
|
|
|
if (separatorIndex < 0)
|
|
|
|
|
{
|
|
|
|
|
separatorIndex = pair.IndexOf(':');
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (separatorIndex <= 0 || separatorIndex >= pair.Length - 1)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add(pair.Substring(0, separatorIndex), pair.Substring(separatorIndex + 1));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static void ParseSceneSlotJson(string json, Action<string, string> add)
|
|
|
|
|
{
|
|
|
|
|
if (string.IsNullOrWhiteSpace(json) || add == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
var parsed = JsonUtility.FromJson<TapadnSceneSlotMapConfig>(json);
|
|
|
|
|
if (parsed?.Mappings == null)
|
|
|
|
|
{
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
foreach (var mapping in parsed.Mappings)
|
|
|
|
|
{
|
|
|
|
|
if (mapping == null)
|
|
|
|
|
{
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
add(mapping.Scene, mapping.SlotId);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
catch (Exception exception)
|
|
|
|
|
{
|
|
|
|
|
UnityEngine.Debug.LogWarning($"[TapADN] Parse rewarded scene slot JSON failed: {exception.Message}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static Dictionary<string, string> CloneSceneSlotMap(Dictionary<string, string> source)
|
|
|
|
|
{
|
|
|
|
|
return source == null
|
|
|
|
|
? new Dictionary<string, string>(StringComparer.Ordinal)
|
|
|
|
|
: new Dictionary<string, string>(source, StringComparer.Ordinal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string NormalizeScenario(string scenario)
|
|
|
|
|
{
|
|
|
|
|
return string.IsNullOrWhiteSpace(scenario) ? "__default__" : scenario.Trim();
|
|
|
|
|
}
|
|
|
|
|
|
2026-06-04 17:16:17 +08:00
|
|
|
private static string GetString(IDictionary<string, string> map, params string[] keys)
|
|
|
|
|
{
|
|
|
|
|
foreach (var key in keys)
|
|
|
|
|
{
|
|
|
|
|
if (!string.IsNullOrWhiteSpace(key) &&
|
|
|
|
|
map.TryGetValue(key, out var value) &&
|
|
|
|
|
!string.IsNullOrWhiteSpace(value))
|
|
|
|
|
{
|
|
|
|
|
return value.Trim();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool? GetBool(IDictionary<string, string> map, params string[] keys)
|
|
|
|
|
{
|
|
|
|
|
var value = GetString(map, keys);
|
|
|
|
|
return TryConvertBool(value, out var result) ? result : null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static int? GetInt(IDictionary<string, string> map, params string[] keys)
|
|
|
|
|
{
|
|
|
|
|
var value = GetString(map, keys);
|
|
|
|
|
return int.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) ? result : (int?)null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static long? GetLong(IDictionary<string, string> map, params string[] keys)
|
|
|
|
|
{
|
|
|
|
|
return ParseLong(GetString(map, keys));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static long? ParseLong(string value)
|
|
|
|
|
{
|
|
|
|
|
return long.TryParse(value, NumberStyles.Integer, CultureInfo.InvariantCulture, out var result) ? result : (long?)null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static bool TryConvertBool(object value, out bool result)
|
|
|
|
|
{
|
|
|
|
|
switch (value)
|
|
|
|
|
{
|
|
|
|
|
case bool boolValue:
|
|
|
|
|
result = boolValue;
|
|
|
|
|
return true;
|
|
|
|
|
case string stringValue:
|
|
|
|
|
if (bool.TryParse(stringValue, out result))
|
|
|
|
|
{
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.Equals(stringValue, "1", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
result = true;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (string.Equals(stringValue, "0", StringComparison.OrdinalIgnoreCase))
|
|
|
|
|
{
|
|
|
|
|
result = false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
result = false;
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private static string ConvertDictionaryValue(object value)
|
|
|
|
|
{
|
|
|
|
|
if (value == null)
|
|
|
|
|
{
|
|
|
|
|
return null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value is string stringValue)
|
|
|
|
|
{
|
|
|
|
|
return stringValue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value is IEnumerable enumerable)
|
|
|
|
|
{
|
|
|
|
|
var items = new List<string>();
|
|
|
|
|
foreach (var item in enumerable)
|
|
|
|
|
{
|
|
|
|
|
if (item != null)
|
|
|
|
|
{
|
|
|
|
|
items.Add(item.ToString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return string.Join(",", items.ToArray());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return value.ToString();
|
|
|
|
|
}
|
2026-06-17 15:40:25 +08:00
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
private sealed class TapadnSceneSlotMapConfig
|
|
|
|
|
{
|
|
|
|
|
public List<TapadnSceneSlotMapping> Mappings;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
[Serializable]
|
|
|
|
|
private sealed class TapadnSceneSlotMapping
|
|
|
|
|
{
|
|
|
|
|
public string Scene;
|
|
|
|
|
public string SlotId;
|
|
|
|
|
}
|
2026-06-04 17:16:17 +08:00
|
|
|
}
|