feat(upserver): 保存M2客户端KV迁移至本人统计写检查点
保存独立KV用户服务、固定会话存档与原业务接线,以及C3d资料缓存和C3e本人统计写。 保留原PF/AGG路线、业务公式和时序;榜单读取、好友资料、公告、匹配及首场景闸仍待完成。 验证:ServiceHost两条件各33组646断言;Unity CLI Loop编译0错误269警告。 包含相关方案、评审裁决、测试及状态文档。未操作服务器、正式账号或打包。
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
using game;
|
||||
using game.PlayerDataStorage;
|
||||
|
||||
static partial class Probe
|
||||
{
|
||||
static async Task MergedUser()
|
||||
{
|
||||
var selection = PlayerKVRuntimeSelection.Capture("kv", PlayerKVRuntimeSelection.FormalApiUrl, false);
|
||||
var user = new KVUserService(selection, _ => new Handler(_ => throw new Exception("unexpected HTTP")));
|
||||
Check(user is IUserService && user is IKVUserLoadReceiver && user is IKVUserLifecycle,
|
||||
"independent KV service implements actual consumer contracts");
|
||||
Check(!typeof(PlayFabUserService).IsAssignableFrom(user.GetType()), "KV does not inherit PF");
|
||||
Check(typeof(IUserService).GetProperty("entityKey") == null, "common identity has no PF entity DTO");
|
||||
Check(typeof(IUserService).GetProperty("CustomId").CanWrite, "login input uses common setter");
|
||||
Check(user.GetDefaultName("101") == "Angler#101" && user.GetDefaultName("123456") == "Angler#12345",
|
||||
"short and long identity names");
|
||||
Check(KVUserService.ParseLastLoginTime(null, false) == DateTime.MinValue, "missing login time sentinel");
|
||||
foreach (var value in new[] { "", "bad", "0001-01-01T00:00:00.0000000Z" })
|
||||
{
|
||||
try { KVUserService.ParseLastLoginTime(value, true); throw new Exception("bad time accepted"); }
|
||||
catch (FormatException) { Check(true, "present invalid time is not first login"); }
|
||||
}
|
||||
Check(KVUserService.ParseLastLoginTime("2026-09-28T01:00:00.0000000Z", true).Kind == DateTimeKind.Utc,
|
||||
"stored previous login is UTC");
|
||||
user.Logout();
|
||||
await user.CloseKVForValidationAsync();
|
||||
Pass("merged-KV-contract-and-login-time");
|
||||
await MergedLogin();
|
||||
MergedDailyRefresh();
|
||||
}
|
||||
|
||||
sealed class KVChat : IChatService
|
||||
{
|
||||
internal int Waits;
|
||||
public void WaitingForLogin() { Waits++; }
|
||||
}
|
||||
|
||||
static async Task MergedLogin()
|
||||
{
|
||||
foreach (var scenario in new[] { "success", "save-unknown", "logout-during-save", "corrupt", "logout-during-load" })
|
||||
{
|
||||
var badProfile = scenario == "corrupt";
|
||||
var selection = PlayerKVRuntimeSelection.Capture("kv", PlayerKVRuntimeSelection.FormalApiUrl, false);
|
||||
var config = Configuration(); config.Set("EventApiURL", PlayerKVRuntimeSelection.FormalApiUrl);
|
||||
var root = UnityEngine.Application.persistentDataPath;
|
||||
UnityEngine.Application.persistentDataPath = Path.Combine(Path.GetTempPath(), "ft-merged-" + Guid.NewGuid().ToString("N"));
|
||||
var raw = Raw();
|
||||
var remote = new Dictionary<string, string>(raw);
|
||||
if (badProfile) raw["LastLoginTimeUtc"] = "corrupt";
|
||||
int auth = 0, gets = 0, success = 0, applied = 0;
|
||||
var getStarted = new TaskCompletionSource<bool>();
|
||||
var releaseGet = new TaskCompletionSource<System.Net.Http.HttpResponseMessage>();
|
||||
var setStarted = new TaskCompletionSource<bool>();
|
||||
var releaseSet = new TaskCompletionSource<System.Net.Http.HttpResponseMessage>();
|
||||
Action beforeSet = null;
|
||||
var chat = new KVChat();
|
||||
GContext.container.Values[typeof(IChatService)] = chat;
|
||||
GContext.container.Values[typeof(ISettingService)] = new DefaultSettingService();
|
||||
GContext.container.Values[typeof(ILocalNotificationService)] = new LocalNotificationService();
|
||||
GContext.container.Values[typeof(ClubService)] = new ClubService();
|
||||
PlayerKVGameplayBindings.SnapshotFactory = Snapshot;
|
||||
PlayerKVGameplayBindings.BindFactory = receiver => new PlayerKVGameLoadTransaction(
|
||||
Enumerable.Range(1, 31).Select(id => (IPlayerKVLoadModule)new PlayerKVLoadModule(id,
|
||||
() => { if (id == 31) receiver.ResetForKVLoad(); },
|
||||
decoded => { applied++; if (id == 31) receiver.ReplaceFromKVDecoded(decoded.Module<PlayerKVLoginState>(31), decoded.Epoch, decoded.Raw); })),
|
||||
Environment.CurrentManagedThreadId, receiver.DiscardKVIntents);
|
||||
var server = new CustomServerMgr(config, _ => new Handler(_ => throw new Exception("PF transport forbidden")));
|
||||
var user = new KVUserService(selection, jar => new Handler(request =>
|
||||
{
|
||||
switch (request.RequestUri.AbsolutePath)
|
||||
{
|
||||
case "/account/Login":
|
||||
auth++; jar.Add(selection.Api, new System.Net.Cookie("sid", "synthetic"));
|
||||
return Json(new { state = 0, internalId = 17, newCreate = false,
|
||||
createTime = "2026-01-01T00:00:00Z", svrTime = "2026-09-29T00:00:00Z" });
|
||||
case "/playerdata/Get": gets++; getStarted.TrySetResult(true); return releaseGet.Task;
|
||||
case "/playerdata/Set":
|
||||
var onSet = beforeSet; beforeSet = null; onSet?.Invoke();
|
||||
setStarted.TrySetResult(true);
|
||||
if (scenario == "logout-during-save") return releaseSet.Task;
|
||||
if (scenario == "save-unknown") return Json(new { }, System.Net.HttpStatusCode.InternalServerError);
|
||||
var body = Newtonsoft.Json.Linq.JObject.Parse(request.Content.ReadAsStringAsync().GetAwaiter().GetResult());
|
||||
foreach (var entry in body["data"].ToObject<Dictionary<string, string>>()) remote[entry.Key] = entry.Value;
|
||||
return Json(new { });
|
||||
case "/friend/unauthorized": return Json(new { }, System.Net.HttpStatusCode.Unauthorized);
|
||||
default: throw new Exception("unplanned synthetic route " + request.RequestUri.AbsolutePath);
|
||||
}
|
||||
})) { CustomId = "101", customServerMgr = server, SaveStore = new KVPlayerSaveStore() };
|
||||
using var subscription = GContext.OnEvent<EvtAPISvrLoginSuccess>().Subscribe(evt =>
|
||||
{
|
||||
success++;
|
||||
Check(applied == 31 && chat.Waits == 1 && user.IsAuthorized && user.KVHandoffReady,
|
||||
"identity event follows all modules, chat subscription and original handoff");
|
||||
Check(evt.playerId == "101" && evt.internalId == 17 && server.Cookie != null,
|
||||
"event carries authenticated ID and ready cookie");
|
||||
});
|
||||
Effects.Clear();
|
||||
try
|
||||
{
|
||||
var pending = user.Login(null);
|
||||
await getStarted.Task;
|
||||
Check(!user.IsLogin && !user.IsAuthorized && user.UserId == null && success == 0,
|
||||
"no public identity during remote load");
|
||||
Check(await user.Login(null) == ELoginStep.Api && auth == 1, "duplicate login never authenticates twice");
|
||||
if (scenario == "logout-during-load") user.Logout();
|
||||
releaseGet.SetResult(await Json(new { data = raw }));
|
||||
var result = await pending;
|
||||
if (scenario == "logout-during-load")
|
||||
{
|
||||
Check(result == ELoginStep.Api && !user.IsAuthorized && user.UserId == null && success == 0 && applied == 0,
|
||||
"logout during load discards delayed response before module apply or identity");
|
||||
}
|
||||
else if (badProfile)
|
||||
{
|
||||
Check(result == ELoginStep.Api && !user.IsAuthorized && success == 0 && chat.Waits == 0,
|
||||
"corrupt profile revokes before public event or chat subscription");
|
||||
}
|
||||
else
|
||||
{
|
||||
Check(result == ELoginStep.Done && user.UserId == "101" && user.ApiPlayerId == "101" && user.InternalId == 17,
|
||||
"real KV service publishes new authenticated identity");
|
||||
Check(user.LastLoginTime == DateTime.MinValue && user.LoginTime == new DateTime(2026, 9, 29, 0, 0, 0, DateTimeKind.Utc),
|
||||
"missing previous time and authenticated current time are distinct");
|
||||
Check(user.DisplayName == "Angler#101" && user.ContinentCode == null && user.KVTapJoyBalance == 9,
|
||||
"profile defaults, unknown region and decoded platform balance");
|
||||
Check(await user.Login(null) == ELoginStep.Api && success == 1 && auth == 1 && gets == 1,
|
||||
"completed login cannot publish a second event");
|
||||
if (scenario == "logout-during-save")
|
||||
{
|
||||
var save = user.UpdateLanguage("de");
|
||||
await setStarted.Task;
|
||||
user.Logout();
|
||||
Check(!user.IsAuthorized && !user.SaveStore.IsCurrent, "close invalidates store before save response");
|
||||
releaseSet.SetResult(await Json(new { }));
|
||||
try { await save; throw new Exception("late profile was published"); }
|
||||
catch (InvalidOperationException) { Check(user.Language == null, "late save completion cannot republish a closed profile"); }
|
||||
}
|
||||
else
|
||||
{
|
||||
await MergedSaveContract(user, remote, scenario == "save-unknown", action => beforeSet = action);
|
||||
Check(await server.FriendRequest("unauthorized", "") == null && !user.IsAuthorized && user.UserId == null,
|
||||
"current 401 synchronously revokes independent identity");
|
||||
}
|
||||
}
|
||||
Check(Effects.SDK == 0 && Effects.Helpers == 0 && Effects.Rewards == 0,
|
||||
"formal KV never invokes PF SDK or platform/reward initialization");
|
||||
await user.CloseKVForValidationAsync();
|
||||
var staleTokens = new Activity.Services.EventTokenService(user.SaveStore);
|
||||
Check(staleTokens.GetTokenCount(1) == 0, "original token service catches unavailable storage and retains its initial balance");
|
||||
Check(!user.SaveStore.IsCurrent && !user.SaveStore.Read("Language").Success &&
|
||||
!user.SaveStore.Write("Language", "stale").Accepted, "old store is revoked synchronously on close");
|
||||
}
|
||||
finally
|
||||
{
|
||||
user.Logout(); await user.CloseKVForValidationAsync();
|
||||
UnityEngine.Application.persistentDataPath = root;
|
||||
PlayerKVGameplayBindings.BindFactory = null; PlayerKVGameplayBindings.SnapshotFactory = null;
|
||||
}
|
||||
}
|
||||
Pass("merged-real-KV-login-publication-duplicate-401-and-corrupt-profile");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType><TargetFramework>net9.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings><Nullable>disable</Nullable>
|
||||
<DefineConstants>$(DefineConstants);UNITY_EDITOR;SERVICE_HOST</DefineConstants>
|
||||
<DefineConstants Condition="'$(AndroidProbe)'=='true'">$(DefineConstants);UNITY_ANDROID;AGG</DefineConstants>
|
||||
<DefineConstants Condition="'$(PlayerProbe)'=='true'">SERVICE_HOST</DefineConstants>
|
||||
<NoWarn>$(NoWarn);CS0436;CS1998</NoWarn>
|
||||
<RestoreConfigFile>$(MSBuildThisFileDirectory)../../MinimalLoginTests/NuGet.Config</RestoreConfigFile>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Remove="FactoryProbe.cs" Condition="'$(PlayerProbe)'!='true'" />
|
||||
<Compile Remove="Program.cs" Condition="'$(PlayerProbe)'=='true'" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/PlayerData/PlayerKV*.cs" Exclude="../../../../Client/Assets/Scripts/Services/PlayerData/PlayerKVEditorValidationHost.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/Account/S101AccountSession.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/UserService.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/KVUserService.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/PlayerData/IPlayerSaveStore.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/PlayerData/PlayerSaveStores.cs" />
|
||||
<Compile Include="../M2MergedContractTests.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/SurveyService.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/FootPrintService.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/InGameMail.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/InGameMailHandler.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/UI/PartnerStatue/EventPartnerStatuePlayfabData.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Activity/Data/EventDataRepository.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Activity/Services/EventTokenService.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Activity/Services/IEventTokenService.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Activity/Data/IEventDataRepository.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/TimeManager/TimeRefreshManager.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/TimeManager/ITimeTickService.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/TimeManager/Event/*.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/DataCenter/DateTimeExtensions.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/PlayerData/IKVUser*.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Core/KVMgr.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/UserService.KVLoad.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Services/AggUserService.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Core/PlayFabMgr.cs" />
|
||||
<Compile Include="../../../../Client/Assets/Scripts/Core/CustomServerMgr.cs" />
|
||||
<Reference Include="PlayFab"><HintPath>../../../../Client/Library/ScriptAssemblies/PlayFab.dll</HintPath></Reference>
|
||||
<Reference Include="Newtonsoft.Json"><HintPath>../../../../Client/Library/PackageCache/com.unity.nuget.newtonsoft-json@3.2.1/Runtime/Newtonsoft.Json.dll</HintPath></Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
232
CodexOutput/upserver/B3BatchMigration/M2/C3b修改前快照/Stubs.cs.txt
Normal file
232
CodexOutput/upserver/B3BatchMigration/M2/C3b修改前快照/Stubs.cs.txt
Normal file
@@ -0,0 +1,232 @@
|
||||
// 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<T>() where T:class =>Found as T;
|
||||
public T AddComponent<T>() where T:new(){Effects.Helpers++;return new T();}
|
||||
}
|
||||
public class MonoBehaviour:Object { public GameObject gameObject=new(); public T GetComponent<T>() where T:class=>null; }
|
||||
public static class Debug { public static void Log(object o){} public static void LogWarning(object o){} public static void LogError(object o){} 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<string,string> 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 void Save(){Effects.Prefs++;}
|
||||
}
|
||||
}
|
||||
namespace asap.core
|
||||
{
|
||||
public class InjectAttribute:Attribute{}
|
||||
public interface IConfig { T Get<T>(string key,T fallback); void Set(string key,object value); }
|
||||
public static class Awaiters { public static Task NextFrame=>Task.CompletedTask; }
|
||||
}
|
||||
sealed class Config:asap.core.IConfig
|
||||
{
|
||||
internal readonly Dictionary<string,object> Values=new();
|
||||
public T Get<T>(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<T> : IObservable<T>
|
||||
{
|
||||
internal static Action<T> Handlers;
|
||||
public IDisposable Subscribe(Action<T> action){Effects.Subscriptions++;Handlers+=action;return new Subscription(()=>Handlers-=action);}
|
||||
public IDisposable Subscribe(IObserver<T> 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<IDisposable> 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<T> : IObserver<T>
|
||||
{
|
||||
readonly Action<T> next;
|
||||
internal Observer(Action<T> 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<T>(this IObservable<T> source, Action<T> next) => source.Subscribe(new Observer<T>(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 sealed class SurveyData { public int ID, LevelCondition, Reward; public string Hash; public List<int> TailNumberList = new(); }
|
||||
public sealed class TbSurveyData { public List<SurveyData> DataList = new(); }
|
||||
public sealed class AutoDeliveryMail { public int MailID, ExpireDay, DropID; public List<int> AccountLevelRange = new(); public string AccountCreateTimestamp, Title_l10n_key, Content_l10n_key, Inscribe_l10n_key; public List<string> LoginTimestampRange = new(); }
|
||||
public sealed class TbAutoDeliveryMail { public Dictionary<int, AutoDeliveryMail> DataMap = new(); public List<AutoDeliveryMail> DataList = new(); }
|
||||
public sealed class GlobalConfig { public int GlobalTimeOffset = 9; }
|
||||
}
|
||||
public static class GContext
|
||||
{
|
||||
public static readonly Container container=new();
|
||||
public static UniRx.Stream<T> OnEvent<T>()=>new();
|
||||
public static void Publish<T>(T value){Effects.Events++;UniRx.Stream<T>.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<IKVUserLoadReceiver, PlayerKVGameLoadTransaction> BindFactory;
|
||||
internal static Func<PlayerKVSchemaSnapshot> 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<Type,object> Values=new();public T Resolve<T>()=> (T)Values[typeof(T)]; }
|
||||
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<T>(string s)=>JsonConvert.DeserializeObject<T>(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<UpdateUserDataResult> ok,Action<PlayFabError> 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<Task<LoginResult>> LoginOverride;
|
||||
public static Task<T> ExecuteWithRetryAsync<T>(Func<Task<T>> call)=>call();
|
||||
public static Task<LoginResult> LoginWithCustomIDAsync(LoginWithCustomIDRequest r){Effects.SDK++;PlayFab.PlayFabClientAPI.Logged=Result!=null;return LoginOverride?.Invoke() ?? Task.FromResult(Result);}
|
||||
public static Task<LoginResult> LoginWithAndroidDeviceIDAsync(LoginWithAndroidDeviceIDRequest r)=>LoginWithCustomIDAsync(new());
|
||||
public static Task<GetPlayerProfileResult> GetPlayerProfileAsync(GetPlayerProfileRequest r){Effects.SDK++;return Task.FromResult(new GetPlayerProfileResult{PlayerProfile=new PlayerProfileModel{Locations=new(){new LocationModel()}}});}
|
||||
public static Task<UpdateUserTitleDisplayNameResult> UpdateUserTitleDisplayNameAsync(UpdateUserTitleDisplayNameRequest r){Effects.SDK++;return Task.FromResult(new UpdateUserTitleDisplayNameResult{DisplayName=r.DisplayName});}
|
||||
public static Task<EmptyResponse> UpdateAvatarUrlAsync(UpdateAvatarUrlRequest r){Effects.SDK++;return Task.FromResult(new EmptyResponse());}
|
||||
public static Task<GetUserDataResult> GetUserDataAsync(GetUserDataRequest r){Effects.SDK++;return Task.FromResult(new GetUserDataResult{Data=new()});}
|
||||
}
|
||||
public static class PlayFabProfilesAsyncAPI
|
||||
{ public static Task<PlayFab.ProfilesModels.SetProfileLanguageResponse> 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<EAccoutType> linkedAccout=new();}
|
||||
public static AccountInfo TYAccountInfo=new(){userId=101,channel=EAccoutType.hwGuest};
|
||||
public static bool IsLoggedIn;
|
||||
public static TYSdkFacade Instance=new();
|
||||
internal static Func<Task<LoginInfo>> LoginOverride;
|
||||
public Task<LoginInfo> LoginBySns(){Effects.SDK++;return LoginOverride?.Invoke() ?? Task.FromResult(new LoginInfo{isSuccess=true,userId=101});}
|
||||
public Task<LoginInfo> LoginByToken()=>LoginBySns();public Task<LoginInfo> Login(EAccoutType type)=>LoginBySns();
|
||||
public void Logout(){Effects.SDK++;IsLoggedIn=false;}
|
||||
public Task<bool> 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){Effects.Events++;}
|
||||
public static void SetProps(Dictionary<string,object> p){Effects.Events++;}public static void SetUserProps(Dictionary<string,object> 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 Action Save; public void SavePlayerData() => Save?.Invoke(); public int lv=1;public int Loads;public void LoadPlayerData(IDictionary<string,string> 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;public ulong curCount;}
|
||||
public enum RewardType {NormalOne}
|
||||
public class ShowData {public ShowData(){}public ShowData(List<ItemData> items,RewardType t){Effects.UI++;}}
|
||||
public class PlayerItemData { public Action<int, bool> Drop;
|
||||
public void AddItemByDrop(int id, object change) => Drop?.Invoke(id, false);
|
||||
public void AddItemByDropList(List<int> ids, object change) { foreach (var id in ids) Drop?.Invoke(id, false); }
|
||||
public void AddItemByDropListLureInflation(float? inflation, List<int> 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<string,int> earn,Action<string,int> 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"; }
|
||||
public static class LocalizationMgr { public static string GetText(string key) => key; }
|
||||
public sealed class OnLvChangeEvent { public int lvl; }
|
||||
public interface IRTService { IDisposable OnEvent<T>(Func<T, Task> action); }
|
||||
namespace UniRx
|
||||
{
|
||||
public static class MailProbeRxExtensions
|
||||
{
|
||||
public static IObservable<T> Skip<T>(this IObservable<T> source, int count) => source;
|
||||
public static IObservable<T> Where<T>(this IObservable<T> source, Func<T,bool> predicate) => source;
|
||||
}
|
||||
}
|
||||
17
CodexOutput/upserver/B3BatchMigration/M2/C3b修改前快照/index.json
Normal file
17
CodexOutput/upserver/B3BatchMigration/M2/C3b修改前快照/index.json
Normal file
@@ -0,0 +1,17 @@
|
||||
[
|
||||
{
|
||||
"path": "CodexOutput/upserver/KVGameLoadTests/ServiceHost/ServiceHost.csproj",
|
||||
"backup": "CodexOutput/upserver/B3BatchMigration/M2/C3b修改前快照/ServiceHost.csproj.txt",
|
||||
"sha256": "ACF7930CA4AFAC470BA1BB3103A39F5B7ED2B4D5DB05F3C268FF651074AD0AF8"
|
||||
},
|
||||
{
|
||||
"path": "CodexOutput/upserver/KVGameLoadTests/ServiceHost/Stubs.cs",
|
||||
"backup": "CodexOutput/upserver/B3BatchMigration/M2/C3b修改前快照/Stubs.cs.txt",
|
||||
"sha256": "D6C2EAE1449440D915CD961D859383FAA4065368C1078A4F74F6565B12A8E41E"
|
||||
},
|
||||
{
|
||||
"path": "CodexOutput/upserver/KVGameLoadTests/ServiceHost/M2MergedGameplayTests.cs",
|
||||
"backup": "CodexOutput/upserver/B3BatchMigration/M2/C3b修改前快照/M2MergedGameplayTests.cs.txt",
|
||||
"sha256": "BB30FE00BF76BA63E5707AC7DE71B5AF4AACD400B1543EBB2E22778DED5E4A5C"
|
||||
}
|
||||
]
|
||||
Reference in New Issue
Block a user