using System; using System.Globalization; using System.Linq; using ShiroginSDK.Runtime.Services.Base; using ShiroginSDK.Runtime.Services.Interfaces; using UnityEngine; namespace ShiroginSDK.Runtime.Modules.Data.Scripts { /// /// Unified Remote Config system that merges local BaseData cache /// and remote Firebase values. /// [Serializable] public class RemoteConfigData : BaseData { // --------------------------- // 🔹 Gameplay & Ads Settings // --------------------------- public int InterstitialTime = 180; public int RewardedAfterInterstitialTime = 50; public int FirstGameInterstitialTime = 120; public int HpScale = 100; public int DamageScale = 100; public int ReviveCount = 1; public int ReviveTime = 8; public int RewardedAdSkipTime = 1; public int RewardedSkillOfferCD = 45; public string GameName = "default_game_name"; public string IOSRemoveAds = "dihe_noads"; public string AndroidRemoveAds = "dihe_noads"; public bool RemoveAdsPopupActive = true; public int RemoveAdsPopupFrequency = 10; public int PassiveUpgradeBasePrice = 10; public int RateUsShowGameCount = 2; public int TargetFps = 60; public float[] EnemyHpMultiplier = { 1, 1.4f, 2, 2.5f, 3, 3.5f, 4, 4.5f, 5, 6 }; public float[] EnemyDamageMultiplier = { 1, 1.4f, 2, 2, 2.5f, 3, 3, 3.5f, 4, 4 }; public float ExpMultiplier = 1f; public float GoldMultiplier = 1f; public float[] BossHpMultiplier = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; public float[] BossDamageMultiplier = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; public int ForceOpenStoreStartGameCount = 2; public int ForceOpenStoreFrequency = 3; public string StoreData = "{}"; // 🔹 CharacterStoreData + IAPStoreData birleşti public bool InterTimeUnscale; public float PauseSceneInterTime = 15000; public bool ShuffleActive = true; public bool IAPStoreActive = true; public int TicketPopupShowRewardedCount = 999999; // 🔹 Firebase RemoteConfig cache metadata public string CachedJson = "{}"; public long LastFetchTicksUtc; protected override string PrefsKey => "REMOTE_CONFIG_DATA"; /// /// Checks whether we should fetch new Firebase data (older than 24h or empty) /// public bool ShouldFetchNewData() { if (string.IsNullOrEmpty(CachedJson) || CachedJson == "{}") return true; if (LastFetchTicksUtc <= 0) return true; var lastFetch = new DateTime(LastFetchTicksUtc, DateTimeKind.Utc); var diff = DateTime.UtcNow - lastFetch; return diff.TotalHours >= 24; } public void UpdateCache(string newJson) { if (string.IsNullOrEmpty(newJson)) newJson = "{}"; CachedJson = newJson; LastFetchTicksUtc = DateTime.UtcNow.Ticks; Save(); } public string GetLastFetchTimeString() { if (LastFetchTicksUtc <= 0) return "Never"; var dt = new DateTime(LastFetchTicksUtc, DateTimeKind.Utc); return dt.ToLocalTime().ToString("yyyy-MM-dd HH:mm:ss"); } /// /// Loads local data, applies remote overrides, and saves updated values. /// public void Initialize() { Load(); // 🔹 Load local cache first var remoteService = ServiceLocator.Get(); if (remoteService == null) { Debug.LogWarning("[RemoteConfigData] ⚠️ IRemoteConfigService not initialized. Using local values."); return; } // Merge logic: local fallback, remote override InterstitialTime = GetIntMerged(remoteService, "interstitial_time", InterstitialTime); RewardedAfterInterstitialTime = GetIntMerged(remoteService, "rewarded_after_interstitial_time", RewardedAfterInterstitialTime); FirstGameInterstitialTime = GetIntMerged(remoteService, "first_game_interstitial_time", FirstGameInterstitialTime); HpScale = GetIntMerged(remoteService, "hp_scale", HpScale); DamageScale = GetIntMerged(remoteService, "damage_scale", DamageScale); ReviveCount = GetIntMerged(remoteService, "revive_count", ReviveCount); ReviveTime = GetIntMerged(remoteService, "revive_time", ReviveTime); RewardedAdSkipTime = GetIntMerged(remoteService, "rewarded_ad_skip_time", RewardedAdSkipTime); RewardedSkillOfferCD = GetIntMerged(remoteService, "rewarded_skill_offer_cd", RewardedSkillOfferCD); RemoveAdsPopupFrequency = GetIntMerged(remoteService, "remove_ads_popup_frequency", RemoveAdsPopupFrequency); PassiveUpgradeBasePrice = GetIntMerged(remoteService, "passive_upgrade_base_price", PassiveUpgradeBasePrice); RateUsShowGameCount = GetIntMerged(remoteService, "rate_us_show_game_count", RateUsShowGameCount); TargetFps = GetIntMerged(remoteService, "target_fps", TargetFps); ForceOpenStoreStartGameCount = GetIntMerged(remoteService, "force_open_store_start_count", ForceOpenStoreStartGameCount); ForceOpenStoreFrequency = GetIntMerged(remoteService, "force_open_store_frequency", ForceOpenStoreFrequency); TicketPopupShowRewardedCount = GetIntMerged(remoteService, "ticket_popup_show_rewarded_count", TicketPopupShowRewardedCount); RemoveAdsPopupActive = GetBoolMerged(remoteService, "remove_ads_popup_active", RemoveAdsPopupActive); InterTimeUnscale = GetBoolMerged(remoteService, "inter_unscale_time", InterTimeUnscale); ShuffleActive = GetBoolMerged(remoteService, "shuffle_active", ShuffleActive); IAPStoreActive = GetBoolMerged(remoteService, "iap_store_active", IAPStoreActive); ExpMultiplier = GetFloatMerged(remoteService, "exp_multiplier", ExpMultiplier); GoldMultiplier = GetFloatMerged(remoteService, "gold_multiplier", GoldMultiplier); PauseSceneInterTime = GetFloatMerged(remoteService, "pause_scene_inter_time", PauseSceneInterTime); GameName = GetStringMerged(remoteService, "game_name", GameName); IOSRemoveAds = GetStringMerged(remoteService, "ios_remove_ads", IOSRemoveAds); AndroidRemoveAds = GetStringMerged(remoteService, "android_remove_ads", AndroidRemoveAds); StoreData = GetStringMerged(remoteService, "store_data", StoreData); // Array parse var ci = (CultureInfo)CultureInfo.InvariantCulture.Clone(); EnemyHpMultiplier = ParseArrayMerged(remoteService, "enemy_hp_multiplier", EnemyHpMultiplier, ci); EnemyDamageMultiplier = ParseArrayMerged(remoteService, "enemy_damage_multiplier", EnemyDamageMultiplier, ci); BossHpMultiplier = ParseArrayMerged(remoteService, "boss_hp_multiplier", BossHpMultiplier, ci); BossDamageMultiplier = ParseArrayMerged(remoteService, "boss_damage_multiplier", BossDamageMultiplier, ci); Save(); Debug.Log("[RemoteConfigData] ✅ Remote + Local merge completed successfully."); } // ----------------------- // 🔧 Merge Helper Methods // ----------------------- private int GetIntMerged(IRemoteConfigService r, string key, int localVal) { return r.GetInt(key, localVal); } private float GetFloatMerged(IRemoteConfigService r, string key, float localVal) { return r.GetFloat(key, localVal); } private bool GetBoolMerged(IRemoteConfigService r, string key, bool localVal) { return r.GetBool(key, localVal); } private string GetStringMerged(IRemoteConfigService r, string key, string localVal) { var remote = r.GetString(key, localVal); return string.IsNullOrEmpty(remote) ? localVal : remote; } private float[] ParseArrayMerged(IRemoteConfigService r, string key, float[] localArray, CultureInfo ci) { var val = r.GetString(key, string.Join(",", localArray.Select(x => x.ToString(ci)))); try { return val.Split(',').Select(x => float.Parse(x, ci)).ToArray(); } catch { return localArray; } } } }