// Only SDK/engine/business dependencies are replaced. Four service sources are linked unchanged. using PlayFab.ClientModels; using Newtonsoft.Json; // Legacy desktop fallback names AndroidDeviceId on CustomID request (unreachable with validated CustomId). // Keep this compatibility DTO local; do not silently change the pre-existing PF branch in production. namespace PlayFab.ClientModels { public class LoginWithCustomIDRequest { public string CustomId,AndroidDeviceId;public bool CreateAccount;public GetPlayerCombinedInfoRequestParams InfoRequestParameters; } } static class Effects { internal static int SDK,Prefs,Events,Subscriptions,Helpers,Rewards,UI,Timers,Account; internal static void Clear() { SDK=Prefs=Events=Subscriptions=Helpers=Rewards=UI=Timers=Account=0; } internal static int Total => SDK+Prefs+Events+Subscriptions+Helpers+Rewards+UI+Timers+Account; } namespace UnityEngine { public static class Mathf { public static int Min(int a, int b) => Math.Min(a, b); } public class Object { public static implicit operator bool(Object value)=>value!=null; public static void DontDestroyOnLoad(Object o){} } public class GameObject:Object { public static object Found; public static T FindObjectOfType() where T:class =>Found as T; public T AddComponent() where T:new(){Effects.Helpers++;return new T();} } public class MonoBehaviour:Object { public GameObject gameObject=new(); public T GetComponent() where T:class=>null; } public static class Debug { internal static readonly List Errors=new(); public static void Log(object o){} public static void LogWarning(object o){} public static void LogError(object o){Errors.Add(o?.ToString());} public static void LogException(Exception e){System.Console.WriteLine("fixture observed exception: " + e);} } public static class Application { public static string version="synthetic",identifier="101",persistentDataPath=Path.GetTempPath(); public static event Action quitting; public static void QuitForTest()=>quitting?.Invoke(); } public static class SystemInfo { public static string deviceUniqueIdentifier="101",deviceModel="stub"; } public static class PlayerPrefs { public static readonly Dictionary Data=new(); public static string GetString(string key,string fallback=""){Effects.Prefs++;return Data.GetValueOrDefault(key,fallback);} public static void SetString(string key,string value){Effects.Prefs++;Data[key]=value;} public static bool HasKey(string key) => Data.ContainsKey(key); public static int GetInt(string key,int fallback=0)=>throw new NotSupportedException("Activity preference is not under test."); public static void SetInt(string key,int value)=>throw new NotSupportedException("Activity preference is not under test."); public static void Save(){Effects.Prefs++;} } } namespace asap.core { public class InjectAttribute:Attribute{} public interface IConfig { T Get(string key,T fallback); void Set(string key,object value); } public static class Awaiters { public static Task NextFrame=>Task.CompletedTask; internal static Func SecondsOverride; public static Task Seconds(float value)=>SecondsOverride?.Invoke(value) ?? throw new NotSupportedException("Unexpected timer."); } } sealed class Config:asap.core.IConfig { internal readonly Dictionary Values=new(); public T Get(string key,T fallback)=>Values.TryGetValue(key,out var v)?(T)v:fallback; public void Set(string key,object value)=>Values[key]=value; } namespace UniRx { public sealed class Stream : IObservable { internal static Action Handlers; public IDisposable Subscribe(Action action){Effects.Subscriptions++;Handlers+=action;return new Subscription(()=>Handlers-=action);} public IDisposable Subscribe(IObserver observer) => Subscribe(observer.OnNext); } public sealed class Subscription:IDisposable { readonly Action action; public Subscription(Action action)=>this.action=action;public void Dispose()=>action(); } public sealed class CompositeDisposable : IDisposable { readonly List values = new(); public void Add(IDisposable value) => values.Add(value); public void Dispose() { foreach (var value in values) value.Dispose(); values.Clear(); } } public static class ProbeRxExtensions { sealed class Observer : IObserver { readonly Action next; internal Observer(Action next) { this.next = next; } public void OnNext(T value) => next(value); public void OnCompleted() { } public void OnError(Exception error) => throw error; } public static IDisposable Subscribe(this IObservable source, Action next) => source.Subscribe(new Observer(next)); public static void AddTo(this IDisposable subscription, CompositeDisposable subscriptions) => subscriptions.Add(subscription); } } namespace cfg { public sealed class Tables { public GlobalConfig TbGlobalConfig { get; } = new(); public TbSurveyData TbSurveyData { get; } = new(); public TbAutoDeliveryMail TbAutoDeliveryMail { get; } = new(); public TbInvite TbInvite { get; } = new(); public TbMapData TbMapData {get;}=new(); public UnusedTable TbFishingEvent {get;}=new(); public UnusedTable TbRankInit {get;}=new(); public UnusedTable TbRankTargets {get;}=new(); public UnusedTable TbRobot {get;}=new(); } public sealed class MapData { public int LevelRequired; } public sealed class TbMapData { public List DataList=new(); } public sealed class FishingEvent { public int ID,RedirectID; } public sealed class RankInit { public int UnlockPoint; public List TargetList; } public sealed class RankTargets { public int NextTarget,TokenRequiredB; } public sealed class Robot { public string Name_l10n_key,Avatar; } public sealed class UnusedTable { public T GetOrDefault(int id)=>throw new NotSupportedException("Activity leaderboard is not under test."); public Dictionary DataMap=>throw new NotSupportedException("Activity leaderboard is not under test."); } public sealed class Invite { public int NumInvite, DropID; } public sealed class TbInvite { public List DataList = new(); } public sealed class SurveyData { public int ID, LevelCondition, Reward; public string Hash; public List TailNumberList = new(); } public sealed class TbSurveyData { public List DataList = new(); } public sealed class AutoDeliveryMail { public int MailID, ExpireDay, DropID; public List AccountLevelRange = new(); public string AccountCreateTimestamp, Title_l10n_key, Content_l10n_key, Inscribe_l10n_key; public List LoginTimestampRange = new(); } public sealed class TbAutoDeliveryMail { public Dictionary DataMap = new(); public List DataList = new(); } public sealed class GlobalConfig { public int GlobalTimeOffset = 9; } } public static class GContext { public static readonly Container container=new(); public static UniRx.Stream OnEvent()=>new(); public static void Publish(T value){Effects.Events++;UniRx.Stream.Handlers?.Invoke(value);} } public static class SubBoostrap { internal static game.PlayerDataStorage.PlayerKVRuntimeSelection RuntimeSelection { get; set; } } namespace game.PlayerDataStorage { // The service-host verifies service branch behavior; Unity resolves the real 31-module binding. internal static class PlayerKVGameplayBindings { internal static Func BindFactory; internal static Func SnapshotFactory; internal static PlayerKVGameLoadTransaction Bind(IKVUserLoadReceiver user) => BindFactory?.Invoke(user) ?? throw new NotSupportedException("Unity module binding required."); internal static PlayerKVSchemaSnapshot Snapshot(DateTime nowUtc,string version="kv-loop") => SnapshotFactory?.Invoke() ?? throw new NotSupportedException("Unity configuration required."); } } public sealed class Container { public readonly Dictionary Values=new();public T Resolve()=> (T)Values[typeof(T)]; public object ResolveStage(string name)=>throw new NotSupportedException("Stage is not under test."); } public static class GameDebug { public static void LogError(string s,params object[] a){} } public static class ZZTimeHelper { public static DateTime UtcNow()=>new(2026,9,23,0,0,0,DateTimeKind.Utc); public static bool Adjusted; public static void AdjustTime(DateTime t)=>Adjusted=true;public static void WathForcusChange(){} } public static class GConstant { public const string K_Event_API_URL="EventApiURL",K_AssetVersion="AssetVersion",Yidun_GooglePlayChannel="stub",Yidun_AndroidBusinessId="stub",K_PlayFab_Title="PFTitle",V_Debug_PF_Title="stub",K_PlayFab_TimeOut="PFTimeout"; } namespace LitJson { public static class JsonMapper { public static string ToJson(object o)=>JsonConvert.SerializeObject(o);public static T ToObject(string s)=>JsonConvert.DeserializeObject(s); } } namespace GameCore { } // The real repository only needs the event marker; production model behavior is verified in Unity separately. namespace Activity.Data { public interface IEventData { } } namespace YiDun.Protector { public class YiDunManager { } } namespace PlayFab { public static class PlayFabClientAPI { public static bool Logged; public static bool IsClientLoggedIn(){Effects.SDK++;return Logged;} public static void ForgetAllCredentials(){Effects.SDK++;Logged=false;} public static void UpdateUserData(UpdateUserDataRequest r,Action ok,Action fail){Effects.SDK++;ok?.Invoke(new());} } public static class PlayFabSettings { public static string TitleId;public static int RequestTimeout; } } namespace PlayFab.Internal { public static class PlayFabWebRequest { public static void SkipCertificateValidation(){Effects.SDK++;} } } namespace asap.playfab.async { public static class PlayFabClientAsyncAPI { internal static LoginResult Result; internal static Func> LoginOverride; internal static readonly List StatisticsRequests=new(); internal static Func> StatisticsOverride; public static Task UpdatePlayerStatisticsAsync(UpdatePlayerStatisticsRequest r){Effects.SDK++;StatisticsRequests.Add(r);return StatisticsOverride?.Invoke() ?? Task.FromResult(new UpdatePlayerStatisticsResult());} public static Task GetLeaderboardAsync(GetLeaderboardRequest r){Effects.SDK++;throw new NotSupportedException("Unmigrated leaderboard read.");} public static Task ExecuteWithRetryAsync(Func> call)=>call(); public static Task LoginWithCustomIDAsync(LoginWithCustomIDRequest r){Effects.SDK++;PlayFab.PlayFabClientAPI.Logged=Result!=null;return LoginOverride?.Invoke() ?? Task.FromResult(Result);} public static Task LoginWithAndroidDeviceIDAsync(LoginWithAndroidDeviceIDRequest r)=>LoginWithCustomIDAsync(new()); public static Task GetPlayerProfileAsync(GetPlayerProfileRequest r){Effects.SDK++;return Task.FromResult(new GetPlayerProfileResult{PlayerProfile=new PlayerProfileModel{Locations=new(){new LocationModel()}}});} public static Task UpdateUserTitleDisplayNameAsync(UpdateUserTitleDisplayNameRequest r){Effects.SDK++;return Task.FromResult(new UpdateUserTitleDisplayNameResult{DisplayName=r.DisplayName});} public static Task UpdateAvatarUrlAsync(UpdateAvatarUrlRequest r){Effects.SDK++;return Task.FromResult(new EmptyResponse());} public static Task GetUserDataAsync(GetUserDataRequest r){Effects.SDK++;return Task.FromResult(new GetUserDataResult{Data=new()});} public static Task GetFriendsListAsync(GetFriendsListRequest r){Effects.SDK++;throw new InvalidOperationException("Unmigrated PF friend-list SDK must not be exercised by the UserID compatibility test.");} } public static class PlayFabProfilesAsyncAPI { public static Task SetProfileLanguageAsync(PlayFab.ProfilesModels.SetProfileLanguageRequest r){Effects.SDK++;return Task.FromResult(new PlayFab.ProfilesModels.SetProfileLanguageResponse());} } } namespace tysdk { public enum EAccoutType {hwGoogle,hwFacebook,hwGuest,hwVkid,Apple,none} public class LoginInfo { public bool isSuccess; public int userId;public string StrUserId=>userId.ToString(); } public sealed class TYSdkFacade { public sealed class AccountInfo {public EAccoutType channel;public string userName,avatar;public int userId;public List linkedAccout=new();} public static AccountInfo TYAccountInfo=new(){userId=101,channel=EAccoutType.hwGuest}; public static bool IsLoggedIn; public static TYSdkFacade Instance=new(); internal static Func> LoginOverride; public Task LoginBySns(){Effects.SDK++;return LoginOverride?.Invoke() ?? Task.FromResult(new LoginInfo{isSuccess=true,userId=101});} public Task LoginByToken()=>LoginBySns();public Task Login(EAccoutType type)=>LoginBySns(); public void Logout(){Effects.SDK++;IsLoggedIn=false;} public Task LinkCheck(EAccoutType t){Effects.SDK++;return Task.FromResult(false);} public Task<(int code,int userId)> LinkAccount(EAccoutType t){Effects.SDK++;return Task.FromResult((1,0));} } } public static class ChannelManager { public static bool IsRustoreStore=>false; } public class AFHelper { public static AFHelper Instance=new();public bool GetDLReferer(out string pid,out string uid){pid=uid=null;return false;} } public static class GEvent { public sealed class Event:IDisposable { public Event AddContent(string k,object v)=>this;public void Dispose(){} } public static Event GameEvent(string name){Effects.Events++;return new();} public static Event LoginEvent()=>GameEvent("login");public static Event CompleteRegistrationEvent()=>GameEvent("registration"); public static void SetProp(string k,object v){Effects.Events++;}public static void SetUserProp(string k,object v,bool b=true){Effects.Events++;} public static void SetProps(Dictionary p){Effects.Events++;}public static void SetUserProps(Dictionary p){Effects.Events++;} public static void OnLogin(string a,string b){Effects.Events++;} } namespace game { public interface IChatService { void WaitingForLogin(); } public interface ISettingService { string Lang {get;} } // CP3A's real Setting/Club/Notification instances are exercised by the Unity CLI Loop fixed case. public interface ILocalNotificationService { } public sealed class DefaultSettingService : ISettingService { public string Lang => "en"; public static InvalidOperationException PromptFailure(string message) => new(message); PlayerDataStorage.PlayerKVGameSessionHandle bound; public void PreflightFormalPromptOwner(PlayerDataStorage.PlayerKVGameSessionHandle owner) { if(bound!=null || owner==null) throw new InvalidOperationException(); } public void BindFormalPromptOwner(PlayerDataStorage.PlayerKVGameSessionHandle owner) { PreflightFormalPromptOwner(owner); bound=owner; } public bool HasFormalPromptOwner(PlayerDataStorage.PlayerKVGameSessionHandle owner) => ReferenceEquals(bound,owner); } public sealed class ClubService { PlayerDataStorage.PlayerKVGameSessionHandle bound; public void PreflightFormalPromptOwner(PlayerDataStorage.PlayerKVGameSessionHandle owner) { if(bound!=null || owner==null) throw new InvalidOperationException(); } public void BindFormalPromptOwner(PlayerDataStorage.PlayerKVGameSessionHandle owner) { PreflightFormalPromptOwner(owner); bound=owner; } public bool HasFormalPromptOwner(PlayerDataStorage.PlayerKVGameSessionHandle owner) => ReferenceEquals(bound,owner); } public sealed class LocalNotificationService : ILocalNotificationService { DefaultSettingService bound; public void PreflightFormalPromptSettings(DefaultSettingService settings) { if(bound!=null || settings==null) throw new InvalidOperationException(); } public void BindFormalPromptSettings(DefaultSettingService settings) { PreflightFormalPromptSettings(settings); bound=settings; } public bool HasFormalPromptSettings(DefaultSettingService settings) => ReferenceEquals(bound,settings); } public class MMTService { public string Init(int value){Effects.Events++;return value.ToString();} } public class PlayerData { public string InfiniteBuildingLevel; public Action Save; public void SavePlayerData() => Save?.Invoke(); public int lv=1;public int Loads;public void LoadPlayerData(IDictionary data){if(!ZZTimeHelper.Adjusted)throw new Exception("PF time not adjusted");Loads++;} } public class ChangeAvatarEvent{} public class GetClubPlayInfoEvent { public string id,name,avatarUrl; } public class ItemData {public int id,count,origin;public ulong curCount;} public class FishingEventData { public Dictionary RankTargetCount=>throw new NotSupportedException("Activity reward is not under test."); } public class FishingStage { public bool IsNextQueue; public string NextQueueKey; } public class ChangeSource { public ChangeSource(int id,string a,string b,string c)=>throw new NotSupportedException("Activity reward is not under test."); } public interface IFaceUIService { void AddGiftFaceUI(int id, UITypes type); } public enum UITypes { EventRankPopupPanel } public enum RewardType {NormalOne} public class ShowData {public ShowData(){}public ShowData(List items,RewardType t){Effects.UI++;}} public class PlayerItemData { public Action Drop; public void AddItemByDrop(int id, object change) => Drop?.Invoke(id, false); public List AddItemByDrop(int id, object change, bool value) => throw new NotSupportedException("Activity reward is not under test."); public void AddItemByDropList(List ids, object change) { foreach (var id in ids) Drop?.Invoke(id, false); } public void AddItemByDropListLureInflation(float? inflation, List ids, object change) { foreach (var id in ids) Drop?.Invoke(id, true); } public int GetItemCount(int id)=>0;public void AddItem(ItemData i,object o){Effects.Rewards++;}} public class TapjoyHelper:UnityEngine.MonoBehaviour {public void Init(int balance,Action earn,Action changed){Effects.Helpers++;}} } namespace TapjoyUnity.Internal { public class TapjoyComponent:UnityEngine.MonoBehaviour{} } namespace UnityEngine.Assertions { public static class Assert { public static void IsNotNull(object value) { if(value==null) throw new Exception("Unexpected null in real mail cache."); } } } public sealed class RedPointManager { public static RedPointManager Instance { get; } = new(); public void SetRedPointState(string key, bool active, int count = 0) { } } public static class RedPointName { public const string Unread_Mail = "mail", Home_Invite="invite", Home_Friend_Add="friend-add"; } public static class LocalizationMgr { public static string GetText(string key) => key; } public sealed class OnLvChangeEvent { public int lvl; } public interface IRTService { IDisposable OnEvent(Func action); } namespace UniRx { public static class MailProbeRxExtensions { public static IObservable Skip(this IObservable source, int count) => source; public static IObservable Where(this IObservable source, Func predicate) => source; } }