Compare commits
6 Commits
main
...
6813da149a
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6813da149a | ||
|
|
1c0cdf7a99 | ||
|
|
a6f5e107f8 | ||
|
|
c4ae02def9 | ||
|
|
0eb43b2b40 | ||
|
|
f40a816cc4 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -10,3 +10,4 @@ CLAUDE.md
|
|||||||
QWEN.md
|
QWEN.md
|
||||||
Client/.claude/
|
Client/.claude/
|
||||||
dev-ab-svr/debugconfig.json
|
dev-ab-svr/debugconfig.json
|
||||||
|
/Client/.uloop/
|
||||||
|
|||||||
9
AGENTS.md
Normal file
9
AGENTS.md
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
# 项目通用开发规则
|
||||||
|
|
||||||
|
- KV模式的迁移目标是由KV管理器及其接线承接原PlayFab相关能力,不只迁个人存档;等级榜、公开资料、好友和匹配是原PlayFab调用的既有功能,不得当作新增产品需求、默认延期或直接转交服务端。先核客户端已有KV能力及等价调用映射;只有明确证实缺少必要能力时,才把具体接口证据集中写入沟通文档。不得反复要求用户确认“是否存KV”、新ID或原邮件流程。已审同合同替换连续实施,确有新合同或架构差异时一次合并评审,避免逐功能送审。
|
||||||
|
- 整个迁移流程、所有阶段与批次均只做平移,不限于 M2。全部迁移完成前,仅修改完成迁移所必需的存储、身份和接口接线,保留原业务规则、调用顺序、同步/异步方式、返回值、异常处理和界面流程。不得夹带额外业务修正、优化或代码重构;不得以“更安全”“更合理”或“顺手修复”为由改变原逻辑。
|
||||||
|
- 发现原有业务缺陷、代码结构问题或可优化点,统一记录到迁移完成后的待办,不在任何迁移阶段穿插处理。必须等整个迁移流程全部完成后,再由用户另行授权修正;单个阶段完成不构成提前修正的许可。此前方案或评审包含此类扩展时,以此规则及用户最新要求为准。
|
||||||
|
- 最终闲置实现清理仅限本次迁移造成且经核实已无消费者的实现,不得借清理重构代码或删除原有有效功能。确有无法保持原流程的迁移障碍,先说明具体差异,不自行改写业务规则或冻结功能。
|
||||||
|
- 在满足已确认的功能、正确性和必要安全边界的前提下,优先选择最简单、最直观、最容易维护的实现。抽象应服务于实际调用者;不要为假设中的扩展增加接口、适配器、管理器、状态机或重复保护层。
|
||||||
|
- 修改代码前完成相关方案的完整评审,记录裁决和开发边界。评审新增抽象时,说明它解决的具体问题、实际调用点,以及为何复用或小幅修改现有实现不足;无法说明必要性的层次不要引入。
|
||||||
|
- 同一事实保持单一来源,同一业务流程避免多重开关和重复状态。迁移中的临时路径须登记,最终通关前恢复或清理;最终代码删除闲置实现,但保留仍在使用的原有功能。
|
||||||
@@ -22,13 +22,13 @@ public class DebugConfig
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
private const string s101StaicResUrl = "http://192.168.9.101:8080/{0}";
|
private const string s101StaicResUrl = "http://s101.local:8080/{0}";
|
||||||
private const string s101AddrUrl = "http://192.168.9.101:8080/{0}/{1}";
|
private const string s101AddrUrl = "http://s101.local:8080/{0}/{1}";
|
||||||
private const string s101EventAPIUrl = "http://192.168.9.101:5292/";
|
private const string s101EventAPIUrl = "http://s101.local:18080/";
|
||||||
private const string s101RTMPid = "80000560";
|
private const string s101RTMPid = "80000560";
|
||||||
private const string s101RTMServerEndpoint = "rtm-nx-front.ilivedata.com:13321";
|
private const string s101RTMServerEndpoint = "rtm-nx-front.ilivedata.com:13321";
|
||||||
private const string s101RTMHmacSecret = "7a1ba6bb85a4473d96fa4bf45b01f1dd";
|
private const string s101RTMHmacSecret = "7a1ba6bb85a4473d96fa4bf45b01f1dd";
|
||||||
private const string s101FuncUrl= "http://192.168.9.101:7071";
|
private const string s101FuncUrl= "http://s101.local:7071";
|
||||||
private const string s101FuncKey= "testKey";
|
private const string s101FuncKey= "testKey";
|
||||||
|
|
||||||
private const string devStaicResUrl = "https://sls-cloudfunction-ap-beijing-code-1305151099.cos.ap-beijing.myqcloud.com/dev/{0}";
|
private const string devStaicResUrl = "https://sls-cloudfunction-ap-beijing-code-1305151099.cos.ap-beijing.myqcloud.com/dev/{0}";
|
||||||
|
|||||||
23
Client/Assets/Editor/KVGameLoadValidation.cs
Normal file
23
Client/Assets/Editor/KVGameLoadValidation.cs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public static class KVGameLoadValidation
|
||||||
|
{
|
||||||
|
// Fixed assembly/type/method and explicit case allow-list; no arbitrary reflection arguments.
|
||||||
|
public static async Task<string> RunAsync(string caseId)
|
||||||
|
{
|
||||||
|
if (caseId != "M08-M23" && caseId != "M21-M22-M24" && caseId != "M09-M10-M12" &&
|
||||||
|
caseId != "M14" && caseId != "M07" && caseId != "M20-M21-M22-M24-M28-M29" && caseId != "M16-M17" &&
|
||||||
|
caseId != "M06-M13" && caseId != "M15-M26-M27" && caseId != "M30" && caseId != "M19" && caseId != "M11" && caseId != "M25" &&
|
||||||
|
caseId != "M01-M02-M21-M22-M24" && caseId != "M04-M21-M22-M24" && caseId != "M05-M21-M22-M24" && caseId != "M03" && caseId != "M18" && caseId != "M31" && caseId != "B2-20") throw new ArgumentException("Unknown fixed validation case.");
|
||||||
|
var assembly = AppDomain.CurrentDomain.GetAssemblies().Single(a => a.GetName().Name == "HotUpdate");
|
||||||
|
var type = assembly.GetType("game.PlayerDataStorage.PlayerKVEditorValidationHost", true);
|
||||||
|
var method = type.GetMethod("RunAsync", BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(string) }, null);
|
||||||
|
if (method == null) throw new InvalidOperationException("Validation entry unavailable.");
|
||||||
|
return await (Task<string>)method.Invoke(null, new object[] { caseId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
2
Client/Assets/Editor/KVGameLoadValidation.cs.meta
Normal file
2
Client/Assets/Editor/KVGameLoadValidation.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4ce05f2f22c2492f8a3c51a82a208647
|
||||||
85
Client/Assets/Editor/KVGameplayLoopSetup.cs
Normal file
85
Client/Assets/Editor/KVGameplayLoopSetup.cs
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Security.Cryptography;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
// Fixed CLI helpers; no arbitrary method names or process-marker deletion.
|
||||||
|
public static class KVGameplayLoopSetup
|
||||||
|
{
|
||||||
|
static string Root => Path.GetFullPath(Path.Combine(Application.dataPath,"../../CodexOutput/upserver/KVGameplayLoopTests"));
|
||||||
|
static Type Find(string name) => AppDomain.CurrentDomain.GetAssemblies().Select(a=>a.GetType("game.PlayerDataStorage."+name)).FirstOrDefault(t=>t!=null)
|
||||||
|
?? throw new InvalidOperationException("Gameplay assembly not loaded.");
|
||||||
|
static object ReadProperty(Type type,string name) => type.GetProperty(name,BindingFlags.Static|BindingFlags.NonPublic)?.GetValue(null);
|
||||||
|
|
||||||
|
public static async System.Threading.Tasks.Task<string> RunValidationAsync(string caseId)
|
||||||
|
{
|
||||||
|
if(caseId!="equipment-chain" && caseId!="fishing-consume" && caseId!="fishing-reward") throw new ArgumentException("Unknown fixed validation case.");
|
||||||
|
if(EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling || EditorApplication.isUpdating)
|
||||||
|
throw new InvalidOperationException("Idle editor required.");
|
||||||
|
var method=Find("PlayerKVGameplayLoop").GetMethod(caseId=="equipment-chain"?"VerifyEquipmentForEditorAsync":caseId=="fishing-consume"?"VerifyFishingForEditorAsync":"VerifyFishingRewardForEditorAsync",BindingFlags.Static|BindingFlags.NonPublic);
|
||||||
|
if(method==null) throw new InvalidOperationException("Fixed equipment validation entry unavailable.");
|
||||||
|
return await (System.Threading.Tasks.Task<string>)method.Invoke(null,null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string State()
|
||||||
|
{
|
||||||
|
var type=Find("PlayerKVGameplayLoop");
|
||||||
|
var history=Path.Combine(Root,"run-control");
|
||||||
|
return JsonConvert.SerializeObject(new{project=Application.dataPath,playing=EditorApplication.isPlaying,
|
||||||
|
enabled=ReadProperty(type,"Enabled"),ready=ReadProperty(type,"Ready"),error=ReadProperty(type,"Error"),run=ReadProperty(type,"RunPath"),
|
||||||
|
permitExists=File.Exists(Path.Combine(Root,"permit.json")),
|
||||||
|
processMarkers=Directory.Exists(history)?Directory.GetFiles(history,"*.claimed").Select(Path.GetFileName).OrderBy(x=>x).ToArray():Array.Empty<string>()});
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string ValidatePermit(string path)
|
||||||
|
{
|
||||||
|
var type=Find("PlayerKVLoopPermit");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var permit=type.GetMethod("Read",BindingFlags.Static|BindingFlags.NonPublic).Invoke(null,new object[]{Path.GetFullPath(path)});
|
||||||
|
return JsonConvert.SerializeObject(permit);
|
||||||
|
}
|
||||||
|
catch(TargetInvocationException e) { throw e.InnerException ?? e; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string InspectPFBackup(string path)
|
||||||
|
{
|
||||||
|
if(EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling || EditorApplication.isUpdating)
|
||||||
|
throw new InvalidOperationException("Idle editor required.");
|
||||||
|
var method=Find("PlayerKVGameplayLoop").GetMethod("InspectPFBackupForEditor",BindingFlags.Static|BindingFlags.NonPublic);
|
||||||
|
try { return (string)method.Invoke(null,new object[]{path}); }
|
||||||
|
catch(TargetInvocationException e) { throw e.InnerException ?? e; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string PreparePermit(string account,string backupPath,string[] allowedKeys)
|
||||||
|
=> PreparePermitCore(account,backupPath,allowedKeys,false);
|
||||||
|
public static string PrepareFishingPermit(string account,string backupPath,string[] allowedKeys)
|
||||||
|
=> PreparePermitCore(account,backupPath,allowedKeys,true);
|
||||||
|
public static string PrepareFishingRewardPermit(string account,string backupPath,string[] allowedKeys)
|
||||||
|
=> PreparePermitCore(account,backupPath,allowedKeys,true,true);
|
||||||
|
static string PreparePermitCore(string account,string backupPath,string[] allowedKeys,bool fishing,bool reward=false)
|
||||||
|
{
|
||||||
|
if(EditorApplication.isPlayingOrWillChangePlaymode || EditorApplication.isCompiling)
|
||||||
|
throw new InvalidOperationException("Stop play before preparing a new process run.");
|
||||||
|
backupPath=Path.GetFullPath(backupPath);
|
||||||
|
var bytes=File.ReadAllBytes(backupPath);
|
||||||
|
string hash;
|
||||||
|
using(var sha=SHA256.Create()) hash=BitConverter.ToString(sha.ComputeHash(bytes)).Replace("-","");
|
||||||
|
var candidate=Path.Combine(Root,"permit.candidate.json");
|
||||||
|
Directory.CreateDirectory(Root);
|
||||||
|
var json=JObject.FromObject(new{Version=reward?3:fishing?2:1,Enabled=true,PlayerId=account,
|
||||||
|
Api="http://s101.local:18080/",BackupPath=backupPath,BackupSha256=hash,AllowedKeys=allowedKeys});
|
||||||
|
if(fishing) json["Operation"]=reward?"fishing-reward-once":"fishing-consume-once";
|
||||||
|
File.WriteAllText(candidate,json.ToString(Formatting.Indented));
|
||||||
|
var validated=ValidatePermit(candidate); // Empty/mismatched backups cannot enable a run.
|
||||||
|
File.WriteAllText(Path.Combine(Root,"permit.json"),validated);
|
||||||
|
return State();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
2
Client/Assets/Editor/KVGameplayLoopSetup.cs.meta
Normal file
2
Client/Assets/Editor/KVGameplayLoopSetup.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: ff2728a480374b609aaed9ea0742215e
|
||||||
19
Client/Assets/Editor/KVSaveRouteValidation.cs
Normal file
19
Client/Assets/Editor/KVSaveRouteValidation.cs
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
#if UNITY_EDITOR
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
public static class KVSaveRouteValidation
|
||||||
|
{
|
||||||
|
public static async Task<string> RunAsync(string caseId)
|
||||||
|
{
|
||||||
|
if (caseId != "fixed-route") throw new ArgumentException("Unknown fixed validation case.");
|
||||||
|
var assembly = AppDomain.CurrentDomain.GetAssemblies().Single(a => a.GetName().Name == "HotUpdate");
|
||||||
|
var type = assembly.GetType("game.PlayerDataStorage.PlayerKVSaveRouteEditorValidationHost", true);
|
||||||
|
var method = type.GetMethod("RunAsync", BindingFlags.Static | BindingFlags.NonPublic, null, new[] { typeof(string) }, null);
|
||||||
|
if (method == null) throw new InvalidOperationException("Validation entry unavailable.");
|
||||||
|
return await (Task<string>)method.Invoke(null, new object[] { caseId });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
2
Client/Assets/Editor/KVSaveRouteValidation.cs.meta
Normal file
2
Client/Assets/Editor/KVSaveRouteValidation.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: dc9b5dbb615a4746a95df66b46987589
|
||||||
74
Client/Assets/Editor/S101LoginWindow.cs
Normal file
74
Client/Assets/Editor/S101LoginWindow.cs
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using game.Account;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
public sealed class S101LoginWindow : EditorWindow
|
||||||
|
{
|
||||||
|
string playerId = "101";
|
||||||
|
string status = "输入涂游测试 ID,验证 s101 认证及 Cookie。";
|
||||||
|
bool busy;
|
||||||
|
S101AccountSession session;
|
||||||
|
CancellationTokenSource cancellation;
|
||||||
|
|
||||||
|
[MenuItem("Tools/Debug/S101 Minimal Login")]
|
||||||
|
static void Open() => GetWindow<S101LoginWindow>("S101 最小登录");
|
||||||
|
|
||||||
|
void OnGUI()
|
||||||
|
{
|
||||||
|
EditorGUILayout.LabelField("API", S101AccountSession.DefaultApiUrl);
|
||||||
|
using (new EditorGUI.DisabledScope(busy))
|
||||||
|
{
|
||||||
|
playerId = EditorGUILayout.TextField("涂游测试 ID", playerId);
|
||||||
|
if (GUILayout.Button("登录并验证 Cookie")) Login();
|
||||||
|
}
|
||||||
|
EditorGUILayout.HelpBox(status, MessageType.Info);
|
||||||
|
EditorGUILayout.LabelField("此入口只验证认证,不初始化玩法或写入存档。");
|
||||||
|
}
|
||||||
|
|
||||||
|
async void Login()
|
||||||
|
{
|
||||||
|
busy = true;
|
||||||
|
session?.Dispose();
|
||||||
|
cancellation?.Dispose();
|
||||||
|
cancellation = new CancellationTokenSource();
|
||||||
|
var attempt = new S101AccountSession();
|
||||||
|
session = attempt;
|
||||||
|
var token = cancellation.Token;
|
||||||
|
status = "正在登录…";
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var login = await attempt.LoginAsync(playerId, token);
|
||||||
|
if (token.IsCancellationRequested) return;
|
||||||
|
if (!login.Success)
|
||||||
|
{
|
||||||
|
status = $"登录失败:{login.Error},HTTP {login.StatusCode}";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var probe = await attempt.CheckAuthorizationAsync(token);
|
||||||
|
if (token.IsCancellationRequested) return;
|
||||||
|
status = probe.Success
|
||||||
|
? $"认证通过:涂游 ID {attempt.PlayerId},内部 ID {attempt.InternalId};Cookie 授权读取通过。"
|
||||||
|
: $"登录成功,但授权读取未通过:{probe.Error},HTTP {probe.StatusCode}";
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
status = "验证异常:" + ex.GetType().Name;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
busy = false;
|
||||||
|
if (this != null) Repaint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnDisable()
|
||||||
|
{
|
||||||
|
cancellation?.Cancel();
|
||||||
|
session?.Dispose();
|
||||||
|
cancellation?.Dispose();
|
||||||
|
cancellation = null;
|
||||||
|
session = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Client/Assets/Editor/S101LoginWindow.cs.meta
Normal file
11
Client/Assets/Editor/S101LoginWindow.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: a8f49f7440c141e89d8519ff3aa1c034
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -503,7 +503,7 @@ public class Boostrap : MonoBehaviour
|
|||||||
private async Task AfterAssetUpdateV2()
|
private async Task AfterAssetUpdateV2()
|
||||||
{
|
{
|
||||||
bsLoading.SetProgress(0.15f);
|
bsLoading.SetProgress(0.15f);
|
||||||
await SubBoostrap.RegisterServices(ctx.gameObject);
|
await SubBoostrap.RegisterServices(ctx.gameObject, config);
|
||||||
bsLoading.SetProgress(0.16f);
|
bsLoading.SetProgress(0.16f);
|
||||||
await SubBoostrap.AfterAssetUpdate(config, bsLoading.SetProgress);
|
await SubBoostrap.AfterAssetUpdate(config, bsLoading.SetProgress);
|
||||||
bsLoading.SetProgress(0.18f);
|
bsLoading.SetProgress(0.18f);
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ public class GConstant
|
|||||||
|
|
||||||
|
|
||||||
public const string K_FuncUrl = "FuncUrl";
|
public const string K_FuncUrl = "FuncUrl";
|
||||||
public const string V_FuncUrl = "http://192.168.9.101:7071";
|
public const string V_FuncUrl = "http://s101.local:7071";
|
||||||
|
|
||||||
public const string K_FuncKey = "FuncKey";
|
public const string K_FuncKey = "FuncKey";
|
||||||
public const string V_FuncKey = "testKey";
|
public const string V_FuncKey = "testKey";
|
||||||
|
|||||||
@@ -9,6 +9,10 @@ namespace Activity.Data
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class EventDataRepository : IEventDataRepository
|
public class EventDataRepository : IEventDataRepository
|
||||||
{
|
{
|
||||||
|
private readonly game.PlayerDataStorage.IPlayerSaveStore store;
|
||||||
|
public EventDataRepository(game.PlayerDataStorage.IPlayerSaveStore store)
|
||||||
|
{ this.store = store ?? throw new ArgumentNullException(nameof(store)); }
|
||||||
|
|
||||||
public void Save<T>(T data) where T : IEventData
|
public void Save<T>(T data) where T : IEventData
|
||||||
{
|
{
|
||||||
if (data == null)
|
if (data == null)
|
||||||
@@ -23,7 +27,7 @@ namespace Activity.Data
|
|||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
Debug.Log($"[EventDataRepository] Saving {typeof(T).Name}: {json}");
|
Debug.Log($"[EventDataRepository] Saving {typeof(T).Name}: {json}");
|
||||||
#endif
|
#endif
|
||||||
PlayFabMgr.Instance?.UpdateUserDataValue(typeof(T).Name, json);
|
store.Write(typeof(T).Name, json).RequireAccepted();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -35,7 +39,7 @@ namespace Activity.Data
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dataStr = PlayFabMgr.Instance?.GetLocalData(typeof(T).Name);
|
var dataStr = store.Read(typeof(T).Name).ValueOrThrow();
|
||||||
if (string.IsNullOrEmpty(dataStr)) return new T();
|
if (string.IsNullOrEmpty(dataStr)) return new T();
|
||||||
// #if UNITY_EDITOR
|
// #if UNITY_EDITOR
|
||||||
// Debug.Log($"[EventDataRepository] Load {typeof(T).Name}: {dataStr}");
|
// Debug.Log($"[EventDataRepository] Load {typeof(T).Name}: {dataStr}");
|
||||||
@@ -52,7 +56,7 @@ namespace Activity.Data
|
|||||||
|
|
||||||
public bool Exists<T>() where T : IEventData
|
public bool Exists<T>() where T : IEventData
|
||||||
{
|
{
|
||||||
var dataStr = PlayFabMgr.Instance?.GetLocalData(typeof(T).Name);
|
var dataStr = store.Read(typeof(T).Name).ValueOrThrow();
|
||||||
return !string.IsNullOrEmpty(dataStr);
|
return !string.IsNullOrEmpty(dataStr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,15 @@ namespace Activity
|
|||||||
public class ActivitySentryManager
|
public class ActivitySentryManager
|
||||||
{
|
{
|
||||||
private static Dictionary<(int, int), Type> _activitySentryTypes;
|
private static Dictionary<(int, int), Type> _activitySentryTypes;
|
||||||
|
private static object _registrationContainer;
|
||||||
|
|
||||||
|
private static void EnsureCurrentContainer()
|
||||||
|
{
|
||||||
|
if (ReferenceEquals(_registrationContainer, GContext.container)) return;
|
||||||
|
_registrationContainer = GContext.container;
|
||||||
|
_activitySentryTypes = null;
|
||||||
|
TypeKeyCache.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 类型键缓存:Sentry 类型 → (EventType, EventSubType)
|
/// 类型键缓存:Sentry 类型 → (EventType, EventSubType)
|
||||||
@@ -21,6 +30,7 @@ namespace Activity
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
EnsureCurrentContainer();
|
||||||
if (_activitySentryTypes != null) return _activitySentryTypes;
|
if (_activitySentryTypes != null) return _activitySentryTypes;
|
||||||
InitActivitySentryTypes();
|
InitActivitySentryTypes();
|
||||||
|
|
||||||
@@ -42,6 +52,7 @@ namespace Activity
|
|||||||
}
|
}
|
||||||
public static void InitActivitySentryType(Type type)
|
public static void InitActivitySentryType(Type type)
|
||||||
{
|
{
|
||||||
|
EnsureCurrentContainer();
|
||||||
_activitySentryTypes ??= new Dictionary<(int, int), Type>();
|
_activitySentryTypes ??= new Dictionary<(int, int), Type>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@@ -82,4 +93,4 @@ namespace Activity
|
|||||||
return TypeKeyCache.GetValueOrDefault(sentryType);
|
return TypeKeyCache.GetValueOrDefault(sentryType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,10 @@ namespace Activity.Services
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class EventTokenService : IEventTokenService
|
public class EventTokenService : IEventTokenService
|
||||||
{
|
{
|
||||||
|
private readonly game.PlayerDataStorage.IPlayerSaveStore store;
|
||||||
|
public EventTokenService(game.PlayerDataStorage.IPlayerSaveStore store)
|
||||||
|
{ this.store = store ?? throw new ArgumentNullException(nameof(store)); }
|
||||||
|
|
||||||
#region 常量与字段
|
#region 常量与字段
|
||||||
|
|
||||||
private const string TransitionDataKey = "TransitionData";
|
private const string TransitionDataKey = "TransitionData";
|
||||||
@@ -75,7 +79,7 @@ namespace Activity.Services
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var dataStr = PlayFabMgr.Instance?.GetLocalData(TransitionDataKey);
|
var dataStr = store.Read(TransitionDataKey).ValueOrThrow();
|
||||||
if (!string.IsNullOrEmpty(dataStr))
|
if (!string.IsNullOrEmpty(dataStr))
|
||||||
{
|
{
|
||||||
_tokenData.Clear();
|
_tokenData.Clear();
|
||||||
@@ -106,7 +110,7 @@ namespace Activity.Services
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
var json = Newtonsoft.Json.JsonConvert.SerializeObject(_tokenData);
|
var json = Newtonsoft.Json.JsonConvert.SerializeObject(_tokenData);
|
||||||
PlayFabMgr.Instance?.UpdateUserDataValue(TransitionDataKey, json);
|
store.Write(TransitionDataKey, json).RequireAccepted();
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
Debug.Log($"[EventTokenService] Saved {_tokenData.Count} token entries to PlayFab");
|
Debug.Log($"[EventTokenService] Saved {_tokenData.Count} token entries to PlayFab");
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
@@ -12,6 +12,8 @@ using UnityEngine;
|
|||||||
public class AquariumManager
|
public class AquariumManager
|
||||||
{
|
{
|
||||||
public const string AquariumEventDataNewKey = "AquariumEventDataNewKey";
|
public const string AquariumEventDataNewKey = "AquariumEventDataNewKey";
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore;
|
||||||
|
readonly IUserService loginUser;
|
||||||
private cfg.Tables _tables;
|
private cfg.Tables _tables;
|
||||||
private ICustomServerMgr customServerMgr;
|
private ICustomServerMgr customServerMgr;
|
||||||
public AquariumManagerData data { get; private set; }
|
public AquariumManagerData data { get; private set; }
|
||||||
@@ -21,12 +23,15 @@ public class AquariumManager
|
|||||||
public List<AquariumSlotData> sellList;
|
public List<AquariumSlotData> sellList;
|
||||||
public AquariumManager()
|
public AquariumManager()
|
||||||
{
|
{
|
||||||
|
saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
loginUser = GContext.container.Resolve<IUserService>();
|
||||||
_tables = GContext.container.Resolve<Tables>();
|
_tables = GContext.container.Resolve<Tables>();
|
||||||
customServerMgr = GContext.container.Resolve<ICustomServerMgr>();
|
customServerMgr = GContext.container.Resolve<ICustomServerMgr>();
|
||||||
}
|
}
|
||||||
public static AquariumManagerData GetAquariumManagerData()
|
public static AquariumManagerData GetAquariumManagerData(game.PlayerDataStorage.IPlayerSaveStore store = null)
|
||||||
{
|
{
|
||||||
string dataStr = PlayFabMgr.Instance.GetLocalData(AquariumEventDataNewKey);
|
var source = store ?? GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
string dataStr = source.Read(AquariumEventDataNewKey).ValueOrThrow();
|
||||||
if (!string.IsNullOrEmpty(dataStr))
|
if (!string.IsNullOrEmpty(dataStr))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -43,7 +48,8 @@ public class AquariumManager
|
|||||||
public async Task Synchrodata()
|
public async Task Synchrodata()
|
||||||
{
|
{
|
||||||
//从服务器拿数据
|
//从服务器拿数据
|
||||||
var dataSever = GetAquariumManagerData();
|
if (!saveStore.IsCurrent) throw new OperationCanceledException();
|
||||||
|
var dataSever = GetAquariumManagerData(saveStore);
|
||||||
if (dataSever == null)
|
if (dataSever == null)
|
||||||
{
|
{
|
||||||
//新数据
|
//新数据
|
||||||
@@ -63,8 +69,9 @@ public class AquariumManager
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
GetAquariumDataRequest request = new GetAquariumDataRequest();
|
GetAquariumDataRequest request = new GetAquariumDataRequest();
|
||||||
request.playFabId = GContext.container.Resolve<IUserService>().UserId;
|
request.playFabId = loginUser.UserId;
|
||||||
string result = await customServerMgr.CustomServerPost("aquarium/GetAquariumData", Newtonsoft.Json.JsonConvert.SerializeObject(request));
|
string result = await customServerMgr.CustomServerPost("aquarium/GetAquariumData", Newtonsoft.Json.JsonConvert.SerializeObject(request));
|
||||||
|
if (!saveStore.IsCurrent) throw new OperationCanceledException();
|
||||||
AquariumServerData serverData = null;
|
AquariumServerData serverData = null;
|
||||||
if (result != null)
|
if (result != null)
|
||||||
{
|
{
|
||||||
@@ -611,7 +618,7 @@ public class AquariumManager
|
|||||||
}
|
}
|
||||||
void UpdateUserData()
|
void UpdateUserData()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(AquariumEventDataNewKey, data.Serialize());
|
saveStore.Write(AquariumEventDataNewKey, data.Serialize()).RequireAccepted();
|
||||||
}
|
}
|
||||||
void SaveData(bool all = false)
|
void SaveData(bool all = false)
|
||||||
{
|
{
|
||||||
@@ -637,7 +644,7 @@ public class AquariumManager
|
|||||||
if (all)
|
if (all)
|
||||||
{
|
{
|
||||||
UpdateAquariumAllDataRequest request = new UpdateAquariumAllDataRequest();
|
UpdateAquariumAllDataRequest request = new UpdateAquariumAllDataRequest();
|
||||||
request.playFabId = GContext.container.Resolve<IUserService>().UserId;
|
request.playFabId = loginUser.UserId;
|
||||||
request.data = new AquariumServerData()
|
request.data = new AquariumServerData()
|
||||||
{
|
{
|
||||||
startTime = data.startTime,
|
startTime = data.startTime,
|
||||||
@@ -653,7 +660,7 @@ public class AquariumManager
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
UpdateSlotDatasRequest request = new UpdateSlotDatasRequest();
|
UpdateSlotDatasRequest request = new UpdateSlotDatasRequest();
|
||||||
request.playFabId = GContext.container.Resolve<IUserService>().UserId;
|
request.playFabId = loginUser.UserId;
|
||||||
request.slotDatas = data.slotDatas;
|
request.slotDatas = data.slotDatas;
|
||||||
request.cardLv = string.Join(',', cardLv);
|
request.cardLv = string.Join(',', cardLv);
|
||||||
customServerMgr.CustomServerPost("aquarium/UpdateSlotData", Newtonsoft.Json.JsonConvert.SerializeObject(request));
|
customServerMgr.CustomServerPost("aquarium/UpdateSlotData", Newtonsoft.Json.JsonConvert.SerializeObject(request));
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
@@ -10,6 +10,8 @@ using UnityEngine;
|
|||||||
|
|
||||||
public class CampDataMM
|
public class CampDataMM
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
|
||||||
private cfg.Tables _tables;
|
private cfg.Tables _tables;
|
||||||
MMTService _MMService;
|
MMTService _MMService;
|
||||||
public CampDataMM(cfg.Tables tables, MMTService mmService)
|
public CampDataMM(cfg.Tables tables, MMTService mmService)
|
||||||
@@ -101,6 +103,24 @@ public class CampDataMM
|
|||||||
//是否需要修复
|
//是否需要修复
|
||||||
public bool IsFix => _isFix && AreaIndex < AreaList.Count;
|
public bool IsFix => _isFix && AreaIndex < AreaList.Count;
|
||||||
bool _isFix;
|
bool _isFix;
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVCampState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) => game.PlayerDataStorage.PlayerKVSaveSchema.DecodeCamp(raw,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
CampDataDic=new Dictionary<string,int>(StringComparer.Ordinal);
|
||||||
|
_isFix=false; _isOpenSkyscraper="0"; _id=101;
|
||||||
|
PreID=AreaIndex=AreaStep=AreaId=AreaStepCount=TimelineId=0;
|
||||||
|
AreaIcon=null; constructionArea=null; StepInfo=null; AreaStepList=null; IsUpdataArea=false;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVCampState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new ArgumentNullException(nameof(state));
|
||||||
|
CampDataDic=state.Values.ToDictionary(p=>p.Key,p=>p.Value,StringComparer.Ordinal);
|
||||||
|
_isFix=state.IsFix; _isOpenSkyscraper=state.Skyscraper;
|
||||||
|
}
|
||||||
|
internal game.PlayerDataStorage.PlayerKVCampState SnapshotForKVValidation() =>
|
||||||
|
new game.PlayerDataStorage.PlayerKVCampState(_isFix,_isOpenSkyscraper,CampDataDic);
|
||||||
public void InitData(Dictionary<string, string> userData)
|
public void InitData(Dictionary<string, string> userData)
|
||||||
{
|
{
|
||||||
string value;
|
string value;
|
||||||
@@ -124,7 +144,7 @@ public class CampDataMM
|
|||||||
_isFix = isFix;
|
_isFix = isFix;
|
||||||
if (isSave)
|
if (isSave)
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("IsFix", _isFix.ToString());
|
SaveStore.Write("IsFix", _isFix.ToString()).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +250,7 @@ public class CampDataMM
|
|||||||
UpdateCurrentData();
|
UpdateCurrentData();
|
||||||
}
|
}
|
||||||
CampDataDic["CampId"] = Id;
|
CampDataDic["CampId"] = Id;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("CampDataDic", JsonMapper.ToJson(CampDataDic)); ;
|
SaveStore.Write("CampDataDic", JsonMapper.ToJson(CampDataDic)).RequireAccepted(); ;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -258,7 +278,7 @@ public class CampDataMM
|
|||||||
if (NextMapID == -1 || !_tables.TbConstruction.DataMap.ContainsKey(NextMapID))
|
if (NextMapID == -1 || !_tables.TbConstruction.DataMap.ContainsKey(NextMapID))
|
||||||
{
|
{
|
||||||
_isOpenSkyscraper = "1";
|
_isOpenSkyscraper = "1";
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("IsOpenSkyscraper", _isOpenSkyscraper);
|
SaveStore.Write("IsOpenSkyscraper", _isOpenSkyscraper).RequireAccepted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Debug.LogError(
|
Debug.LogError(
|
||||||
@@ -335,7 +355,7 @@ public class CampDataMM
|
|||||||
if (NextMapID == -1 || !_tables.TbConstruction.DataMap.ContainsKey(NextMapID))
|
if (NextMapID == -1 || !_tables.TbConstruction.DataMap.ContainsKey(NextMapID))
|
||||||
{
|
{
|
||||||
_isOpenSkyscraper = "1";
|
_isOpenSkyscraper = "1";
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("IsOpenSkyscraper", _isOpenSkyscraper);
|
SaveStore.Write("IsOpenSkyscraper", _isOpenSkyscraper).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,8 +4,11 @@ using System;
|
|||||||
using System.Net;
|
using System.Net;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using game.Account;
|
||||||
|
using game.PlayerDataStorage;
|
||||||
|
|
||||||
public interface ICustomServerMgr
|
public interface ICustomServerMgr
|
||||||
{
|
{
|
||||||
@@ -21,6 +24,11 @@ public interface ICustomServerMgr
|
|||||||
Task<T> EventPartnerRequest<T>(string url, object data = null);
|
Task<T> EventPartnerRequest<T>(string url, object data = null);
|
||||||
Task<string> EventPartnerRequest(string url, object data);
|
Task<string> EventPartnerRequest(string url, object data);
|
||||||
CookieContainer Cookie { get; }
|
CookieContainer Cookie { get; }
|
||||||
|
Uri ApiBaseUri { get; }
|
||||||
|
int SessionVersion { get; }
|
||||||
|
event Action SessionChanged;
|
||||||
|
void UseAccountSession(S101AccountSession session);
|
||||||
|
void ClearAccountSession();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CustomServerMgr : ICustomServerMgr
|
public class CustomServerMgr : ICustomServerMgr
|
||||||
@@ -31,86 +39,187 @@ public class CustomServerMgr : ICustomServerMgr
|
|||||||
HttpClient client;
|
HttpClient client;
|
||||||
|
|
||||||
private CookieContainer _cookie;
|
private CookieContainer _cookie;
|
||||||
|
private readonly Func<CookieContainer, HttpMessageHandler> handlerFactory;
|
||||||
|
private readonly SynchronizationContext ownerContext;
|
||||||
public CookieContainer Cookie => _cookie ?? throw new System.NullReferenceException();
|
public int SessionVersion { get; private set; }
|
||||||
|
public event Action SessionChanged;
|
||||||
public CustomServerMgr(IConfig config)
|
PlayerKVAccountLease kvLease;
|
||||||
|
bool kvOnly;
|
||||||
|
bool kvBusinessReady;
|
||||||
|
bool kvBusinessPublished;
|
||||||
|
int pfRequests;
|
||||||
|
internal event Action<int> KVUnauthorized;
|
||||||
|
internal bool IsFreshForKVLoad => pfRequests==0 && kvLease==null;
|
||||||
|
internal void BindKVForValidation(PlayerKVAccountLease lease)
|
||||||
{
|
{
|
||||||
this.config = config;
|
if(lease==null || lease.IsFormal || !lease.IsCurrent || lease.ApiBaseUri!=ApiBaseUri || !IsFreshForKVLoad)
|
||||||
|
throw new InvalidOperationException("Fresh matching KV lease required.");
|
||||||
var httpClientHandler = new HttpClientHandler();
|
kvOnly=true; kvBusinessReady=false; kvBusinessPublished=false; SessionVersion++; kvLease=lease; _cookie=null;
|
||||||
_cookie = new CookieContainer();
|
var previous=client; client=null; previous?.Dispose(); SessionChanged?.Invoke();
|
||||||
httpClientHandler.CookieContainer = _cookie;
|
}
|
||||||
client = new HttpClient(httpClientHandler);
|
internal void BindKVForGame(PlayerKVAccountLease lease)
|
||||||
|
{
|
||||||
client.BaseAddress =
|
if(lease==null || !lease.IsFormal || !lease.IsCurrent || lease.ApiBaseUri.AbsoluteUri!=PlayerKVRuntimeSelection.FormalApiUrl ||
|
||||||
new System.Uri(config.Get<string>(GConstant.K_Event_API_URL,
|
ApiBaseUri.AbsoluteUri!=PlayerKVRuntimeSelection.FormalApiUrl || !IsFreshForKVLoad)
|
||||||
"http://192.168.9.101:5292/"));
|
throw new InvalidOperationException("Fresh formal KV lease required.");
|
||||||
client.Timeout = TimeSpan.FromSeconds(15);
|
kvOnly=true; kvBusinessReady=false; kvBusinessPublished=false; SessionVersion++; kvLease=lease; _cookie=null;
|
||||||
|
var previous=client; client=null; previous?.Dispose(); SessionChanged?.Invoke();
|
||||||
|
}
|
||||||
|
internal void EnableKVBusiness(long epoch)
|
||||||
|
{
|
||||||
|
if(!kvOnly || kvBusinessReady || kvBusinessPublished || kvLease==null || !kvLease.IsFormal || !kvLease.IsCurrent ||
|
||||||
|
kvLease.Epoch!=epoch || kvLease.ApiBaseUri.AbsoluteUri!=PlayerKVRuntimeSelection.FormalApiUrl ||
|
||||||
|
ApiBaseUri.AbsoluteUri!=PlayerKVRuntimeSelection.FormalApiUrl)
|
||||||
|
throw new InvalidOperationException("Current formal KV lease required for business transport.");
|
||||||
|
kvBusinessPublished=true; kvBusinessReady=true;
|
||||||
|
}
|
||||||
|
internal void DisableKVBusiness()
|
||||||
|
{
|
||||||
|
if(!kvOnly || !kvBusinessReady) return;
|
||||||
|
kvBusinessReady=false; SessionVersion++;
|
||||||
|
try { SessionChanged?.Invoke(); }
|
||||||
|
catch(Exception ex) { Debug.LogError($"KV session change failed: {ex.GetType().Name}"); }
|
||||||
|
}
|
||||||
|
internal Task ClearKVForGame() => ClearKVForValidation();
|
||||||
|
internal Task ClearKVForValidation()
|
||||||
|
{
|
||||||
|
kvBusinessReady=false; SessionVersion++; var previous=kvLease; kvLease=null; _cookie=null;
|
||||||
|
var closing=previous?.CloseAsync() ?? Task.CompletedTask;
|
||||||
|
SessionChanged?.Invoke(); return closing;
|
||||||
|
}
|
||||||
|
internal async Task<PlayerKVAccountResponse> SendKVForValidationAsync(string route)
|
||||||
|
{
|
||||||
|
var lease=kvLease; int version=SessionVersion;
|
||||||
|
if(!kvOnly || lease==null) return new PlayerKVAccountResponse(false);
|
||||||
|
var response=await lease.SendAsync(HttpMethod.Get,route);
|
||||||
|
if(version!=SessionVersion || !ReferenceEquals(lease,kvLease) || !response.IsCurrent) return new PlayerKVAccountResponse(false);
|
||||||
|
if(response.StatusCode==401 || response.StatusCode==403)
|
||||||
|
{
|
||||||
|
KVUnauthorized?.Invoke(version);
|
||||||
|
return new PlayerKVAccountResponse(false,response.StatusCode);
|
||||||
|
}
|
||||||
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> CustomServerPost(string url, string bodyString,
|
|
||||||
string contentType = "application/json")
|
public CookieContainer Cookie => kvOnly
|
||||||
|
? (kvBusinessReady && kvLease?.IsFormal==true ? kvLease.FormalCookies : null) ?? throw new NullReferenceException()
|
||||||
|
: _cookie ?? throw new NullReferenceException();
|
||||||
|
public Uri ApiBaseUri { get; }
|
||||||
|
|
||||||
|
public CustomServerMgr(IConfig config) : this(config, null) { }
|
||||||
|
|
||||||
|
public CustomServerMgr(IConfig config, Func<CookieContainer, HttpMessageHandler> handlerFactory)
|
||||||
{
|
{
|
||||||
|
ownerContext=SynchronizationContext.Current;
|
||||||
|
this.handlerFactory = handlerFactory ?? (cookies => new HttpClientHandler
|
||||||
|
{
|
||||||
|
CookieContainer = cookies, UseCookies = true, AllowAutoRedirect = false
|
||||||
|
});
|
||||||
|
this.config = config;
|
||||||
|
|
||||||
|
var url = config.Get<string>(GConstant.K_Event_API_URL, S101AccountSession.DefaultApiUrl);
|
||||||
|
if (string.IsNullOrWhiteSpace(url)) url = S101AccountSession.DefaultApiUrl;
|
||||||
|
ApiBaseUri = new Uri(url.TrimEnd('/') + "/");
|
||||||
|
ClearAccountSession();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UseAccountSession(S101AccountSession session)
|
||||||
|
{
|
||||||
|
if(kvOnly) throw new InvalidOperationException("Controlled container cannot switch to PlayFab.");
|
||||||
|
if (session == null || !session.IsAuthenticated || session.ApiBaseUri != ApiBaseUri)
|
||||||
|
throw new ArgumentException("An authenticated session for this API is required.", nameof(session));
|
||||||
|
ReplaceTransport(session.Cookies);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearAccountSession()
|
||||||
|
{
|
||||||
|
if(kvOnly) { PlayerKVShutdownRegistry.Process.Register(ClearKVForValidation()); return; }
|
||||||
|
ReplaceTransport(new CookieContainer());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ReplaceTransport(CookieContainer cookies)
|
||||||
|
{
|
||||||
|
SessionVersion++;
|
||||||
|
var previous = client;
|
||||||
|
_cookie = cookies;
|
||||||
|
client = new HttpClient(handlerFactory(cookies)) { BaseAddress = ApiBaseUri, Timeout = TimeSpan.FromSeconds(15) };
|
||||||
|
previous?.Dispose();
|
||||||
|
SessionChanged?.Invoke();
|
||||||
|
}
|
||||||
|
|
||||||
|
public Task<string> CustomServerPost(string url, string bodyString,
|
||||||
|
string contentType = "application/json") => SendAsync(HttpMethod.Post, url, bodyString, contentType);
|
||||||
|
|
||||||
|
public Task<string> GetStringAsync(string url) => SendAsync(HttpMethod.Get, url, null, null);
|
||||||
|
|
||||||
|
// Unity callers use the main thread. Capture a fixed transport before the first await.
|
||||||
|
private async Task<string> SendAsync(HttpMethod method, string url, string body, string contentType)
|
||||||
|
{
|
||||||
|
if(kvOnly)
|
||||||
|
{
|
||||||
|
if(ownerContext!=null && !ReferenceEquals(SynchronizationContext.Current,ownerContext))
|
||||||
|
{
|
||||||
|
var completion=new TaskCompletionSource<string>(TaskCreationOptions.RunContinuationsAsynchronously);
|
||||||
|
ownerContext.Post(async _=>
|
||||||
|
{
|
||||||
|
try { completion.TrySetResult(await SendAsync(method,url,body,contentType)); }
|
||||||
|
catch(Exception ex) { completion.TrySetException(ex); }
|
||||||
|
},null);
|
||||||
|
return await completion.Task.ConfigureAwait(false);
|
||||||
|
}
|
||||||
|
if(!kvBusinessReady) throw new InvalidOperationException("Formal KV business transport is not ready.");
|
||||||
|
var lease=kvLease; var kvVersion=SessionVersion;
|
||||||
|
if(lease==null || !lease.IsFormal || !lease.IsCurrent) return null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var response=await lease.SendAsync(method,url,body,contentType);
|
||||||
|
if(!kvBusinessReady || kvVersion!=SessionVersion || !ReferenceEquals(lease,kvLease) || !response.IsCurrent)
|
||||||
|
return null;
|
||||||
|
if(response.StatusCode==(int)HttpStatusCode.OK) return response.Body;
|
||||||
|
if(response.StatusCode==(int)HttpStatusCode.Unauthorized || response.StatusCode==(int)HttpStatusCode.Forbidden)
|
||||||
|
{
|
||||||
|
DisableKVBusiness();
|
||||||
|
KVUnauthorized?.Invoke(SessionVersion);
|
||||||
|
}
|
||||||
|
else if(response.StatusCode.HasValue)
|
||||||
|
Debug.LogError($"API request failed: HTTP {response.StatusCode.Value}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
catch(Exception e)
|
||||||
|
{
|
||||||
|
if(kvVersion==SessionVersion) Debug.LogError($"API request failed: {e.GetType().Name}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pfRequests++;
|
||||||
|
var transport = client;
|
||||||
|
var version = SessionVersion;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//#if UNITY_EDITOR
|
using (var request = new HttpRequestMessage(method, url))
|
||||||
// Debug.Log("CustomServerPost url:" + url);
|
|
||||||
// Debug.Log("CustomServerPost bodyString:" + bodyString);
|
|
||||||
//#endif
|
|
||||||
var content = new StringContent(bodyString, Encoding.UTF8, "application/json");
|
|
||||||
var response = await client.PostAsync(url, content);
|
|
||||||
string result = await response.Content.ReadAsStringAsync();
|
|
||||||
if (response.StatusCode == System.Net.HttpStatusCode.OK)
|
|
||||||
{
|
{
|
||||||
//GameDebug.Log("CustomServerPost result:" + result.ToString());
|
if (body != null) request.Content = new StringContent(body, Encoding.UTF8, contentType);
|
||||||
return result;
|
using (var response = await transport.SendAsync(request))
|
||||||
}
|
{
|
||||||
else if (response.StatusCode == System.Net.HttpStatusCode.Unauthorized || response.StatusCode == System.Net.HttpStatusCode.Forbidden)
|
var result = await response.Content.ReadAsStringAsync();
|
||||||
{
|
if (version != SessionVersion) return null;
|
||||||
GContext.Publish(new game.EvtAPISvrUnauthorized());
|
if (response.StatusCode == HttpStatusCode.OK) return result;
|
||||||
return null;
|
if (response.StatusCode == HttpStatusCode.Unauthorized || response.StatusCode == HttpStatusCode.Forbidden)
|
||||||
}
|
GContext.Publish(new game.EvtAPISvrUnauthorized { SessionVersion = version });
|
||||||
else
|
else
|
||||||
{
|
Debug.LogError($"API request failed: HTTP {(int)response.StatusCode}");
|
||||||
Debug.LogError(response.StatusCode.ToString() + "+++CustomServerPost error:" +
|
return null;
|
||||||
result.ToString() + "+++CustomServerPost url:" + url + ":" +
|
}
|
||||||
bodyString);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Debug.LogError("CustomServerPost error:" + e.Message + "---CustomServerPost url:" +
|
if (version == SessionVersion) Debug.LogError($"API request failed: {e.GetType().Name}");
|
||||||
url + ":" + bodyString + "\n" + e.StackTrace);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<string> GetStringAsync(string url)
|
|
||||||
{
|
|
||||||
var response = await client.GetAsync(url);
|
|
||||||
|
|
||||||
if (response.StatusCode == HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
return await response.Content.ReadAsStringAsync();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
string result = await response.Content.ReadAsStringAsync();
|
|
||||||
Debug.LogError(response.StatusCode.ToString() + "+++GetStringAsync error:" +
|
|
||||||
result.ToString() + "+++GetStringAsync url:" + url);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (response.StatusCode == HttpStatusCode.Unauthorized)
|
|
||||||
{
|
|
||||||
GContext.Publish(new game.EvtAPISvrUnauthorized());
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task<string> AccountRequest(string url, object data)
|
public async Task<string> AccountRequest(string url, object data)
|
||||||
{
|
{
|
||||||
return await CustomServerPost($"account/{url}",
|
return await CustomServerPost($"account/{url}",
|
||||||
|
|||||||
52
Client/Assets/Scripts/Core/KVMgr.cs
Normal file
52
Client/Assets/Scripts/Core/KVMgr.cs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using game.PlayerDataStorage;
|
||||||
|
|
||||||
|
internal static class KVMgr
|
||||||
|
{
|
||||||
|
internal static PlayerKVKeyReadResult ReadKV(PlayerKVGameSessionHandle handle, string key)
|
||||||
|
{
|
||||||
|
if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.ReadLocal))
|
||||||
|
return new PlayerKVKeyReadResult(PlayerKVKeyReadError.LoadGuardActive, handle);
|
||||||
|
if (handle == null || !KVSnapshot.ValidKey(key))
|
||||||
|
return new PlayerKVKeyReadResult(PlayerKVKeyReadError.InvalidInput, handle);
|
||||||
|
var read = handle.ReadLocalSnapshot();
|
||||||
|
if (!read.Success)
|
||||||
|
return new PlayerKVKeyReadResult(read.Error == PlayerKVLocalReadError.StaleOrClosing
|
||||||
|
? PlayerKVKeyReadError.StaleOrClosing : PlayerKVKeyReadError.NotReady, handle);
|
||||||
|
var found = read.Data.TryGetValue(key, out var value);
|
||||||
|
return new PlayerKVKeyReadResult(PlayerKVKeyReadError.None, handle, found, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static PlayerKVEditResult WriteKV(PlayerKVGameSessionHandle handle,
|
||||||
|
string key, string value, bool remoteStore = true)
|
||||||
|
{
|
||||||
|
if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Update))
|
||||||
|
return new PlayerKVEditResult(new PlayerKVStateResult(PlayerKVChangeError.Blocked));
|
||||||
|
if (handle == null)
|
||||||
|
return new PlayerKVEditResult(new PlayerKVStateResult(PlayerKVChangeError.Validation));
|
||||||
|
return handle.Update(key, value, remoteStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Task<PlayerKVFlushResult> FlushKVAsync(PlayerKVGameSessionHandle handle,
|
||||||
|
CancellationToken waitToken = default)
|
||||||
|
{
|
||||||
|
if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Sync))
|
||||||
|
return Task.FromResult(new PlayerKVFlushResult(0, 0, 1, 0, PlayerKVError.Cancelled,
|
||||||
|
handle == null ? PlayerKVSyncStatus.NotLoaded : handle.Status));
|
||||||
|
if (handle == null)
|
||||||
|
return Task.FromResult(new PlayerKVFlushResult(0, 0, 1, 0, PlayerKVError.Validation, PlayerKVSyncStatus.NotLoaded));
|
||||||
|
return handle.FlushAsync(waitToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static Task<PlayerKVTicketResult> WaitForKVTicketAsync(PlayerKVGameSessionHandle handle,
|
||||||
|
PlayerKVSyncTicket ticket, CancellationToken waitToken = default)
|
||||||
|
{
|
||||||
|
if (PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Sync))
|
||||||
|
return Task.FromResult(new PlayerKVTicketResult(PlayerKVTicketStatus.Blocked, PlayerKVError.Cancelled,
|
||||||
|
handle == null ? PlayerKVSyncStatus.NotLoaded : handle.Status));
|
||||||
|
if (handle == null)
|
||||||
|
return Task.FromResult(new PlayerKVTicketResult(PlayerKVTicketStatus.Blocked, PlayerKVError.Validation, PlayerKVSyncStatus.NotLoaded));
|
||||||
|
return handle.WaitForTicketAsync(ticket, waitToken);
|
||||||
|
}
|
||||||
|
}
|
||||||
11
Client/Assets/Scripts/Core/KVMgr.cs.meta
Normal file
11
Client/Assets/Scripts/Core/KVMgr.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e96f727fbe08473c89bb88150927d2be
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -7,6 +7,7 @@ using System.Linq;
|
|||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using game.PlayerDataStorage;
|
||||||
|
|
||||||
public class PlayFabMgr : MonoBehaviour
|
public class PlayFabMgr : MonoBehaviour
|
||||||
{
|
{
|
||||||
@@ -25,6 +26,9 @@ public class PlayFabMgr : MonoBehaviour
|
|||||||
private CancellationTokenSource tokenSource;
|
private CancellationTokenSource tokenSource;
|
||||||
|
|
||||||
static PlayFabMgr _instance = null;
|
static PlayFabMgr _instance = null;
|
||||||
|
// An inactive, never-awakened component proves that no timer or PF send has ever been started.
|
||||||
|
internal bool IsUnstartedForKVLoad => tokenSource==null && dataBuffer==null && swapData==null && localData==null && lastUpdateTime==null && _instance!=this;
|
||||||
|
internal static bool HasLiveInstanceForKVLoad => _instance!=null;
|
||||||
|
|
||||||
public static PlayFabMgr Instance
|
public static PlayFabMgr Instance
|
||||||
{
|
{
|
||||||
@@ -41,6 +45,10 @@ public class PlayFabMgr : MonoBehaviour
|
|||||||
|
|
||||||
public Dictionary<string, string> CompareDatas(Dictionary<string, UserDataRecord> remoteDatas, string userId)
|
public Dictionary<string, string> CompareDatas(Dictionary<string, UserDataRecord> remoteDatas, string userId)
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(PlayerKVGameplayLoop.Enabled) throw PlayerKVGameplayLoop.Stop("PF archive comparison is disabled in KV loop.");
|
||||||
|
#endif
|
||||||
|
PlayerKVGameLoadGuard.RequireLegacyAllowed(PlayerKVGuardPoint.Compare);
|
||||||
Last_Update_Time_Key = $"{Last_Update_Time_Key_Prefix}_{userId}";
|
Last_Update_Time_Key = $"{Last_Update_Time_Key_Prefix}_{userId}";
|
||||||
Local_Data_Key = $"{Local_Data_Key_prefix}_{userId}";
|
Local_Data_Key = $"{Local_Data_Key_prefix}_{userId}";
|
||||||
var lastUpdateTimeStr = PlayerPrefs.GetString(Last_Update_Time_Key, string.Empty);
|
var lastUpdateTimeStr = PlayerPrefs.GetString(Last_Update_Time_Key, string.Empty);
|
||||||
@@ -114,12 +122,26 @@ public class PlayFabMgr : MonoBehaviour
|
|||||||
|
|
||||||
void Awake()
|
void Awake()
|
||||||
{
|
{
|
||||||
|
if(PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Lifecycle)) return;
|
||||||
_instance = this;
|
_instance = this;
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(PlayerKVGameplayLoop.Enabled) return;
|
||||||
|
#endif
|
||||||
InitBuffer();
|
InitBuffer();
|
||||||
tokenSource = new CancellationTokenSource();
|
tokenSource = new CancellationTokenSource();
|
||||||
UpdateUserDataValue(tokenSource.Token);
|
UpdateUserDataValue(tokenSource.Token);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
internal void StartKVGameplayLoopSync()
|
||||||
|
{
|
||||||
|
if(!PlayerKVGameplayLoop.Ready || tokenSource!=null) return;
|
||||||
|
tokenSource=new CancellationTokenSource();
|
||||||
|
UpdateUserDataValue(tokenSource.Token);
|
||||||
|
}
|
||||||
|
internal void StopKVGameplayLoopSync()
|
||||||
|
{ tokenSource?.Cancel(); tokenSource?.Dispose(); tokenSource=null; }
|
||||||
|
#endif
|
||||||
void InitBuffer()
|
void InitBuffer()
|
||||||
{
|
{
|
||||||
dataBuffer = new LinkedList<Dictionary<string, string>>();
|
dataBuffer = new LinkedList<Dictionary<string, string>>();
|
||||||
@@ -132,6 +154,15 @@ public class PlayFabMgr : MonoBehaviour
|
|||||||
|
|
||||||
void OnApplicationPause(bool is_pause)
|
void OnApplicationPause(bool is_pause)
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(PlayerKVGameplayLoop.Enabled)
|
||||||
|
{
|
||||||
|
if(is_pause) { StopKVGameplayLoopSync(); _=PlayerKVGameplayLoop.FlushObservedAsync(); }
|
||||||
|
else StartKVGameplayLoopSync();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if(PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Lifecycle)) return;
|
||||||
if (is_pause)
|
if (is_pause)
|
||||||
{
|
{
|
||||||
tokenSource.Cancel();
|
tokenSource.Cancel();
|
||||||
@@ -147,6 +178,10 @@ public class PlayFabMgr : MonoBehaviour
|
|||||||
|
|
||||||
void OnApplicationQuit()
|
void OnApplicationQuit()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(PlayerKVGameplayLoop.Enabled) { StopKVGameplayLoopSync(); _=PlayerKVGameplayLoop.CloseAsync(); return; }
|
||||||
|
#endif
|
||||||
|
if(PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Lifecycle)) return;
|
||||||
tokenSource.Cancel();
|
tokenSource.Cancel();
|
||||||
tokenSource = null;
|
tokenSource = null;
|
||||||
SyncData();
|
SyncData();
|
||||||
@@ -154,13 +189,19 @@ public class PlayFabMgr : MonoBehaviour
|
|||||||
|
|
||||||
void OnDestroy()
|
void OnDestroy()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(PlayerKVGameplayLoop.Enabled) { StopKVGameplayLoopSync(); _=PlayerKVGameplayLoop.CloseAsync(); return; }
|
||||||
|
#endif
|
||||||
|
if(PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Lifecycle)) return;
|
||||||
tokenSource?.Cancel();
|
tokenSource?.Cancel();
|
||||||
tokenSource = null;
|
tokenSource = null;
|
||||||
|
if(!PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.PrefsSave)) PlayerPrefs.Save();
|
||||||
SyncData();
|
SyncData();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void UpdateUserDataValue(CancellationToken token)
|
private async void UpdateUserDataValue(CancellationToken token)
|
||||||
{
|
{
|
||||||
|
if(PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Lifecycle)) return;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (!token.IsCancellationRequested)
|
while (!token.IsCancellationRequested)
|
||||||
@@ -174,6 +215,10 @@ public class PlayFabMgr : MonoBehaviour
|
|||||||
|
|
||||||
public void UpdateUserDataValue(string key, string data, bool remoteStore = true)
|
public void UpdateUserDataValue(string key, string data, bool remoteStore = true)
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(PlayerKVGameplayLoop.Enabled) { PlayerKVGameplayLoop.Write(key,data,remoteStore); return; }
|
||||||
|
#endif
|
||||||
|
PlayerKVGameLoadGuard.RequireLegacyAllowed(PlayerKVGuardPoint.Update);
|
||||||
if (remoteStore)
|
if (remoteStore)
|
||||||
{
|
{
|
||||||
var cbuff = dataBuffer.First;
|
var cbuff = dataBuffer.First;
|
||||||
@@ -203,6 +248,10 @@ public class PlayFabMgr : MonoBehaviour
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public string GetLocalData(string key)
|
public string GetLocalData(string key)
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(PlayerKVGameplayLoop.Enabled) return PlayerKVGameplayLoop.Read(key);
|
||||||
|
#endif
|
||||||
|
PlayerKVGameLoadGuard.RequireLegacyAllowed(PlayerKVGuardPoint.ReadLocal);
|
||||||
if (localData.ContainsKey(key))
|
if (localData.ContainsKey(key))
|
||||||
{
|
{
|
||||||
return localData[key];
|
return localData[key];
|
||||||
@@ -215,6 +264,12 @@ public class PlayFabMgr : MonoBehaviour
|
|||||||
|
|
||||||
private void SyncData()
|
private void SyncData()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(PlayerKVGameplayLoop.Enabled) { _=PlayerKVGameplayLoop.FlushObservedAsync(); return; }
|
||||||
|
#endif
|
||||||
|
if(PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Sync)) return;
|
||||||
|
// Logout clears credentials before RootCtx is destroyed. Keep pending data local.
|
||||||
|
if (!PlayFabClientAPI.IsClientLoggedIn()) return;
|
||||||
var buf = dataBuffer.First;
|
var buf = dataBuffer.First;
|
||||||
if (buf.Value.Count == 0)
|
if (buf.Value.Count == 0)
|
||||||
return;
|
return;
|
||||||
@@ -265,8 +320,14 @@ public class PlayFabMgr : MonoBehaviour
|
|||||||
GameDebug.LogError("[PlayFabMgr]UpdateUserData Error: {0}", error.ToString());
|
GameDebug.LogError("[PlayFabMgr]UpdateUserData Error: {0}", error.ToString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void FlushBufferedData() => SyncData();
|
||||||
|
|
||||||
public async Task<bool> SyncDataImmidiate(string key, string data)
|
public async Task<bool> SyncDataImmidiate(string key, string data)
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(PlayerKVGameplayLoop.Enabled) throw PlayerKVGameplayLoop.Stop("Immediate/consuming saves are outside the equipment loop.");
|
||||||
|
#endif
|
||||||
|
if(PlayerKVGameLoadGuard.Reject(PlayerKVGuardPoint.Immediate)) return false;
|
||||||
foreach (var buff in dataBuffer)
|
foreach (var buff in dataBuffer)
|
||||||
{
|
{
|
||||||
if (buff.ContainsKey(key))
|
if (buff.ContainsKey(key))
|
||||||
@@ -293,4 +354,5 @@ public class PlayFabMgr : MonoBehaviour
|
|||||||
);
|
);
|
||||||
return await taskSource.Task;
|
return await taskSource.Task;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -198,54 +198,69 @@ namespace Game
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected CompositeDisposable disposables;
|
protected CompositeDisposable disposables;
|
||||||
|
private int initializationVersion;
|
||||||
public async Task Init(System.Action<float> progress)
|
public async Task Init(System.Action<float> progress)
|
||||||
{
|
{
|
||||||
//playerData = GContext.container.Resolve<PlayerData>();
|
if (residentClip != null || disposables != null) Release();
|
||||||
_tables = GContext.container.Resolve<cfg.Tables>();
|
var version = ++initializationVersion;
|
||||||
//var service = (SoundService)soundService;
|
var container = GContext.container;
|
||||||
await soundService.InitAsync();
|
_tables = container.Resolve<cfg.Tables>();
|
||||||
|
|
||||||
var opMap = new Dictionary<string, AsyncOperationHandle<AudioClip>>();
|
var opMap = new Dictionary<string, AsyncOperationHandle<AudioClip>>();
|
||||||
|
CompositeDisposable pendingSubscriptions = null;
|
||||||
foreach (var addr in residentFish)
|
bool transferred = false;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
opMap[addr] = Addressables.LoadAssetAsync<AudioClip>(addr);
|
await soundService.InitAsync();
|
||||||
}
|
if (version != initializationVersion || !ReferenceEquals(container, GContext.container)) return;
|
||||||
|
foreach (var addr in residentFish)
|
||||||
var tasks = opMap.Values.Select(_ => _.Task);
|
|
||||||
var total = (float)tasks.Count();
|
|
||||||
|
|
||||||
while (true)
|
|
||||||
{
|
|
||||||
var completed = tasks.Count(_ => _.IsCompleted);
|
|
||||||
if (completed == total)
|
|
||||||
{
|
{
|
||||||
progress.Invoke(1f);
|
if (!opMap.ContainsKey(addr)) opMap.Add(addr, Addressables.LoadAssetAsync<AudioClip>(addr));
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
else
|
var tasks = opMap.Values.Select(_ => _.Task).ToArray();
|
||||||
|
var total = (float)tasks.Length;
|
||||||
|
while (true)
|
||||||
{
|
{
|
||||||
|
var completed = tasks.Count(_ => _.IsCompleted);
|
||||||
|
if (completed == total)
|
||||||
|
{
|
||||||
|
progress.Invoke(1f);
|
||||||
|
break;
|
||||||
|
}
|
||||||
progress.Invoke(completed / total);
|
progress.Invoke(completed / total);
|
||||||
|
await Awaiters.NextFrame;
|
||||||
|
if (version != initializationVersion || !ReferenceEquals(container, GContext.container)) return;
|
||||||
|
}
|
||||||
|
if (version != initializationVersion || !ReferenceEquals(container, GContext.container)) return;
|
||||||
|
var loadedClips = opMap.ToDictionary(_ => _.Key, _ => _.Value.Result);
|
||||||
|
pendingSubscriptions = new CompositeDisposable();
|
||||||
|
GContext.OnEvent<EventUISound>().Subscribe(PlaySound).AddTo(pendingSubscriptions);
|
||||||
|
GContext.OnEvent<EventRewardSound>().Subscribe(PlayRewardSound).AddTo(pendingSubscriptions);
|
||||||
|
GContext.OnEvent<EventFishingSound>().Subscribe(PlayFishingSound).AddTo(pendingSubscriptions);
|
||||||
|
GContext.OnEvent<EventBGMSound>().Subscribe(PlayMusic).AddTo(pendingSubscriptions);
|
||||||
|
GContext.OnEvent<FadeOutEvent>().Subscribe(FadeOutEvent).AddTo(pendingSubscriptions);
|
||||||
|
GContext.OnEvent<AssetReferenceAudioClip>().Subscribe(PlaySoundByReference).AddTo(pendingSubscriptions);
|
||||||
|
GContext.OnEvent<AssetReferenceAudioVoiceClip>().Subscribe(PlayVoiceSoundByReference).AddTo(pendingSubscriptions);
|
||||||
|
|
||||||
|
GContext.OnEvent<ChangeRodDataEvent>().Subscribe(OnChangeRodData).AddTo(pendingSubscriptions);
|
||||||
|
GContext.OnEvent<SoundMuteEvent>().Subscribe(OnSoundMute).AddTo(pendingSubscriptions);
|
||||||
|
GContext.OnEvent<OnSoundStateEvent>().Subscribe(OnSoundStateEvent).AddTo(pendingSubscriptions);
|
||||||
|
soundService.BGMVol = container.Resolve<ISettingService>().Music ? 80 : 0;
|
||||||
|
soundService.SFXVol = container.Resolve<ISettingService>().Sound ? 80 : 0;
|
||||||
|
soundService.VoiceVol = container.Resolve<ISettingService>().Sound ? 80 : 0;
|
||||||
|
residentClip = loadedClips;
|
||||||
|
disposables = pendingSubscriptions;
|
||||||
|
transferred = true;
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (!transferred)
|
||||||
|
{
|
||||||
|
pendingSubscriptions?.Dispose();
|
||||||
|
if (version == initializationVersion) Release();
|
||||||
|
foreach (var handle in opMap.Values)
|
||||||
|
if (handle.IsValid()) Addressables.Release(handle);
|
||||||
}
|
}
|
||||||
await Awaiters.NextFrame;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
residentClip = opMap.ToDictionary(_ => _.Key, _ => _.Value.Result);
|
|
||||||
disposables = new CompositeDisposable();
|
|
||||||
GContext.OnEvent<EventUISound>().Subscribe(PlaySound).AddTo(disposables);
|
|
||||||
GContext.OnEvent<EventRewardSound>().Subscribe(PlayRewardSound).AddTo(disposables);
|
|
||||||
GContext.OnEvent<EventFishingSound>().Subscribe(PlayFishingSound).AddTo(disposables);
|
|
||||||
GContext.OnEvent<EventBGMSound>().Subscribe(PlayMusic).AddTo(disposables);
|
|
||||||
GContext.OnEvent<FadeOutEvent>().Subscribe(FadeOutEvent).AddTo(disposables);
|
|
||||||
GContext.OnEvent<AssetReferenceAudioClip>().Subscribe(PlaySoundByReference).AddTo(disposables);
|
|
||||||
GContext.OnEvent<AssetReferenceAudioVoiceClip>().Subscribe(PlayVoiceSoundByReference).AddTo(disposables);
|
|
||||||
|
|
||||||
GContext.OnEvent<ChangeRodDataEvent>().Subscribe(OnChangeRodData).AddTo(disposables);
|
|
||||||
GContext.OnEvent<SoundMuteEvent>().Subscribe(OnSoundMute).AddTo(disposables);
|
|
||||||
GContext.OnEvent<OnSoundStateEvent>().Subscribe(OnSoundStateEvent).AddTo(disposables);
|
|
||||||
soundService.BGMVol = GContext.container.Resolve<ISettingService>().Music ? 80 : 0;
|
|
||||||
soundService.SFXVol = GContext.container.Resolve<ISettingService>().Sound ? 80 : 0;
|
|
||||||
soundService.VoiceVol = GContext.container.Resolve<ISettingService>().Sound ? 80 : 0;
|
|
||||||
}
|
}
|
||||||
void OnSoundStateEvent(OnSoundStateEvent onSoundStateEvent)
|
void OnSoundStateEvent(OnSoundStateEvent onSoundStateEvent)
|
||||||
{
|
{
|
||||||
@@ -757,6 +772,7 @@ namespace Game
|
|||||||
}
|
}
|
||||||
public void Release()
|
public void Release()
|
||||||
{
|
{
|
||||||
|
initializationVersion++;
|
||||||
if (disposables != null)
|
if (disposables != null)
|
||||||
{
|
{
|
||||||
disposables.Dispose();
|
disposables.Dispose();
|
||||||
|
|||||||
@@ -32,6 +32,31 @@ public class AchievementDataManager : IDisposable
|
|||||||
{
|
{
|
||||||
_tables = tables;
|
_tables = tables;
|
||||||
}
|
}
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVAchievementState DecodeForKVLoad(
|
||||||
|
IReadOnlyDictionary<string, string> raw, IReadOnlyDictionary<string, string> modern,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot, game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors)
|
||||||
|
=> game.PlayerDataStorage.PlayerKVSaveSchema.DecodeAchievements(raw, modern, snapshot, errors);
|
||||||
|
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
_achievementDatas = new Dictionary<ConditionType, AchievementData>();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVAchievementState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new ArgumentNullException(nameof(state));
|
||||||
|
var replacement = new Dictionary<ConditionType, AchievementData>();
|
||||||
|
foreach (var entry in state.Values)
|
||||||
|
replacement.Add((ConditionType)entry.Key, new AchievementData
|
||||||
|
{ Id = entry.Value.Id, Target = entry.Value.Target, day = entry.Value.Day });
|
||||||
|
_achievementDatas = replacement;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool IsEmptyForKVValidation => _achievementDatas.Count == 0;
|
||||||
|
internal AchievementData FindForKVValidation(ConditionType key)
|
||||||
|
=> _achievementDatas.TryGetValue(key, out var value)
|
||||||
|
? new AchievementData { Id = value.Id, Target = value.Target, day = value.day } : null;
|
||||||
|
|
||||||
public void LoadAchievementData(string value)
|
public void LoadAchievementData(string value)
|
||||||
{
|
{
|
||||||
_achievementDatas = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<ConditionType, AchievementData>>(value);
|
_achievementDatas = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<ConditionType, AchievementData>>(value);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -8,11 +8,69 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
public class BargainPackData
|
public class BargainPackData
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
|
||||||
private readonly Tables _tables = GContext.container.Resolve<Tables>();
|
private readonly Tables _tables = GContext.container.Resolve<Tables>();
|
||||||
private readonly TbEventPackManager _epm = GContext.container.Resolve<Tables>().TbEventPackManager;
|
private readonly TbEventPackManager _epm = GContext.container.Resolve<Tables>().TbEventPackManager;
|
||||||
private readonly TbSpecialPack _spp = GContext.container.Resolve<Tables>().TbSpecialPack;
|
private readonly TbSpecialPack _spp = GContext.container.Resolve<Tables>().TbSpecialPack;
|
||||||
private GeneralEventPackData _data;
|
private GeneralEventPackData _data;
|
||||||
|
|
||||||
|
private bool _kvLoadPresent;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
internal bool SelectionsAreIndependentForKVValidation()
|
||||||
|
{
|
||||||
|
var source = new List<int> { 7, 9 };
|
||||||
|
var state = new game.PlayerDataStorage.PlayerKVBargainState(true,0,_data.redirectID,0,0,0,0,0,0,0,0,0,false,false,0,source);
|
||||||
|
ReplaceFromKVDecoded(state);
|
||||||
|
source.Clear();
|
||||||
|
if (_data.selections.Count != 2 || ReferenceEquals(_data.selections, source) || ReferenceEquals(_data.selections, state.selections)) return false;
|
||||||
|
var previous = _data.selections;
|
||||||
|
_data.selections[0] = 10;
|
||||||
|
if (state.selections[0] != 7) return false;
|
||||||
|
ResetForKVLoad();
|
||||||
|
return _data.selections.Count == 0 && !ReferenceEquals(previous, _data.selections) && !_kvLoadPresent;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
internal bool KVLoadPresent => _kvLoadPresent;
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVBargainState DecodeForKVLoad(
|
||||||
|
IReadOnlyDictionary<string, string> raw, game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodeBargain(raw, snapshot, errors);
|
||||||
|
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
_kvLoadPresent = false;
|
||||||
|
_data = default(GeneralEventPackData);
|
||||||
|
_data.selections = new List<int>();
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVBargainState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new ArgumentNullException(nameof(state));
|
||||||
|
if (!state.IsPresent) { ResetForKVLoad(); return; }
|
||||||
|
var replacement = new GeneralEventPackData
|
||||||
|
{
|
||||||
|
currentEventID = state.currentEventID,
|
||||||
|
redirectID = state.redirectID,
|
||||||
|
VIPLvlWhenEventActivate = state.VIPLvlWhenEventActivate,
|
||||||
|
purchaseCount = state.purchaseCount,
|
||||||
|
savingProgress = state.savingProgress,
|
||||||
|
discountLvl = state.discountLvl,
|
||||||
|
visualProgress = state.visualProgress,
|
||||||
|
visualDiscountLvl = state.visualDiscountLvl,
|
||||||
|
rodID = state.rodID,
|
||||||
|
lastPackIDBought = state.lastPackIDBought,
|
||||||
|
packID = state.packID,
|
||||||
|
doNeedTrigger = state.doNeedTrigger,
|
||||||
|
isTriggered = state.isTriggered,
|
||||||
|
inflation = state.inflation,
|
||||||
|
selections = state.selections == null ? null : new List<int>(state.selections),
|
||||||
|
};
|
||||||
|
_data = replacement;
|
||||||
|
_kvLoadPresent = true;
|
||||||
|
}
|
||||||
|
internal game.PlayerDataStorage.PlayerKVBargainState SnapshotForKVValidation() =>
|
||||||
|
new game.PlayerDataStorage.PlayerKVBargainState(_kvLoadPresent, _data.currentEventID, _data.redirectID, _data.VIPLvlWhenEventActivate, _data.purchaseCount, _data.savingProgress, _data.discountLvl, _data.visualProgress, _data.visualDiscountLvl, _data.rodID, _data.lastPackIDBought, _data.packID, _data.doNeedTrigger, _data.isTriggered, _data.inflation, _data.selections);
|
||||||
|
|
||||||
public int CurrentEventID => _data.currentEventID;
|
public int CurrentEventID => _data.currentEventID;
|
||||||
|
|
||||||
public FishingEvent CurrentEvent => _tables.TbFishingEvent[_data.currentEventID];
|
public FishingEvent CurrentEvent => _tables.TbFishingEvent[_data.currentEventID];
|
||||||
@@ -25,10 +83,11 @@ public class BargainPackData
|
|||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (CurrentEventID == 0) return false;
|
var fishingEvent = _tables.TbFishingEvent.GetOrDefault(CurrentEventID);
|
||||||
|
if (!(fishingEvent?.TimeDefinition is LimitedTime time)) return false;
|
||||||
|
|
||||||
var et = DateTime.Parse((_tables.TbFishingEvent[_data.currentEventID].TimeDefinition as LimitedTime).EndTime);
|
var et = DateTime.Parse(time.EndTime);
|
||||||
var st = DateTime.Parse((_tables.TbFishingEvent[_data.currentEventID].TimeDefinition as LimitedTime).StartTime);
|
var st = DateTime.Parse(time.StartTime);
|
||||||
return ZZTimeHelper.UtcNow() >= st && ZZTimeHelper.UtcNow() < et;
|
return ZZTimeHelper.UtcNow() >= st && ZZTimeHelper.UtcNow() < et;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -121,8 +180,8 @@ public class BargainPackData
|
|||||||
public void SaveData()
|
public void SaveData()
|
||||||
{
|
{
|
||||||
//Debug.LogError("Testing, data not saved for debug purpose.");
|
//Debug.LogError("Testing, data not saved for debug purpose.");
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("GeneralEventPackData",
|
SaveStore.Write("GeneralEventPackData",
|
||||||
Newtonsoft.Json.JsonConvert.SerializeObject(_data));
|
Newtonsoft.Json.JsonConvert.SerializeObject(_data)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadData(GeneralEventPackData data)
|
public void LoadData(GeneralEventPackData data)
|
||||||
@@ -259,4 +318,4 @@ public class BargainPackProgressEvent
|
|||||||
{
|
{
|
||||||
public int type; //0: 初始化 1:增加动画
|
public int type; //0: 初始化 1:增加动画
|
||||||
public int addProgress;
|
public int addProgress;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,9 +33,33 @@ public struct BpVipUnlock
|
|||||||
|
|
||||||
public class BattlePassData
|
public class BattlePassData
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
public BattlePassRecord BattlePassRecord;
|
public BattlePassRecord BattlePassRecord;
|
||||||
public BattleTask BattleTask;
|
public BattleTask BattleTask;
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVBattlePassState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodeBattlePass(raw,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
BattlePassRecord=new BattlePassRecord();
|
||||||
|
BattleTask=new BattleTask();
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVBattlePassState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
var record=new BattlePassRecord {
|
||||||
|
ID=state.Record.ID,Level=state.Record.Level,Exp=state.Record.Exp,BuyVipToastIndex=state.Record.BuyVipToastIndex,
|
||||||
|
IsUnlockVip=state.Record.IsUnlockVip,NormalRewardGet=new List<int>(state.Record.Normal),VipRewardGet=new List<int>(state.Record.Vip),
|
||||||
|
LastDropIDs=new List<int>(state.Record.LastDrops),InflationRate=state.Record.Inflation
|
||||||
|
};
|
||||||
|
var task=new BattleTask {
|
||||||
|
dic_dailyTasks=state.Task.Daily.ToDictionary(p=>p.Key,p=>p.Value),dic_weeklyTasks=state.Task.Weekly.ToDictionary(p=>p.Key,p=>p.Value),
|
||||||
|
loginDays=new List<int>(state.Task.LoginDays),DailyTaskEndTime=state.Task.DailyEnd,WeeklyTaskEndTime=state.Task.WeeklyEnd
|
||||||
|
};
|
||||||
|
BattlePassRecord=record; BattleTask=task;
|
||||||
|
}
|
||||||
|
|
||||||
private Tables _tables;
|
private Tables _tables;
|
||||||
|
|
||||||
|
|
||||||
@@ -91,7 +115,7 @@ public class BattlePassData
|
|||||||
{
|
{
|
||||||
string battlePassRecord = BattlePassRecord.SerializeObject();
|
string battlePassRecord = BattlePassRecord.SerializeObject();
|
||||||
string battleTask = BattleTask.SerializeObject();
|
string battleTask = BattleTask.SerializeObject();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("BattlePassRecordTask", battlePassRecord + "#" + battleTask);
|
playerSaveStore.Write("BattlePassRecordTask", battlePassRecord + "#" + battleTask).RequireAccepted();
|
||||||
}
|
}
|
||||||
public void SaveBattlePassRecord()
|
public void SaveBattlePassRecord()
|
||||||
{
|
{
|
||||||
@@ -136,20 +160,16 @@ public class BattlePassData
|
|||||||
|
|
||||||
public void RefreshDaiyTask()
|
public void RefreshDaiyTask()
|
||||||
{
|
{
|
||||||
var bpMain = _tables.TbBattlePassMain.GetOrDefault(_tables.TbFishingEvent.GetOrDefault(BattlePassRecord.ID).RedirectID);
|
var fishingEvent = _tables.TbFishingEvent.GetOrDefault(BattlePassRecord.ID);
|
||||||
if (bpMain != null)
|
if (fishingEvent == null) return;
|
||||||
|
var bpMain = _tables.TbBattlePassMain.GetOrDefault(fishingEvent.RedirectID);
|
||||||
|
if (bpMain == null) return;
|
||||||
|
BattleTask.DailyTaskEndTime = ConvertTools.GetDateTimeYMD(ZZTimeHelper.UtcNow().UtcNowOffset()).AddDays(1);
|
||||||
|
var dailyTasks = bpMain.DailyTaskList;
|
||||||
|
BattleTask.dic_dailyTasks.Clear();
|
||||||
|
foreach (var task in dailyTasks)
|
||||||
{
|
{
|
||||||
BattleTask.DailyTaskEndTime = ConvertTools.GetDateTimeYMD(ZZTimeHelper.UtcNow().UtcNowOffset()).AddDays(1);
|
BattleTask.dic_dailyTasks.Add(task, 0);
|
||||||
var dailyTasks = bpMain.DailyTaskList;
|
|
||||||
BattleTask.dic_dailyTasks.Clear();
|
|
||||||
foreach (var task in dailyTasks)
|
|
||||||
{
|
|
||||||
BattleTask.dic_dailyTasks.Add(task, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BattleTask = new BattleTask();
|
|
||||||
}
|
}
|
||||||
GContext.Publish(new ConditionTypeEvent { type = ConditionType.LoginDays, count = 1 });
|
GContext.Publish(new ConditionTypeEvent { type = ConditionType.LoginDays, count = 1 });
|
||||||
SaveBattleTask();
|
SaveBattleTask();
|
||||||
@@ -157,23 +177,17 @@ public class BattlePassData
|
|||||||
|
|
||||||
public void RefreshWeeklyTask()
|
public void RefreshWeeklyTask()
|
||||||
{
|
{
|
||||||
|
var fishingEvent = _tables.TbFishingEvent.GetOrDefault(BattlePassRecord.ID);
|
||||||
var bpMain = _tables.TbBattlePassMain.GetOrDefault(_tables.TbFishingEvent.GetOrDefault(BattlePassRecord.ID).RedirectID);
|
if (fishingEvent == null) return;
|
||||||
if (bpMain != null)
|
var bpMain = _tables.TbBattlePassMain.GetOrDefault(fishingEvent.RedirectID);
|
||||||
|
if (bpMain == null) return;
|
||||||
|
var weeklyTasks = bpMain.WeeklyTaskList;
|
||||||
|
BattleTask.dic_weeklyTasks.Clear();
|
||||||
|
foreach (var task in weeklyTasks)
|
||||||
{
|
{
|
||||||
var weeklyTasks = bpMain.WeeklyTaskList;
|
BattleTask.dic_weeklyTasks.Add(task, 0);
|
||||||
BattleTask.dic_weeklyTasks.Clear();
|
|
||||||
foreach (var task in weeklyTasks)
|
|
||||||
{
|
|
||||||
BattleTask.dic_weeklyTasks.Add(task, 0);
|
|
||||||
}
|
|
||||||
BattleTask.WeeklyTaskEndTime = ConvertTools.GetDateTimeSunDay(ZZTimeHelper.UtcNow().UtcNowOffset()).AddDays(1);
|
|
||||||
}
|
|
||||||
//当前没有战令了
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BattleTask = new BattleTask();
|
|
||||||
}
|
}
|
||||||
|
BattleTask.WeeklyTaskEndTime = ConvertTools.GetDateTimeSunDay(ZZTimeHelper.UtcNow().UtcNowOffset()).AddDays(1);
|
||||||
BattlePassRecord.InflationRate = GContext.container.Resolve<PlayerData>().InflationRate;
|
BattlePassRecord.InflationRate = GContext.container.Resolve<PlayerData>().InflationRate;
|
||||||
|
|
||||||
GContext.Publish(new ConditionTypeEvent { type = ConditionType.LoginDays, count = 1 });
|
GContext.Publish(new ConditionTypeEvent { type = ConditionType.LoginDays, count = 1 });
|
||||||
@@ -207,7 +221,7 @@ public class BattlePassDataProvider : IDisposable
|
|||||||
private Tables _tables;
|
private Tables _tables;
|
||||||
private Dictionary<int, BattlePassLevel> dic_BPLevel;
|
private Dictionary<int, BattlePassLevel> dic_BPLevel;
|
||||||
|
|
||||||
public bool IsActivating => Data.BattlePassRecord.ID != 0;
|
public bool IsActivating => Data.BattlePassRecord.ID != 0 && curPassMain != null;
|
||||||
public bool UILockVip = false;
|
public bool UILockVip = false;
|
||||||
public bool IsUnlockVip => Data.BattlePassRecord.IsUnlockVip == 1;
|
public bool IsUnlockVip => Data.BattlePassRecord.IsUnlockVip == 1;
|
||||||
|
|
||||||
@@ -249,6 +263,7 @@ public class BattlePassDataProvider : IDisposable
|
|||||||
|
|
||||||
public void CheckIfRefreshBattblePass()
|
public void CheckIfRefreshBattblePass()
|
||||||
{
|
{
|
||||||
|
if (!IsActivating) return;
|
||||||
DateTime endTime = GContext.container.Resolve<FishingEventData>().GetEventEndTime(Data.BattlePassRecord.ID);
|
DateTime endTime = GContext.container.Resolve<FishingEventData>().GetEventEndTime(Data.BattlePassRecord.ID);
|
||||||
|
|
||||||
if (ZZTimeHelper.UtcNow().UtcNowOffset() >= endTime && IsActivating)
|
if (ZZTimeHelper.UtcNow().UtcNowOffset() >= endTime && IsActivating)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using System;
|
using System;
|
||||||
@@ -6,6 +6,8 @@ using System.Collections.Generic;
|
|||||||
|
|
||||||
public class BuffDataCenter
|
public class BuffDataCenter
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
|
||||||
private cfg.Tables _tables;
|
private cfg.Tables _tables;
|
||||||
public BuffDataCenter(cfg.Tables tables)
|
public BuffDataCenter(cfg.Tables tables)
|
||||||
{
|
{
|
||||||
@@ -16,6 +18,39 @@ public class BuffDataCenter
|
|||||||
Dictionary<int, FishBuffTimeData> globalBuffDataList = new Dictionary<int, FishBuffTimeData>();
|
Dictionary<int, FishBuffTimeData> globalBuffDataList = new Dictionary<int, FishBuffTimeData>();
|
||||||
FishBuffTimeData fishDailyBuff = null;
|
FishBuffTimeData fishDailyBuff = null;
|
||||||
public List<FishBuffTimeData> showFishBuffIds = new List<FishBuffTimeData>();
|
public List<FishBuffTimeData> showFishBuffIds = new List<FishBuffTimeData>();
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVBuffState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodeBuffs(raw,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
mapBuffDataList=new Dictionary<int,FishBuffTimeData>();
|
||||||
|
targetBuffDataList=new List<FishBuffTimeData>();
|
||||||
|
globalBuffDataList=new Dictionary<int,FishBuffTimeData>();
|
||||||
|
showFishBuffIds=new List<FishBuffTimeData>(); fishDailyBuff=null;
|
||||||
|
}
|
||||||
|
static FishBuffTimeData MaterializeKVBuff(game.PlayerDataStorage.PlayerKVBuffValue value) => value==null ? null : new FishBuffTimeData
|
||||||
|
{ SortID=value.SortID,sourceID=value.sourceID,buffID=value.buffID,isEnd=value.isEnd,buffEndTime=value.buffEndTime,isNew=false,addDown=0 };
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVBuffState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
var map=new Dictionary<int,FishBuffTimeData>(); var global=new Dictionary<int,FishBuffTimeData>(); var target=new List<FishBuffTimeData>();
|
||||||
|
foreach(var item in state.Map) map.Add(item.Key,MaterializeKVBuff(item.Value));
|
||||||
|
foreach(var item in state.Global) global.Add(item.Key,MaterializeKVBuff(item.Value));
|
||||||
|
foreach(var item in state.Target) target.Add(MaterializeKVBuff(item));
|
||||||
|
mapBuffDataList=map; globalBuffDataList=global; targetBuffDataList=target; fishDailyBuff=MaterializeKVBuff(state.Daily);
|
||||||
|
}
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
internal FishBuffTimeData BuffForKVValidation(int kind,int key)
|
||||||
|
{
|
||||||
|
if(kind==0) return mapBuffDataList.TryGetValue(key,out var value) ? value : null;
|
||||||
|
if(kind==1) return targetBuffDataList.Count>key ? targetBuffDataList[key] : null;
|
||||||
|
if(kind==2) return fishDailyBuff;
|
||||||
|
return globalBuffDataList.TryGetValue(key,out var global) ? global : null;
|
||||||
|
}
|
||||||
|
internal bool IsEmptyForKVValidation => mapBuffDataList.Count==0 && targetBuffDataList.Count==0 &&
|
||||||
|
globalBuffDataList.Count==0 && showFishBuffIds.Count==0 && fishDailyBuff==null;
|
||||||
|
#endif
|
||||||
public void InitData(Dictionary<string, string> userDatas)
|
public void InitData(Dictionary<string, string> userDatas)
|
||||||
{
|
{
|
||||||
if (userDatas.TryGetValue("BuffDataList", out string buffDataStr))
|
if (userDatas.TryGetValue("BuffDataList", out string buffDataStr))
|
||||||
@@ -169,7 +204,7 @@ public class BuffDataCenter
|
|||||||
DateTime now = ZZTimeHelper.UtcNow().UtcNowOffset();
|
DateTime now = ZZTimeHelper.UtcNow().UtcNowOffset();
|
||||||
mapBuffData.buffEndTime = now.AddSeconds(buffData.CountDown);
|
mapBuffData.buffEndTime = now.AddSeconds(buffData.CountDown);
|
||||||
mapBuffDataList.Add(mapID, mapBuffData);
|
mapBuffDataList.Add(mapID, mapBuffData);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("BuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(mapBuffDataList));
|
SaveStore.Write("BuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(mapBuffDataList)).RequireAccepted();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -258,12 +293,12 @@ public class BuffDataCenter
|
|||||||
if (targetBuffDataList[i].buffID == fishBuffTimeData.buffID && targetBuffDataList[i].sourceID == fishBuffTimeData.sourceID)
|
if (targetBuffDataList[i].buffID == fishBuffTimeData.buffID && targetBuffDataList[i].sourceID == fishBuffTimeData.sourceID)
|
||||||
{
|
{
|
||||||
targetBuffDataList[i] = fishBuffTimeData;
|
targetBuffDataList[i] = fishBuffTimeData;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList));
|
SaveStore.Write("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)).RequireAccepted();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
targetBuffDataList.Add(fishBuffTimeData);
|
targetBuffDataList.Add(fishBuffTimeData);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList));
|
SaveStore.Write("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -274,7 +309,7 @@ public class BuffDataCenter
|
|||||||
public void ClearTargetBuff()
|
public void ClearTargetBuff()
|
||||||
{
|
{
|
||||||
targetBuffDataList.Clear();
|
targetBuffDataList.Clear();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList));
|
SaveStore.Write("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)).RequireAccepted();
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// CollectionTargetWeight的特殊处理
|
/// CollectionTargetWeight的特殊处理
|
||||||
@@ -312,7 +347,7 @@ public class BuffDataCenter
|
|||||||
else if (fishItemId == eTKeepsake.FishIDList[collectionTargetWeight.TargetFishIndex - 1])
|
else if (fishItemId == eTKeepsake.FishIDList[collectionTargetWeight.TargetFishIndex - 1])
|
||||||
{
|
{
|
||||||
item.isEnd = true;
|
item.isEnd = true;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList));
|
SaveStore.Write("TargetBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(targetBuffDataList)).RequireAccepted();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -422,7 +457,7 @@ public class BuffDataCenter
|
|||||||
fishBuffTimeData.addDown = buff.CountDown;
|
fishBuffTimeData.addDown = buff.CountDown;
|
||||||
showFishBuffIds.Add(fishBuffTimeData);
|
showFishBuffIds.Add(fishBuffTimeData);
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("GlobalBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(globalBuffDataList));
|
SaveStore.Write("GlobalBuffDataList", Newtonsoft.Json.JsonConvert.SerializeObject(globalBuffDataList)).RequireAccepted();
|
||||||
GContext.Publish(new AddGlobalBuffEvent(buffID));
|
GContext.Publish(new AddGlobalBuffEvent(buffID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -526,7 +561,7 @@ public class BuffDataCenter
|
|||||||
}
|
}
|
||||||
AddGlobalBuff(buff.BuffID);
|
AddGlobalBuff(buff.BuffID);
|
||||||
fishDailyBuff.isEnd = false;
|
fishDailyBuff.isEnd = false;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("FishDailyBuff", Newtonsoft.Json.JsonConvert.SerializeObject(fishDailyBuff));
|
SaveStore.Write("FishDailyBuff", Newtonsoft.Json.JsonConvert.SerializeObject(fishDailyBuff)).RequireAccepted();
|
||||||
return fishDailyBuff;
|
return fishDailyBuff;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -558,4 +593,4 @@ public class AddGlobalBuffEvent
|
|||||||
{
|
{
|
||||||
this.buffID = buffID;
|
this.buffID = buffID;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using Activity.Services;
|
using Activity.Services;
|
||||||
using asap.core;
|
using asap.core;
|
||||||
using Assets.Scripts.UI.SocialRush;
|
using Assets.Scripts.UI.SocialRush;
|
||||||
using cfg;
|
using cfg;
|
||||||
@@ -56,6 +56,17 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
public partial class FishingEventData : IDisposable
|
public partial class FishingEventData : IDisposable
|
||||||
{
|
{
|
||||||
|
game.PlayerDataStorage.IPlayerSaveStore boundSaveStore;
|
||||||
|
[Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore
|
||||||
|
{
|
||||||
|
get => boundSaveStore;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
ThanksGivingPackData.BindSaveStore(value);
|
||||||
|
ChainPackWithProgressMigrationData.BindSaveStore(value);
|
||||||
|
boundSaveStore = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
private cfg.Tables _tables;
|
private cfg.Tables _tables;
|
||||||
private MMTService _mmtService;
|
private MMTService _mmtService;
|
||||||
private IEventTokenService _eventTokenService;
|
private IEventTokenService _eventTokenService;
|
||||||
@@ -130,6 +141,46 @@ namespace GameCore
|
|||||||
//待释放
|
//待释放
|
||||||
IDisposable disposable;
|
IDisposable disposable;
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVEventBaseState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
IReadOnlyDictionary<string,string> modern,game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors)
|
||||||
|
=> game.PlayerDataStorage.PlayerKVSaveSchema.DecodeEventBase(raw,modern,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
limitedTimeEventDic=new Dictionary<int,LimitedTimeEvent>(); fixedTimeEventDic=new Dictionary<int,FixedTimeEvent>();
|
||||||
|
ETDropAfterDropDic=new Dictionary<int,int>(); RankTargetCount=new Dictionary<int,int>(); WheelLevelCount=new Dictionary<int,int>();
|
||||||
|
TurntableCoupon=_tables.TbGlobalConfig.InitWheelTicket; WheelOperateCount=0; AllWheelOperateCount=0; freecount=0; PVPToken=0;
|
||||||
|
collectingTargetEventID=-1; virtualCollectingTargetEventID=-1; NewPlayerEvent=default;
|
||||||
|
collectingTargetInit=null; collectingTargetInitTokenID=0; collectingTargetInitTaskID=0;
|
||||||
|
TargetList=null; collectingTarget=null; preCollectingTarget=null; targetItemDatas=null; preRankTarget=null; rankItemDatas=null;
|
||||||
|
rankEvent=null; rankInit=null; rankTarget=null; turntableEvent=null; wheelInit=null; wheelLevel=null;
|
||||||
|
SystemOpen=new Dictionary<int,bool>(); _unlocked=new HashSet<int>(); _isTargetGuidance=true;
|
||||||
|
IsJoinUsPanelOpen=false; collectingTargetResoure=true; IsAquariumOpen=false; IsOpenDrop=false; OpenAquariumID=0;
|
||||||
|
requiredCount=0; requiredRankCount=0; curActivateItemId=0;
|
||||||
|
duelData=null; rankTierChangeState=0; curSolomain=null; Pack1A1Data=null; Pack1A2Data=null;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVEventBaseState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
limitedTimeEventDic=state.Limited.ToDictionary(p=>p.Key,p=>new LimitedTimeEvent { id=p.Value.Id,duration=p.Value.Duration,startTime=p.Value.StartTime });
|
||||||
|
fixedTimeEventDic=state.Fixed.ToDictionary(p=>p.Key,p=>new FixedTimeEvent { id=p.Value.id,endTime=p.Value.endTime });
|
||||||
|
ETDropAfterDropDic=state.Target.ToDictionary(p=>p.Key,p=>p.Value); RankTargetCount=state.Rank.ToDictionary(p=>p.Key,p=>p.Value);
|
||||||
|
WheelLevelCount=state.Wheel.ToDictionary(p=>p.Key,p=>p.Value); TurntableCoupon=state.Coupon;
|
||||||
|
WheelOperateCount=state.Operate; AllWheelOperateCount=state.AllOperate; freecount=state.Free; PVPToken=state.PvpToken;
|
||||||
|
}
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
internal game.PlayerDataStorage.PlayerKVEventBaseState SnapshotForKVValidation() => new game.PlayerDataStorage.PlayerKVEventBaseState(
|
||||||
|
limitedTimeEventDic.ToDictionary(p=>p.Key,p=>new game.PlayerDataStorage.PlayerKVLimitedValue(p.Value.id,p.Value.duration,p.Value.startTime)),
|
||||||
|
fixedTimeEventDic.ToDictionary(p=>p.Key,p=>new game.PlayerDataStorage.PlayerKVFixedTimeValue(p.Value.id,p.Value.endTime)),
|
||||||
|
ETDropAfterDropDic,RankTargetCount,WheelLevelCount,TurntableCoupon,WheelOperateCount,AllWheelOperateCount,freecount,PVPToken);
|
||||||
|
internal void MutateCollectionsForKVValidation()
|
||||||
|
{ limitedTimeEventDic.Values.First().duration=99; fixedTimeEventDic.Values.First().id=99; ETDropAfterDropDic.Clear(); RankTargetCount.Clear(); WheelLevelCount.Clear(); }
|
||||||
|
internal bool IsInactiveForKVValidation => collectingTargetEventID==-1 && virtualCollectingTargetEventID==-1 && NewPlayerEvent==default &&
|
||||||
|
collectingTargetInit==null && collectingTargetInitTokenID==0 && collectingTargetInitTaskID==0 && TargetList==null && collectingTarget==null &&
|
||||||
|
preCollectingTarget==null && targetItemDatas==null && preRankTarget==null && rankItemDatas==null && rankEvent==null && rankInit==null && rankTarget==null &&
|
||||||
|
turntableEvent==null && wheelInit==null && wheelLevel==null && SystemOpen.Count==0 && _unlocked.Count==0 && duelData==null && curSolomain==null &&
|
||||||
|
Pack1A1Data==null && Pack1A2Data==null && !IsJoinUsPanelOpen && !IsAquariumOpen && !IsOpenDrop && OpenAquariumID==0 && requiredCount==0 && requiredRankCount==0 && curActivateItemId==0;
|
||||||
|
#endif
|
||||||
|
|
||||||
public void InitData(Dictionary<string, string> userDatas)
|
public void InitData(Dictionary<string, string> userDatas)
|
||||||
{
|
{
|
||||||
InitTurntableRoll(_tables.TbGlobalConfig.InitWheelTicket);
|
InitTurntableRoll(_tables.TbGlobalConfig.InitWheelTicket);
|
||||||
@@ -538,7 +589,7 @@ namespace GameCore
|
|||||||
id = t.ID,
|
id = t.ID,
|
||||||
endTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(fixedTime.StartTime).ToString(),
|
endTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(fixedTime.StartTime).ToString(),
|
||||||
};
|
};
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("FixedTimeEventDic", JsonMapper.ToJson(fixedTimeEventDic));
|
playerSaveStore.Write("FixedTimeEventDic", JsonMapper.ToJson(fixedTimeEventDic)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
switch (t.Type)
|
switch (t.Type)
|
||||||
@@ -806,7 +857,7 @@ namespace GameCore
|
|||||||
|
|
||||||
private bool Condition_NoRechargeSeconds(int timeSeconds)
|
private bool Condition_NoRechargeSeconds(int timeSeconds)
|
||||||
{
|
{
|
||||||
var lastPaymentStr = PlayFabMgr.Instance.GetLocalData("LastPaymentTime");
|
var lastPaymentStr = playerSaveStore.Read("LastPaymentTime").ValueOrThrow();
|
||||||
DateTime curTime = ZZTimeHelper.UtcNow().UtcNowOffset();
|
DateTime curTime = ZZTimeHelper.UtcNow().UtcNowOffset();
|
||||||
DateTime endTime = curTime;
|
DateTime endTime = curTime;
|
||||||
if (string.IsNullOrEmpty(lastPaymentStr) || !lastPaymentStr.Contains("__"))
|
if (string.IsNullOrEmpty(lastPaymentStr) || !lastPaymentStr.Contains("__"))
|
||||||
@@ -826,7 +877,8 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public static bool Condition_NoRechargeDay(int timeDay = 7)
|
public static bool Condition_NoRechargeDay(int timeDay = 7)
|
||||||
{
|
{
|
||||||
var lastPaymentStr = PlayFabMgr.Instance.GetLocalData("LastPaymentTime");
|
var store = GContext.container.Resolve<FishingEventData>().playerSaveStore;
|
||||||
|
var lastPaymentStr = store.Read("LastPaymentTime").ValueOrThrow();
|
||||||
if (!string.IsNullOrEmpty(lastPaymentStr) && lastPaymentStr.Contains("__"))
|
if (!string.IsNullOrEmpty(lastPaymentStr) && lastPaymentStr.Contains("__"))
|
||||||
return false;
|
return false;
|
||||||
DateTime curTime = ZZTimeHelper.UtcNow();
|
DateTime curTime = ZZTimeHelper.UtcNow();
|
||||||
@@ -1012,7 +1064,7 @@ namespace GameCore
|
|||||||
case 2:
|
case 2:
|
||||||
// Debug.Log($"[EventBreak] Id {e.ID} activated.");
|
// Debug.Log($"[EventBreak] Id {e.ID} activated.");
|
||||||
EventBreakAct.Ctx = EventBreakTableContext.ReadTables(e.ID, GContext.container.Resolve<Tables>());
|
EventBreakAct.Ctx = EventBreakTableContext.ReadTables(e.ID, GContext.container.Resolve<Tables>());
|
||||||
var playfabData = EventBreakPfData.Deserialize(PlayFabMgr.Instance.GetLocalData(EventBreakPfData.PfKey));
|
var playfabData = EventBreakPfData.Deserialize(playerSaveStore.Read(EventBreakPfData.PfKey).ValueOrThrow());
|
||||||
var eventBreakModel = GContext.container.Resolve<DrillModel>();
|
var eventBreakModel = GContext.container.Resolve<DrillModel>();
|
||||||
if (eventBreakModel == null)
|
if (eventBreakModel == null)
|
||||||
{
|
{
|
||||||
@@ -1034,7 +1086,7 @@ namespace GameCore
|
|||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
var canModel = GContext.container.Resolve<EventCanModel>();
|
var canModel = GContext.container.Resolve<EventCanModel>();
|
||||||
var ecPlayfabString = PlayFabMgr.Instance.GetLocalData(EventCanPlayfabData.PlayFabKey);
|
var ecPlayfabString = playerSaveStore.Read(EventCanPlayfabData.PlayFabKey).ValueOrThrow();
|
||||||
var ecPpString = PlayerPrefs.GetString(EventCanPlayerPreferenceData.PlayerPrefsKey);
|
var ecPpString = PlayerPrefs.GetString(EventCanPlayerPreferenceData.PlayerPrefsKey);
|
||||||
var ecPlayfabData = EventCanPlayfabData.Deserialize(ecPlayfabString);
|
var ecPlayfabData = EventCanPlayfabData.Deserialize(ecPlayfabString);
|
||||||
var ecPlayerPrefsData = EventCanPlayerPreferenceData.Deserialize(ecPpString);
|
var ecPlayerPrefsData = EventCanPlayerPreferenceData.Deserialize(ecPpString);
|
||||||
@@ -1110,7 +1162,7 @@ namespace GameCore
|
|||||||
SetTurntable(t);
|
SetTurntable(t);
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
var pfString = PlayFabMgr.Instance.GetLocalData(EventLuckMagicPlayfabData.Key);
|
var pfString = playerSaveStore.Read(EventLuckMagicPlayfabData.Key).ValueOrThrow();
|
||||||
var pfData = EventLuckMagicPlayfabData.Deserialize(pfString);
|
var pfData = EventLuckMagicPlayfabData.Deserialize(pfString);
|
||||||
var ppString = PlayerPrefs.GetString(EventLuckMagicPlayerPreferenceData.Key);
|
var ppString = PlayerPrefs.GetString(EventLuckMagicPlayerPreferenceData.Key);
|
||||||
var ppData = EventLuckMagicPlayerPreferenceData.Deserialize(ppString);
|
var ppData = EventLuckMagicPlayerPreferenceData.Deserialize(ppString);
|
||||||
@@ -1299,7 +1351,7 @@ namespace GameCore
|
|||||||
SaveTransitionData(turntableEvent.ID, TurntableCoupon);
|
SaveTransitionData(turntableEvent.ID, TurntableCoupon);
|
||||||
}
|
}
|
||||||
TurntableRed();
|
TurntableRed();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TurntableRoll", TurntableCoupon.ToString());
|
playerSaveStore.Write("TurntableRoll", TurntableCoupon.ToString()).RequireAccepted();
|
||||||
}
|
}
|
||||||
public void RewardTurntableRoll(int value, bool remote = true)
|
public void RewardTurntableRoll(int value, bool remote = true)
|
||||||
{
|
{
|
||||||
@@ -1318,7 +1370,7 @@ namespace GameCore
|
|||||||
.AddContent("change_num", value);
|
.AddContent("change_num", value);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TurntableRoll", TurntableCoupon.ToString(), remote);
|
playerSaveStore.Write("TurntableRoll", TurntableCoupon.ToString(), remote).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void TurntableRed()
|
public void TurntableRed()
|
||||||
@@ -1403,7 +1455,7 @@ namespace GameCore
|
|||||||
|
|
||||||
void SetLimitedTimeEventDic()
|
void SetLimitedTimeEventDic()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("LimitedTimeEventDic", Newtonsoft.Json.JsonConvert.SerializeObject(limitedTimeEventDic));
|
playerSaveStore.Write("LimitedTimeEventDic", Newtonsoft.Json.JsonConvert.SerializeObject(limitedTimeEventDic)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region 目标奖励活动
|
#region 目标奖励活动
|
||||||
@@ -1575,10 +1627,14 @@ namespace GameCore
|
|||||||
|
|
||||||
public async Task<bool> CheckResourceLoadQueue(string key, List<string> label)
|
public async Task<bool> CheckResourceLoadQueue(string key, List<string> label)
|
||||||
{
|
{
|
||||||
|
var store = playerSaveStore;
|
||||||
|
if (!store.IsCurrent) return false;
|
||||||
if (!collectingTargetResoure)
|
if (!collectingTargetResoure)
|
||||||
{
|
{
|
||||||
ILoadResourceService loadResourceService = GContext.container.Resolve<ILoadResourceService>();
|
ILoadResourceService loadResourceService = GContext.container.Resolve<ILoadResourceService>();
|
||||||
collectingTargetResoure = await loadResourceService.CheckResourceLoadQueue(key, label);
|
var loaded = await loadResourceService.CheckResourceLoadQueue(key, label);
|
||||||
|
if (!store.IsCurrent) return false;
|
||||||
|
collectingTargetResoure = loaded;
|
||||||
}
|
}
|
||||||
return collectingTargetResoure;
|
return collectingTargetResoure;
|
||||||
}
|
}
|
||||||
@@ -2201,8 +2257,8 @@ namespace GameCore
|
|||||||
|
|
||||||
public void UpdateTurnTableData()
|
public void UpdateTurnTableData()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount));
|
playerSaveStore.Write("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount)).RequireAccepted();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("WheelLevelFreeCount", freecount.ToString());
|
playerSaveStore.Write("WheelLevelFreeCount", freecount.ToString()).RequireAccepted();
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Add item by dropId and multiplier, or just return that item without giving to player, if doAdd is false.
|
/// Add item by dropId and multiplier, or just return that item without giving to player, if doAdd is false.
|
||||||
@@ -2223,10 +2279,10 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
IncreaseScore(score * multiplier);
|
IncreaseScore(score * multiplier);
|
||||||
WheelOperateCount++;
|
WheelOperateCount++;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("WheelOperateCount", WheelOperateCount.ToString());
|
playerSaveStore.Write("WheelOperateCount", WheelOperateCount.ToString()).RequireAccepted();
|
||||||
AllWheelOperateCount += multiplier;
|
AllWheelOperateCount += multiplier;
|
||||||
|
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("AllWheelOperateCount", AllWheelOperateCount.ToString());
|
playerSaveStore.Write("AllWheelOperateCount", AllWheelOperateCount.ToString()).RequireAccepted();
|
||||||
}
|
}
|
||||||
public void IncreaseScore(int score)
|
public void IncreaseScore(int score)
|
||||||
{
|
{
|
||||||
@@ -2243,7 +2299,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount));
|
playerSaveStore.Write("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2265,7 +2321,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
freecount = 0;
|
freecount = 0;
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("WheelLevelFreeCount", freecount.ToString());
|
playerSaveStore.Write("WheelLevelFreeCount", freecount.ToString()).RequireAccepted();
|
||||||
}
|
}
|
||||||
//转盘等级增加函数
|
//转盘等级增加函数
|
||||||
public void IncreaseWheelLevel()
|
public void IncreaseWheelLevel()
|
||||||
@@ -2285,7 +2341,7 @@ namespace GameCore
|
|||||||
// 更新积分进度
|
// 更新积分进度
|
||||||
WheelLevelCount[wheelLevel.Level] = progress;
|
WheelLevelCount[wheelLevel.Level] = progress;
|
||||||
TurntableRed();
|
TurntableRed();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount));
|
playerSaveStore.Write("WheelLevelCount", JsonMapper.ToJson(WheelLevelCount)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public class GuideDataCenter : IDisposable
|
public class GuideDataCenter : IDisposable
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
Tables _tables;
|
Tables _tables;
|
||||||
PlayerData playerData;
|
PlayerData playerData;
|
||||||
public GuideDataCenter(cfg.Tables tables, PlayerData playerData)
|
public GuideDataCenter(cfg.Tables tables, PlayerData playerData)
|
||||||
@@ -56,6 +57,20 @@ namespace GameCore
|
|||||||
public string popupPanelNode;
|
public string popupPanelNode;
|
||||||
public GuidanceGroupDefine curGroupDefine;
|
public GuidanceGroupDefine curGroupDefine;
|
||||||
public GuidanceDefineSetting guidanceDefineSetting;
|
public GuidanceDefineSetting guidanceDefineSetting;
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVGuideState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) => game.PlayerDataStorage.PlayerKVSaveSchema.DecodeGuides(raw,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
GuideSaveDataDic = new Dictionary<string,GuideSaveData>(StringComparer.Ordinal);
|
||||||
|
curSaveData = null; curDefine = null; curGroupDefine = null; popupPanelNode = null; CurPanelName = null;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVGuideState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new ArgumentNullException(nameof(state));
|
||||||
|
GuideSaveDataDic = state.Values.ToDictionary(p=>p.Key,
|
||||||
|
p=>new GuideSaveData { guideSubIndex=p.Value.Index, isFinish=p.Value.Finished, groupName=p.Value.Group },StringComparer.Ordinal);
|
||||||
|
}
|
||||||
//待释放
|
//待释放
|
||||||
IDisposable disposable;
|
IDisposable disposable;
|
||||||
IDisposable disposable2;
|
IDisposable disposable2;
|
||||||
@@ -80,7 +95,10 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public async void Init()
|
public async void Init()
|
||||||
{
|
{
|
||||||
guidanceDefineSetting = (GuidanceDefineSetting)await Addressables.LoadAssetAsync<object>("GuidanceConfig");
|
var store = playerSaveStore;
|
||||||
|
var setting = (GuidanceDefineSetting)await Addressables.LoadAssetAsync<object>("GuidanceConfig");
|
||||||
|
if (disposed || !store.IsCurrent) return;
|
||||||
|
guidanceDefineSetting = setting;
|
||||||
if (guidanceDefineSetting != null)
|
if (guidanceDefineSetting != null)
|
||||||
{
|
{
|
||||||
bool isUpdate = false;
|
bool isUpdate = false;
|
||||||
@@ -101,6 +119,13 @@ namespace GameCore
|
|||||||
|
|
||||||
if (GuideSaveDataDic.TryGetValue(item.groupName.ToString(), out _saveData))
|
if (GuideSaveDataDic.TryGetValue(item.groupName.ToString(), out _saveData))
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if (DeferUnavailablePotionGuide(item, _saveData))
|
||||||
|
{
|
||||||
|
keyValuePairs[item.groupName.ToString()] = _saveData;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
if (!_saveData.isFinish && _saveData.guideSubIndex > 0)
|
if (!_saveData.isFinish && _saveData.guideSubIndex > 0)
|
||||||
{
|
{
|
||||||
for (int i = _saveData.guideSubIndex; i < item.guidanceDefines.Length; i++)
|
for (int i = _saveData.guideSubIndex; i < item.guidanceDefines.Length; i++)
|
||||||
@@ -153,6 +178,29 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
private static bool DeferUnavailablePotionGuide(GuidanceGroupDefine group, GuideSaveData saved)
|
||||||
|
{
|
||||||
|
if (!game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled || !game.PlayerDataStorage.PlayerKVGameplayLoop.Ready ||
|
||||||
|
group.groupName != GroupName.EventPotion01 || saved == null || saved.isFinish || saved.guideSubIndex <= 0 ||
|
||||||
|
group.guidanceDefines == null || saved.guideSubIndex >= group.guidanceDefines.Length ||
|
||||||
|
group.guidanceDefines[saved.guideSubIndex] == null ||
|
||||||
|
group.guidanceDefines[saved.guideSubIndex].panelName != "EventPotionPanel")
|
||||||
|
return false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Existing potion activity classification; availability query does not initialize activity data.
|
||||||
|
const int potionEventType = 4;
|
||||||
|
const int potionEventSubType = 5;
|
||||||
|
return GContext.container.Resolve<FishingEventData>().GetEvent(potionEventType, potionEventSubType) == -1;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("Potion guide availability query failed; retaining original guide recovery: " + ex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
public bool GetIsFinish(string groupName)
|
public bool GetIsFinish(string groupName)
|
||||||
{
|
{
|
||||||
return GuideSaveDataDic.ContainsKey(groupName) && GuideSaveDataDic[groupName].isFinish;
|
return GuideSaveDataDic.ContainsKey(groupName) && GuideSaveDataDic[groupName].isFinish;
|
||||||
@@ -451,7 +499,9 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
async void TriggerGuide(string groupName, string curPanelName, GuidanceGroupDefine guidanceGroupDefine)
|
async void TriggerGuide(string groupName, string curPanelName, GuidanceGroupDefine guidanceGroupDefine)
|
||||||
{
|
{
|
||||||
|
var store = playerSaveStore;
|
||||||
await System.Threading.Tasks.Task.Delay(200);
|
await System.Threading.Tasks.Task.Delay(200);
|
||||||
|
if (disposed || !store.IsCurrent) return;
|
||||||
curSaveData = new GuideSaveData();
|
curSaveData = new GuideSaveData();
|
||||||
curSaveData.groupName = groupName;
|
curSaveData.groupName = groupName;
|
||||||
GuideSaveDataDic[groupName] = curSaveData;
|
GuideSaveDataDic[groupName] = curSaveData;
|
||||||
@@ -598,6 +648,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
async void ShowPanel(string PanelName)
|
async void ShowPanel(string PanelName)
|
||||||
{
|
{
|
||||||
|
if (disposed || !playerSaveStore.IsCurrent) return;
|
||||||
if (curDefine.fingerType != FingerType.None)
|
if (curDefine.fingerType != FingerType.None)
|
||||||
{
|
{
|
||||||
disposable3 = GContext.OnEvent<GuideNextEvent>().Subscribe(GuideNextEvent);
|
disposable3 = GContext.OnEvent<GuideNextEvent>().Subscribe(GuideNextEvent);
|
||||||
@@ -608,10 +659,13 @@ namespace GameCore
|
|||||||
|
|
||||||
public async void ShowGuidancePopupPanel(string nodeName)
|
public async void ShowGuidancePopupPanel(string nodeName)
|
||||||
{
|
{
|
||||||
|
var store = playerSaveStore;
|
||||||
|
if (disposed || !store.IsCurrent) return;
|
||||||
popupPanelNode = nodeName;
|
popupPanelNode = nodeName;
|
||||||
if (!string.IsNullOrEmpty(popupPanelNode))
|
if (!string.IsNullOrEmpty(popupPanelNode))
|
||||||
{
|
{
|
||||||
await UIManager.Instance.ShowUI(UITypes.GuidancePopupPanel);
|
await UIManager.Instance.ShowUI(UITypes.GuidancePopupPanel);
|
||||||
|
if (disposed || !store.IsCurrent) return;
|
||||||
UIManager.Instance.HideUI(UITypes.GuidancePanel);
|
UIManager.Instance.HideUI(UITypes.GuidancePanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -668,11 +722,13 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
List<string> strings = GuideSaveDataDic.Select(kv => kv.Key + "|" + kv.Value.guideSubIndex + "|" + (kv.Value.isFinish ? "1" : "0")).ToList();
|
List<string> strings = GuideSaveDataDic.Select(kv => kv.Key + "|" + kv.Value.guideSubIndex + "|" + (kv.Value.isFinish ? "1" : "0")).ToList();
|
||||||
string value = string.Join(";", strings);
|
string value = string.Join(";", strings);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("GuideSaveDataNew", value);
|
playerSaveStore.Write("GuideSaveDataNew", value).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool disposed;
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
disposed = true;
|
||||||
disposable?.Dispose();
|
disposable?.Dispose();
|
||||||
disposable = null;
|
disposable = null;
|
||||||
disposable2?.Dispose();
|
disposable2?.Dispose();
|
||||||
|
|||||||
@@ -2,9 +2,11 @@ using asap.core;
|
|||||||
using asap.playfab.async;
|
using asap.playfab.async;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
|
using game.PlayerDataStorage;
|
||||||
using PlayFab.ClientModels;
|
using PlayFab.ClientModels;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using tysdk;
|
using tysdk;
|
||||||
@@ -162,6 +164,27 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
Statistics.Add(new StatisticUpdate() { StatisticName = names[i], Value = value[i] });
|
Statistics.Add(new StatisticUpdate() { StatisticName = names[i], Value = value[i] });
|
||||||
}
|
}
|
||||||
|
if (userService is KVUserService kvUser)
|
||||||
|
{
|
||||||
|
var store = kvUser.SaveStore;
|
||||||
|
var writtenNames = new HashSet<string>(StringComparer.Ordinal);
|
||||||
|
bool accepted = false;
|
||||||
|
foreach (var statistic in Statistics)
|
||||||
|
{
|
||||||
|
if (!writtenNames.Add(statistic.StatisticName)) continue;
|
||||||
|
var write = store.Write(statistic.StatisticName, statistic.Value.ToString(CultureInfo.InvariantCulture));
|
||||||
|
if (write.Accepted) accepted = true;
|
||||||
|
else Debug.LogError("KV statistic write failed: " + statistic.StatisticName + ": " + write.Error);
|
||||||
|
}
|
||||||
|
if (accepted)
|
||||||
|
{
|
||||||
|
var confirmation = await store.FlushAsync();
|
||||||
|
if (confirmation.Status != PlayerSaveStatus.Confirmed)
|
||||||
|
Debug.LogError("KV statistic save not confirmed: " + string.Join(",", writtenNames) +
|
||||||
|
": " + confirmation.Status + ": " + confirmation.Error);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
UpdatePlayerStatisticsRequest request = new UpdatePlayerStatisticsRequest()
|
UpdatePlayerStatisticsRequest request = new UpdatePlayerStatisticsRequest()
|
||||||
{
|
{
|
||||||
Statistics = Statistics,
|
Statistics = Statistics,
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
public class PlayerData
|
public class PlayerData
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
private cfg.Tables _tables;
|
private cfg.Tables _tables;
|
||||||
MMTService _MMService;
|
MMTService _MMService;
|
||||||
public PlayerData(cfg.Tables tables, MMTService mmService)
|
public PlayerData(cfg.Tables tables, MMTService mmService)
|
||||||
@@ -34,6 +35,42 @@ namespace GameCore
|
|||||||
public const string Diamond = "DiamondTrue";
|
public const string Diamond = "DiamondTrue";
|
||||||
Dictionary<string, string> NewPlayerDataDic = new Dictionary<string, string>();
|
Dictionary<string, string> NewPlayerDataDic = new Dictionary<string, string>();
|
||||||
public IReadOnlyDictionary<string, string> PlayerDataDic => NewPlayerDataDic;
|
public IReadOnlyDictionary<string, string> PlayerDataDic => NewPlayerDataDic;
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVPlayerState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
IReadOnlyDictionary<string,string> modern,game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) => game.PlayerDataStorage.PlayerKVSaveSchema.DecodePlayer(raw,modern,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
NewPlayerDataDic=new Dictionary<string,string>(StringComparer.Ordinal); vipScoreDic=new Dictionary<int,int>();
|
||||||
|
newRodList=new List<int>();
|
||||||
|
lv=vip=vipAllScore=0; vipLastScore=PriceLv=0; priceLevel=null;
|
||||||
|
energy=pearl=diamond=equipRodID=magnification=seasonId=rewardNewMap=0;
|
||||||
|
gold=0; goldRM=0; energyRM=0; _currentMapId=_lastMapId=0;
|
||||||
|
_fishingFrequency=_allFishingFrequency=0; _lastEnergyRecoveryTime=DateTime.MinValue;
|
||||||
|
IsOpenAppraise=false; InfiniteBuildingData=null;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVPlayerState state)
|
||||||
|
{
|
||||||
|
if(state==null || state.Core==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
var modern=state.Modern.ToDictionary(p=>p.Key,p=>p.Value,StringComparer.Ordinal);
|
||||||
|
var scores=state.VipScores.ToDictionary(p=>p.Key,p=>p.Value);
|
||||||
|
var rods=new List<int>(state.NewRods);
|
||||||
|
var core=state.Core;
|
||||||
|
lv=core.Integer(0); gold=core.Unsigned(1); vipAllScore=core.Integer(2); energy=core.Integer(3);
|
||||||
|
pearl=core.Integer(4); magnification=core.Integer(5); equipRodID=core.Integer(6); _lastEnergyRecoveryTime=core.EnergyTime;
|
||||||
|
rewardNewMap=core.Integer(8); energyRM=core.Integer(9); goldRM=core.Unsigned(10); diamond=core.Integer(11);
|
||||||
|
_currentMapId=core.Integer(12); _lastMapId=core.Integer(13); _fishingFrequency=core.Integer(14); _allFishingFrequency=core.Integer(15);
|
||||||
|
NewPlayerDataDic=modern; vipScoreDic=scores; newRodList=rods;
|
||||||
|
seasonId=state.Season; IsOpenAppraise=state.Appraise; InfiniteBuildingData=state.Building;
|
||||||
|
}
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
internal game.PlayerDataStorage.PlayerKVPlayerState SnapshotForKVValidation() =>
|
||||||
|
new game.PlayerDataStorage.PlayerKVPlayerState(new game.PlayerDataStorage.PlayerKVCoreState(new object[] {
|
||||||
|
(int)lv,(ulong)gold,(int)vipAllScore,(int)energy,(int)pearl,(int)magnification,(int)equipRodID,_lastEnergyRecoveryTime,
|
||||||
|
(int)rewardNewMap,energyRM,goldRM,(int)diamond,(int)_currentMapId,(int)_lastMapId,_fishingFrequency,_allFishingFrequency,0,0,0
|
||||||
|
}),NewPlayerDataDic,vipScoreDic,newRodList,seasonId,IsOpenAppraise,InfiniteBuildingData);
|
||||||
|
internal bool IsDerivedEmptyForKVValidation => (int)vip==0 && vipLastScore==0 && PriceLv==0 && priceLevel==null;
|
||||||
|
#endif
|
||||||
public ObscuredInt lv { get; set; }
|
public ObscuredInt lv { get; set; }
|
||||||
public ObscuredInt vip { get; private set; }
|
public ObscuredInt vip { get; private set; }
|
||||||
public ObscuredInt vipAllScore { get; private set; }
|
public ObscuredInt vipAllScore { get; private set; }
|
||||||
@@ -300,7 +337,7 @@ namespace GameCore
|
|||||||
if (!newRodList.Contains(id))
|
if (!newRodList.Contains(id))
|
||||||
{
|
{
|
||||||
newRodList.Add(id);
|
newRodList.Add(id);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("NewRodList", JsonMapper.ToJson(newRodList));
|
playerSaveStore.Write("NewRodList", JsonMapper.ToJson(newRodList)).RequireAccepted();
|
||||||
if (addShowNewRod)
|
if (addShowNewRod)
|
||||||
{
|
{
|
||||||
showNewRodList.Add(id);
|
showNewRodList.Add(id);
|
||||||
@@ -331,7 +368,7 @@ namespace GameCore
|
|||||||
public void RewardNewRod(int id)
|
public void RewardNewRod(int id)
|
||||||
{
|
{
|
||||||
newRodList.Remove(id);
|
newRodList.Remove(id);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("NewRodList", JsonMapper.ToJson(newRodList));
|
playerSaveStore.Write("NewRodList", JsonMapper.ToJson(newRodList)).RequireAccepted();
|
||||||
GContext.container.Resolve<PlayerFishData>().SetRedPoint();
|
GContext.container.Resolve<PlayerFishData>().SetRedPoint();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1103,6 +1140,57 @@ namespace GameCore
|
|||||||
public void SavePlayerData(bool remote = true)
|
public void SavePlayerData(bool remote = true)
|
||||||
{
|
{
|
||||||
GContext.Publish<PlayerData>(this);
|
GContext.Publish<PlayerData>(this);
|
||||||
|
SerializeAndSavePlayerData(remote);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
internal async System.Threading.Tasks.Task ConsumeEnergyForKVLoopAsync(int cost,
|
||||||
|
game.PlayerDataStorage.PlayerKVGameplayLoop.FishingAction action)
|
||||||
|
{
|
||||||
|
if(cost<=0 || Energy<cost) throw game.PlayerDataStorage.PlayerKVGameplayLoop.Stop("Invalid fishing energy cost or insufficient energy.");
|
||||||
|
int before=Energy;
|
||||||
|
var batch=game.PlayerDataStorage.PlayerKVGameplayLoop.BeginFishingWrites(action);
|
||||||
|
game.PlayerDataStorage.PlayerKVEditResult primary;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using(batch)
|
||||||
|
{
|
||||||
|
ReduceEnergy(cost,false);
|
||||||
|
GContext.Publish(new ConditionTypeEvent(ConditionType.ConsumeEnergy,cost));
|
||||||
|
primary=SerializeAndSavePlayerData(true);
|
||||||
|
}
|
||||||
|
game.PlayerDataStorage.PlayerKVGameplayLoop.Audit("fishing-energy-applied",new{before,cost,after=(int)Energy,writes=batch.Records.Count,localOnly=batch.Records.Count(r=>!r.Remote)});
|
||||||
|
await game.PlayerDataStorage.PlayerKVGameplayLoop.ConfirmFishingAsync(action,batch,primary);
|
||||||
|
}
|
||||||
|
catch(System.Exception e) { game.PlayerDataStorage.PlayerKVGameplayLoop.Fault(e.Message); throw; }
|
||||||
|
}
|
||||||
|
internal async System.Threading.Tasks.Task SetEquipRodIDForKVLoopAsync(int id)
|
||||||
|
{
|
||||||
|
var batch=game.PlayerDataStorage.PlayerKVGameplayLoop.BeginEquip();
|
||||||
|
game.PlayerDataStorage.PlayerKVEditResult primary;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using(batch)
|
||||||
|
{
|
||||||
|
equipRodID=id;
|
||||||
|
GContext.container.Resolve<PlayerFishData>().SetRedPoint();
|
||||||
|
GContext.Publish<PlayerData>(this);
|
||||||
|
primary=SerializeAndSavePlayerData(true);
|
||||||
|
}
|
||||||
|
await game.PlayerDataStorage.PlayerKVGameplayLoop.ConfirmEquipAsync(batch,primary);
|
||||||
|
}
|
||||||
|
catch(System.Exception e) { game.PlayerDataStorage.PlayerKVGameplayLoop.Fault(e.Message); throw; }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
internal game.PlayerDataStorage.PlayerKVEditResult SaveFishingRewardForKVLoop()
|
||||||
|
{
|
||||||
|
game.PlayerDataStorage.PlayerKVGameplayLoop.CheckRewardMainSave();
|
||||||
|
return SerializeAndSavePlayerData(true);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
private game.PlayerDataStorage.PlayerKVEditResult SerializeAndSavePlayerData(bool remote)
|
||||||
|
{
|
||||||
StringBuilder sb = new StringBuilder();
|
StringBuilder sb = new StringBuilder();
|
||||||
sb.Append(lv).Append(",");
|
sb.Append(lv).Append(",");
|
||||||
sb.Append(gold).Append(",");
|
sb.Append(gold).Append(",");
|
||||||
@@ -1143,7 +1231,11 @@ namespace GameCore
|
|||||||
|
|
||||||
NewPlayerDataDic["ct"] = GContext.container.Resolve<FishingEventData>().CTSerialize();
|
NewPlayerDataDic["ct"] = GContext.container.Resolve<FishingEventData>().CTSerialize();
|
||||||
NewPlayerDataDic["rt"] = GContext.container.Resolve<FishingEventData>().RTSerialize(); ;
|
NewPlayerDataDic["rt"] = GContext.container.Resolve<FishingEventData>().RTSerialize(); ;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("NewPlayerDataDic", Newtonsoft.Json.JsonConvert.SerializeObject(NewPlayerDataDic), remote);
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled) return game.PlayerDataStorage.PlayerKVGameplayLoop.Write("NewPlayerDataDic",Newtonsoft.Json.JsonConvert.SerializeObject(NewPlayerDataDic),remote);
|
||||||
|
#endif
|
||||||
|
playerSaveStore.Write("NewPlayerDataDic", Newtonsoft.Json.JsonConvert.SerializeObject(NewPlayerDataDic), remote).RequireAccepted();
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
@@ -1301,13 +1393,14 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public async void CoRecoveryEnergy(int energyRecoveryTime)
|
public async void CoRecoveryEnergy(int energyRecoveryTime)
|
||||||
{
|
{
|
||||||
|
var store = playerSaveStore;
|
||||||
tokenSource?.Cancel();
|
tokenSource?.Cancel();
|
||||||
tokenSource = new System.Threading.CancellationTokenSource();
|
tokenSource = new System.Threading.CancellationTokenSource();
|
||||||
var token = tokenSource.Token;
|
var token = tokenSource.Token;
|
||||||
_isRecoveryEnergy = true;
|
_isRecoveryEnergy = true;
|
||||||
int initEnergyRestorationSpeed = _tables.TbGlobalConfig.InitEnergyRestorationSpeed * 60;
|
int initEnergyRestorationSpeed = _tables.TbGlobalConfig.InitEnergyRestorationSpeed * 60;
|
||||||
|
|
||||||
while (Energy < MaxEnergy && !token.IsCancellationRequested)
|
while (Energy < MaxEnergy && !token.IsCancellationRequested && store.IsCurrent)
|
||||||
{
|
{
|
||||||
if (energyRecoveryTime >= initEnergyRestorationSpeed)
|
if (energyRecoveryTime >= initEnergyRestorationSpeed)
|
||||||
{
|
{
|
||||||
@@ -1340,7 +1433,7 @@ namespace GameCore
|
|||||||
SavePlayerData();
|
SavePlayerData();
|
||||||
}
|
}
|
||||||
await Awaiters.Seconds(1);
|
await Awaiters.Seconds(1);
|
||||||
if (token.IsCancellationRequested)
|
if (token.IsCancellationRequested || !store.IsCurrent)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1411,14 +1504,17 @@ namespace GameCore
|
|||||||
|
|
||||||
public async void OpenAppraisePopupPanel(int fishId)
|
public async void OpenAppraisePopupPanel(int fishId)
|
||||||
{
|
{
|
||||||
|
var store = playerSaveStore;
|
||||||
|
if (!store.IsCurrent) return;
|
||||||
if (lastMapId != _tables.TbMapData.DataList[0].ID && !IsOpenAppraise)
|
if (lastMapId != _tables.TbMapData.DataList[0].ID && !IsOpenAppraise)
|
||||||
{
|
{
|
||||||
var fishData = _tables.TbFishData.GetOrDefault(fishId);
|
var fishData = _tables.TbFishData.GetOrDefault(fishId);
|
||||||
if (fishData != null && fishData.Quality >= 5)
|
if (fishData != null && fishData.Quality >= 5)
|
||||||
{
|
{
|
||||||
await UIManager.Instance.ShowUI(UITypes.AppraisePopupPanel);
|
await UIManager.Instance.ShowUI(UITypes.AppraisePopupPanel);
|
||||||
|
if (!store.IsCurrent) return;
|
||||||
IsOpenAppraise = true;
|
IsOpenAppraise = true;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("IsOpenAppraise", "true");
|
playerSaveStore.Write("IsOpenAppraise", "true").RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public partial class PlayerFishData
|
public partial class PlayerFishData
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
private cfg.Tables _tables;
|
private cfg.Tables _tables;
|
||||||
private ICustomServerMgr customServerMgr;
|
private ICustomServerMgr customServerMgr;
|
||||||
public PlayerFishData(cfg.Tables tables, ICustomServerMgr customServerMgr)
|
public PlayerFishData(cfg.Tables tables, ICustomServerMgr customServerMgr)
|
||||||
@@ -85,6 +86,46 @@ namespace GameCore
|
|||||||
public Dictionary<string, float> LuckDataDic = new Dictionary<string, float>();
|
public Dictionary<string, float> LuckDataDic = new Dictionary<string, float>();
|
||||||
public bool IsOpenPiercing = false;
|
public bool IsOpenPiercing = false;
|
||||||
public int RodSelectedInPack = 0;
|
public int RodSelectedInPack = 0;
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVFishState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
IReadOnlyDictionary<string,string> modern,game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors)
|
||||||
|
=> game.PlayerDataStorage.PlayerKVSaveSchema.DecodeFish(raw,modern,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
mapFishData=new Dictionary<int,Dictionary<int,FishWeightData>>(); fishData=new Dictionary<int,FishWeightData>(); fishCardData=new Dictionary<int,int>();
|
||||||
|
mapProgress=new Dictionary<int,int>(); rodData=new Dictionary<int,int>(); rodLevelData=new Dictionary<int,int>();
|
||||||
|
fishSwimToMap=new Dictionary<int,int>(); fishSwimToMapCount=new Dictionary<int,int>(); _honorlevel=new Dictionary<int,int>();
|
||||||
|
LuckDataDic=new Dictionary<string,float>(StringComparer.Ordinal); rodAccessoriesData=null;
|
||||||
|
InitBotLuck=0; InitFishLuck=0; BotCount=0; _isRedPoint_up=false; RodCanUp=false; RodCanUpLevel=false;
|
||||||
|
MapTipforUnlocked=0; IsOpenMap=false; IsOpenRod=false; IsOpenPiercing=false; RodSelectedInPack=0;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVFishState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
var maps=state.Maps.ToDictionary(m=>m.Key,m=>m.Value.ToDictionary(p=>p.Key,p=>new FishWeightData {
|
||||||
|
Level=p.Value.Level,MaxG=p.Value.Weight,TotalCard=p.Value.Cards,TotalNum=p.Value.Number,NewFish=p.Value.New }));
|
||||||
|
var flat=new Dictionary<int,FishWeightData>();
|
||||||
|
foreach(var map in maps.Values) foreach(var p in map) flat.Add(p.Key,p.Value);
|
||||||
|
mapFishData=maps; fishData=flat; fishCardData=state.Cards.ToDictionary(p=>p.Key,p=>p.Value);
|
||||||
|
rodData=state.Rods.ToDictionary(p=>p.Key,p=>p.Value); rodLevelData=state.RodLevels.ToDictionary(p=>p.Key,p=>p.Value);
|
||||||
|
fishSwimToMap=state.Swim.ToDictionary(p=>p.Key,p=>p.Value); fishSwimToMapCount=state.SwimCount.ToDictionary(p=>p.Key,p=>p.Value);
|
||||||
|
mapProgress=state.Progress.ToDictionary(p=>p.Key,p=>p.Value); _honorlevel=state.Honor.ToDictionary(p=>p.Key,p=>p.Value);
|
||||||
|
LuckDataDic=state.Luck.ToDictionary(p=>p.Key,p=>p.Value,StringComparer.Ordinal);
|
||||||
|
var a=state.Accessories;
|
||||||
|
rodAccessoriesData=a==null ? null : new RodGSAData { GloveID=a.Glove,RodToSkin=a.RodSkin.ToDictionary(p=>p.Key,p=>p.Value),
|
||||||
|
GloveIds=new List<int>(a.Gloves),SkinIds=new List<int>(a.Skins),GloveNewIds=new List<int>(a.NewGloves),SkinNewIds=new List<int>(a.NewSkins) };
|
||||||
|
}
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
internal FishWeightData FishForKVValidation(int map,int id) => mapFishData[map][id];
|
||||||
|
internal bool IndexesMatchForKVValidation(int map,int id,int card) => ReferenceEquals(mapFishData[map][id],fishData[id]) && fishCardData[card]==fishData[id].TotalCard;
|
||||||
|
internal bool EmptyForKVValidation => mapFishData.Count==0 && fishData.Count==0 && fishCardData.Count==0 && mapProgress.Count==0 && rodData.Count==0 && rodLevelData.Count==0 &&
|
||||||
|
fishSwimToMap.Count==0 && fishSwimToMapCount.Count==0 && _honorlevel.Count==0 && LuckDataDic.Count==0 && rodAccessoriesData==null &&
|
||||||
|
InitBotLuck==0 && InitFishLuck==0 && BotCount==0 && !_isRedPoint_up && !RodCanUp && !RodCanUpLevel && !IsOpenMap && !IsOpenRod && !IsOpenPiercing && MapTipforUnlocked==0 && RodSelectedInPack==0;
|
||||||
|
internal bool DictionariesMatchForKVValidation(game.PlayerDataStorage.PlayerKVFishState s) =>
|
||||||
|
rodData.OrderBy(p=>p.Key).SequenceEqual(s.Rods.OrderBy(p=>p.Key)) && rodLevelData.OrderBy(p=>p.Key).SequenceEqual(s.RodLevels.OrderBy(p=>p.Key)) &&
|
||||||
|
fishSwimToMap.OrderBy(p=>p.Key).SequenceEqual(s.Swim.OrderBy(p=>p.Key)) && fishSwimToMapCount.OrderBy(p=>p.Key).SequenceEqual(s.SwimCount.OrderBy(p=>p.Key)) &&
|
||||||
|
mapProgress.OrderBy(p=>p.Key).SequenceEqual(s.Progress.OrderBy(p=>p.Key)) && _honorlevel.OrderBy(p=>p.Key).SequenceEqual(s.Honor.OrderBy(p=>p.Key));
|
||||||
|
#endif
|
||||||
|
|
||||||
public void InitData(Dictionary<string, string> userDatas)
|
public void InitData(Dictionary<string, string> userDatas)
|
||||||
{
|
{
|
||||||
string data_value;
|
string data_value;
|
||||||
@@ -386,7 +427,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
GContext.container.Resolve<PlayerData>().AddNewRod(id);
|
GContext.container.Resolve<PlayerData>().AddNewRod(id);
|
||||||
rodData.Add(id, 0);
|
rodData.Add(id, 0);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("RodData", JsonMapper.ToJson(rodData));
|
playerSaveStore.Write("RodData", JsonMapper.ToJson(rodData)).RequireAccepted();
|
||||||
//鱼竿红点数据修改
|
//鱼竿红点数据修改
|
||||||
RedPointManager.Instance.SetRedPointState(RedPointName.Home_Rod, true);
|
RedPointManager.Instance.SetRedPointState(RedPointName.Home_Rod, true);
|
||||||
}
|
}
|
||||||
@@ -487,7 +528,7 @@ namespace GameCore
|
|||||||
.AddContent("rod_chips_consume", 0);
|
.AddContent("rod_chips_consume", 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("RodLevelData", JsonMapper.ToJson(rodLevelData));
|
playerSaveStore.Write("RodLevelData", JsonMapper.ToJson(rodLevelData)).RequireAccepted();
|
||||||
|
|
||||||
GContext.container.Resolve<PlayerData>().SetPearl(GContext.container.Resolve<PlayerData>().pearl - count);
|
GContext.container.Resolve<PlayerData>().SetPearl(GContext.container.Resolve<PlayerData>().pearl - count);
|
||||||
}
|
}
|
||||||
@@ -546,7 +587,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
//鱼竿红点数据修改
|
//鱼竿红点数据修改
|
||||||
CheckRodRedPointUp();
|
CheckRodRedPointUp();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("RodData", JsonMapper.ToJson(rodData));
|
playerSaveStore.Write("RodData", JsonMapper.ToJson(rodData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetRodPiece(int id)
|
public int GetRodPiece(int id)
|
||||||
@@ -576,7 +617,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("RodData", JsonMapper.ToJson(rodData));
|
playerSaveStore.Write("RodData", JsonMapper.ToJson(rodData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GMSetStarAll(int lv)
|
public void GMSetStarAll(int lv)
|
||||||
@@ -602,7 +643,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("RodData", JsonMapper.ToJson(rodData));
|
playerSaveStore.Write("RodData", JsonMapper.ToJson(rodData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void GMAddAllFishMastery(bool all = false)
|
public void GMAddAllFishMastery(bool all = false)
|
||||||
@@ -1154,6 +1195,14 @@ namespace GameCore
|
|||||||
SetFishData(id, fishData[id]);
|
SetFishData(id, fishData[id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
internal void SaveCaughtFishForKVLoop(int fishId)
|
||||||
|
{
|
||||||
|
if(!fishData.TryGetValue(fishId,out var data)) throw game.PlayerDataStorage.PlayerKVGameplayLoop.Stop("Caught fish data is missing.");
|
||||||
|
game.PlayerDataStorage.PlayerKVGameplayLoop.CheckCaughtFishSave(fishId,data.TotalNum);
|
||||||
|
SetFishData(fishId,data);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
void SetFishData(int id, FishWeightData data)
|
void SetFishData(int id, FishWeightData data)
|
||||||
{
|
{
|
||||||
int mapID = _tables.TbFishData.GetOrDefault(id).AreaID;
|
int mapID = _tables.TbFishData.GetOrDefault(id).AreaID;
|
||||||
@@ -1173,7 +1222,7 @@ namespace GameCore
|
|||||||
void MapNewUpdateUserDataValue(int mapID, Dictionary<int, FishWeightData> keyValuePairs)
|
void MapNewUpdateUserDataValue(int mapID, Dictionary<int, FishWeightData> keyValuePairs)
|
||||||
{
|
{
|
||||||
Dictionary<int, string> mapData = keyValuePairs.ToDictionary(_ => _.Key, _ => _.Value.Serialize());
|
Dictionary<int, string> mapData = keyValuePairs.ToDictionary(_ => _.Key, _ => _.Value.Serialize());
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue($"Map_5_{mapID}", JsonMapper.ToJson(mapData));
|
playerSaveStore.Write($"Map_5_{mapID}", JsonMapper.ToJson(mapData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
public int GetFishLevelByMap(int mapId)
|
public int GetFishLevelByMap(int mapId)
|
||||||
{
|
{
|
||||||
@@ -1306,10 +1355,10 @@ namespace GameCore
|
|||||||
if (fishId != 0)
|
if (fishId != 0)
|
||||||
{
|
{
|
||||||
fishSwimToMapCount[id] = 0;
|
fishSwimToMapCount[id] = 0;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("FishSwimToMapCount", JsonMapper.ToJson(fishSwimToMapCount));
|
playerSaveStore.Write("FishSwimToMapCount", JsonMapper.ToJson(fishSwimToMapCount)).RequireAccepted();
|
||||||
}
|
}
|
||||||
fishSwimToMap[id] = fishId;
|
fishSwimToMap[id] = fishId;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("FishSwimToMap", JsonMapper.ToJson(fishSwimToMap));
|
playerSaveStore.Write("FishSwimToMap", JsonMapper.ToJson(fishSwimToMap)).RequireAccepted();
|
||||||
}
|
}
|
||||||
public void SetFishSwimToMapCount(int id, int count)
|
public void SetFishSwimToMapCount(int id, int count)
|
||||||
{
|
{
|
||||||
@@ -1320,7 +1369,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
SetFishSwimToMap(id, 0);
|
SetFishSwimToMap(id, 0);
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("FishSwimToMapCount", JsonMapper.ToJson(fishSwimToMapCount));
|
playerSaveStore.Write("FishSwimToMapCount", JsonMapper.ToJson(fishSwimToMapCount)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//===========================鱼图鉴===========================
|
//===========================鱼图鉴===========================
|
||||||
@@ -1390,7 +1439,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
|
|
||||||
GContext.container.Resolve<PlayerItemData>().AddItemByDropList(dorpList, null);
|
GContext.container.Resolve<PlayerItemData>().AddItemByDropList(dorpList, null);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("MapProgress", Newtonsoft.Json.JsonConvert.SerializeObject(mapProgress));
|
playerSaveStore.Write("MapProgress", Newtonsoft.Json.JsonConvert.SerializeObject(mapProgress)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public int GetAllPTSByMap(int mapID)
|
public int GetAllPTSByMap(int mapID)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using cfg;
|
using cfg;
|
||||||
using asap.core;
|
using asap.core;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using CodeStage.AntiCheat.ObscuredTypes;
|
using CodeStage.AntiCheat.ObscuredTypes;
|
||||||
using game;
|
using game;
|
||||||
@@ -73,6 +73,13 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public partial class PlayerShopData : IDisposable
|
public partial class PlayerShopData : IDisposable
|
||||||
{
|
{
|
||||||
|
game.PlayerDataStorage.IPlayerSaveStore boundSaveStore;
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore
|
||||||
|
{
|
||||||
|
get => boundSaveStore;
|
||||||
|
set { CouponData.BindSaveStore(value); boundSaveStore = value; }
|
||||||
|
}
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public cfg.Tables _tables { get; set; }
|
public cfg.Tables _tables { get; set; }
|
||||||
[Inject]
|
[Inject]
|
||||||
@@ -126,6 +133,44 @@ namespace GameCore
|
|||||||
Dictionary<int, int> advertCount = new Dictionary<int, int>();
|
Dictionary<int, int> advertCount = new Dictionary<int, int>();
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVShopState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors)
|
||||||
|
=> game.PlayerDataStorage.PlayerKVSaveSchema.DecodeShop(raw,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
shopPackDailyBuyCount=new Dictionary<string,int>(StringComparer.Ordinal); shopAllPackBuyCount=new Dictionary<int,int>();
|
||||||
|
shopGiftBuyCount=new Dictionary<int,int>(); buyData=new List<float>(); advertCount=new Dictionary<int,int>();
|
||||||
|
Voucher=0; ChainPackData=null; VIPAdPackData=null; TurntableAdData=null;
|
||||||
|
_diamondShopItemRecords=new Dictionary<int,ItemShopRecord>(); _diamondShopRefreshCount=0; _diamondShopRefreshTime=default;
|
||||||
|
CouponData.ResetForKVLoad();
|
||||||
|
}
|
||||||
|
static DailySignEvent KVDaily(game.PlayerDataStorage.PlayerKVDailyValue value) => value==null ? null :
|
||||||
|
new DailySignEvent { ID=value.Id,index=value.Index,lastID=value.LastId,time=value.Time };
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVShopState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
shopPackDailyBuyCount=state.Daily.ToDictionary(p=>p.Key,p=>p.Value,StringComparer.Ordinal);
|
||||||
|
shopAllPackBuyCount=state.All.ToDictionary(p=>p.Key,p=>p.Value); shopGiftBuyCount=state.Gift.ToDictionary(p=>p.Key,p=>p.Value);
|
||||||
|
advertCount=state.Advert.ToDictionary(p=>p.Key,p=>p.Value); buyData=new List<float>(state.Buy); Voucher=state.Voucher;
|
||||||
|
ChainPackData=KVDaily(state.Chain); TurntableAdData=KVDaily(state.Turntable);
|
||||||
|
VIPAdPackData=state.Vip==null ? null : new AdvertData { ID=state.Vip.Id,index=state.Vip.Index,day=state.Vip.Day,cdTime=state.Vip.Time,isOpen=state.Vip.Open };
|
||||||
|
_diamondShopItemRecords=state.Items.ToDictionary(p=>p.Key,p=>new ItemShopRecord(p.Value.Id,p.Value.Discount,p.Value.Bought));
|
||||||
|
_diamondShopRefreshCount=state.RefreshCount; _diamondShopRefreshTime=state.RefreshTime; CouponData.ReplaceFromKVDecoded(state.Coupon);
|
||||||
|
}
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
internal game.PlayerDataStorage.PlayerKVShopState SnapshotForKVValidation()
|
||||||
|
{
|
||||||
|
game.PlayerDataStorage.PlayerKVDailyValue Daily(DailySignEvent v) => v==null ? null : new game.PlayerDataStorage.PlayerKVDailyValue(v.ID,v.index,v.lastID,v.time);
|
||||||
|
return new game.PlayerDataStorage.PlayerKVShopState(shopPackDailyBuyCount,shopAllPackBuyCount,shopGiftBuyCount,advertCount,
|
||||||
|
_diamondShopItemRecords.ToDictionary(p=>p.Key,p=>new game.PlayerDataStorage.PlayerKVShopItemValue(p.Value.ItemID,p.Value.Discount,p.Value.hasBought)),
|
||||||
|
buyData,Voucher,_diamondShopRefreshCount,_diamondShopRefreshTime,Daily(ChainPackData),Daily(TurntableAdData),
|
||||||
|
VIPAdPackData==null ? null : new game.PlayerDataStorage.PlayerKVAdvertValue(VIPAdPackData.ID,VIPAdPackData.index,VIPAdPackData.day,VIPAdPackData.cdTime,VIPAdPackData.isOpen),
|
||||||
|
new game.PlayerDataStorage.PlayerKVCouponState(CouponData.ActivateTime,CouponData.EventId,CouponData.RedirectId,CouponData.IsBought));
|
||||||
|
}
|
||||||
|
internal void MutateCollectionsForKVValidation()
|
||||||
|
{ buyData.Clear(); advertCount.Clear(); _diamondShopItemRecords.Values.First().Discount=99; }
|
||||||
|
#endif
|
||||||
|
|
||||||
public void InitData(Dictionary<string, string> userDatas)
|
public void InitData(Dictionary<string, string> userDatas)
|
||||||
{
|
{
|
||||||
if (userDatas == null || userDatas.Count < 1)
|
if (userDatas == null || userDatas.Count < 1)
|
||||||
@@ -212,7 +257,7 @@ namespace GameCore
|
|||||||
public void AddVoucher(int value)
|
public void AddVoucher(int value)
|
||||||
{
|
{
|
||||||
Voucher = Voucher + value;
|
Voucher = Voucher + value;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("Voucher", Voucher.ToString());
|
SaveStore.Write("Voucher", Voucher.ToString()).RequireAccepted();
|
||||||
}
|
}
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
@@ -331,10 +376,10 @@ namespace GameCore
|
|||||||
if (Voucher >= iAPItemList.CostToken)
|
if (Voucher >= iAPItemList.CostToken)
|
||||||
{
|
{
|
||||||
Voucher = Voucher - iAPItemList.CostToken;
|
Voucher = Voucher - iAPItemList.CostToken;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("Voucher", Voucher.ToString());
|
SaveStore.Write("Voucher", Voucher.ToString()).RequireAccepted();
|
||||||
//二次弹窗
|
//二次弹窗
|
||||||
//回调
|
//回调
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{0}");
|
SaveStore.Write("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{0}").RequireAccepted();
|
||||||
BuySuccess(buyType, iAPItemList, itemDataGift, rewardShowType, true);
|
BuySuccess(buyType, iAPItemList, itemDataGift, rewardShowType, true);
|
||||||
OrderManager.OrderManager.OnOrderSuccess(buyType, iAPItemList, itemDataGift, rewardShowType, true);
|
OrderManager.OrderManager.OnOrderSuccess(buyType, iAPItemList, itemDataGift, rewardShowType, true);
|
||||||
if (!buyType.NoShow)
|
if (!buyType.NoShow)
|
||||||
@@ -391,7 +436,7 @@ namespace GameCore
|
|||||||
|
|
||||||
if (result.isSuccess)
|
if (result.isSuccess)
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{sku.price}");
|
SaveStore.Write("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{sku.price}").RequireAccepted();
|
||||||
BuySuccess(buyType, iAPItemList, itemDataGift, rewardShowType);
|
BuySuccess(buyType, iAPItemList, itemDataGift, rewardShowType);
|
||||||
OrderManager.OrderManager.OnOrderSuccess(buyType, iAPItemList, itemDataGift, rewardShowType);
|
OrderManager.OrderManager.OnOrderSuccess(buyType, iAPItemList, itemDataGift, rewardShowType);
|
||||||
if (!buyType.NoShow)
|
if (!buyType.NoShow)
|
||||||
@@ -566,7 +611,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{data.ProdPrice}");
|
SaveStore.Write("LastPaymentTime", $"{ZZTimeHelper.UtcNow()}__{data.ProdPrice}").RequireAccepted();
|
||||||
BuySuccess(data.BuyType, iAPItemList, itemDataGift, data.ShowType);
|
BuySuccess(data.BuyType, iAPItemList, itemDataGift, data.ShowType);
|
||||||
if (data.BuyType.extraPurcheData != null)
|
if (data.BuyType.extraPurcheData != null)
|
||||||
{
|
{
|
||||||
@@ -590,7 +635,7 @@ namespace GameCore
|
|||||||
buyData[0] += iAPItemList.PaymentAmount;
|
buyData[0] += iAPItemList.PaymentAmount;
|
||||||
}
|
}
|
||||||
buyData.Add(iAPItemList.ID);
|
buyData.Add(iAPItemList.ID);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("BuyData", JsonMapper.ToJson(buyData));
|
SaveStore.Write("BuyData", JsonMapper.ToJson(buyData)).RequireAccepted();
|
||||||
#if AGG
|
#if AGG
|
||||||
GEvent.SetUserProp("Total_consumption", buyData[0]);
|
GEvent.SetUserProp("Total_consumption", buyData[0]);
|
||||||
#endif
|
#endif
|
||||||
@@ -661,7 +706,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
TurntableAdData = null;
|
TurntableAdData = null;
|
||||||
shopPackDailyBuyCount["0"] = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
shopPackDailyBuyCount["0"] = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("ShopPackBuyCount", JsonMapper.ToJson(shopPackDailyBuyCount));
|
SaveStore.Write("ShopPackBuyCount", JsonMapper.ToJson(shopPackDailyBuyCount)).RequireAccepted();
|
||||||
}
|
}
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
@@ -691,7 +736,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
shopPackDailyBuyCount["0"] = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
shopPackDailyBuyCount["0"] = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("ShopPackBuyCount", JsonMapper.ToJson(shopPackDailyBuyCount));
|
SaveStore.Write("ShopPackBuyCount", JsonMapper.ToJson(shopPackDailyBuyCount)).RequireAccepted();
|
||||||
}
|
}
|
||||||
public int GetShopPackBuyCount(int id)
|
public int GetShopPackBuyCount(int id)
|
||||||
{
|
{
|
||||||
@@ -748,7 +793,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
shopGiftBuyCount.Add(id, count);
|
shopGiftBuyCount.Add(id, count);
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("ShopGiftBuyCount", JsonMapper.ToJson(shopGiftBuyCount));
|
SaveStore.Write("ShopGiftBuyCount", JsonMapper.ToJson(shopGiftBuyCount)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -817,7 +862,7 @@ namespace GameCore
|
|||||||
index = 0,
|
index = 0,
|
||||||
time = time.ToString()
|
time = time.ToString()
|
||||||
};
|
};
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("ChainPackDataNew", JsonMapper.ToJson(ChainPackData));
|
SaveStore.Write("ChainPackDataNew", JsonMapper.ToJson(ChainPackData)).RequireAccepted();
|
||||||
chainPackM = null;
|
chainPackM = null;
|
||||||
}
|
}
|
||||||
if (chainPackM == null)
|
if (chainPackM == null)
|
||||||
@@ -859,7 +904,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
AddAllPackCount(chainPackM.ID, 1);
|
AddAllPackCount(chainPackM.ID, 1);
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("ChainPackDataNew", JsonMapper.ToJson(ChainPackData));
|
SaveStore.Write("ChainPackDataNew", JsonMapper.ToJson(ChainPackData)).RequireAccepted();
|
||||||
//链式礼包 特殊处理
|
//链式礼包 特殊处理
|
||||||
GContext.Publish(new TargetEvent(chainPackM.ID, 3, 10));
|
GContext.Publish(new TargetEvent(chainPackM.ID, 3, 10));
|
||||||
}
|
}
|
||||||
@@ -889,7 +934,7 @@ namespace GameCore
|
|||||||
shopAllPackBuyCount.Add(id, count);
|
shopAllPackBuyCount.Add(id, count);
|
||||||
}
|
}
|
||||||
GContext.Publish(new ConditionTypeEvent(ConditionType.BuyPack, count));
|
GContext.Publish(new ConditionTypeEvent(ConditionType.BuyPack, count));
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("ShopAllPackBuyCount", JsonMapper.ToJson(shopAllPackBuyCount));
|
SaveStore.Write("ShopAllPackBuyCount", JsonMapper.ToJson(shopAllPackBuyCount)).RequireAccepted();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
//========================================礼包========================================
|
//========================================礼包========================================
|
||||||
@@ -927,7 +972,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("AdvertAllCount", JsonMapper.ToJson(advertCount));
|
SaveStore.Write("AdvertAllCount", JsonMapper.ToJson(advertCount)).RequireAccepted();
|
||||||
GContext.Publish(new ResAddEvent(1006));
|
GContext.Publish(new ResAddEvent(1006));
|
||||||
}
|
}
|
||||||
public int GetAdticketCount()
|
public int GetAdticketCount()
|
||||||
@@ -953,7 +998,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
advertCount.Add(id, 1);
|
advertCount.Add(id, 1);
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("AdvertAllCount", JsonMapper.ToJson(advertCount));
|
SaveStore.Write("AdvertAllCount", JsonMapper.ToJson(advertCount)).RequireAccepted();
|
||||||
return advertCount[id];
|
return advertCount[id];
|
||||||
}
|
}
|
||||||
public void ClearAdvertCount()
|
public void ClearAdvertCount()
|
||||||
@@ -968,7 +1013,7 @@ namespace GameCore
|
|||||||
advertCount[-1] = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
advertCount[-1] = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
||||||
advertCount[0] = allCount;
|
advertCount[0] = allCount;
|
||||||
advertCount[-2] = ticket;
|
advertCount[-2] = ticket;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("AdvertAllCount", JsonMapper.ToJson(advertCount));
|
SaveStore.Write("AdvertAllCount", JsonMapper.ToJson(advertCount)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1012,7 +1057,7 @@ namespace GameCore
|
|||||||
AdConfig adConfig1 = adConfigs[VIPAdPackData.index - 1];
|
AdConfig adConfig1 = adConfigs[VIPAdPackData.index - 1];
|
||||||
VIPAdPackData.cdTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(adConfig1.Interval).ToString();
|
VIPAdPackData.cdTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(adConfig1.Interval).ToString();
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("VIPAdPackData", JsonMapper.ToJson(VIPAdPackData));
|
SaveStore.Write("VIPAdPackData", JsonMapper.ToJson(VIPAdPackData)).RequireAccepted();
|
||||||
//GContext.Publish(new VIPAdPackDataEvent());
|
//GContext.Publish(new VIPAdPackDataEvent());
|
||||||
}
|
}
|
||||||
public DateTime GetVIPAdPackTime()
|
public DateTime GetVIPAdPackTime()
|
||||||
@@ -1044,7 +1089,7 @@ namespace GameCore
|
|||||||
VIPAdPackData = new AdvertData();
|
VIPAdPackData = new AdvertData();
|
||||||
VIPAdPackData.day = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
VIPAdPackData.day = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
||||||
VIPAdPackData.isOpen = true;
|
VIPAdPackData.isOpen = true;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("VIPAdPackData", JsonMapper.ToJson(VIPAdPackData));
|
SaveStore.Write("VIPAdPackData", JsonMapper.ToJson(VIPAdPackData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
public bool IsOpenAdPack()
|
public bool IsOpenAdPack()
|
||||||
{
|
{
|
||||||
@@ -1101,7 +1146,7 @@ namespace GameCore
|
|||||||
// {
|
// {
|
||||||
// isOverForToday = true;
|
// isOverForToday = true;
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TurntableAdData", Newtonsoft.Json.JsonConvert.SerializeObject(TurntableAdData));
|
SaveStore.Write("TurntableAdData", Newtonsoft.Json.JsonConvert.SerializeObject(TurntableAdData)).RequireAccepted();
|
||||||
// GContext.Publish(new VIPAdPackDataEvent());
|
// GContext.Publish(new VIPAdPackDataEvent());
|
||||||
}
|
}
|
||||||
public bool IsTurntableAdMaxOut()
|
public bool IsTurntableAdMaxOut()
|
||||||
@@ -1195,7 +1240,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
_diamondShopItemRecords[itemShopId].hasBought = 1;
|
_diamondShopItemRecords[itemShopId].hasBought = 1;
|
||||||
SetItemShopRedPoint();
|
SetItemShopRedPoint();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("DiamondShopItemRecords", JsonConvert.SerializeObject(_diamondShopItemRecords));
|
SaveStore.Write("DiamondShopItemRecords", JsonConvert.SerializeObject(_diamondShopItemRecords)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1210,7 +1255,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
RefreshItemShop();
|
RefreshItemShop();
|
||||||
_diamondShopRefreshCount++;
|
_diamondShopRefreshCount++;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("DiamondShopRefreshCount", _diamondShopRefreshCount.ToString());
|
SaveStore.Write("DiamondShopRefreshCount", _diamondShopRefreshCount.ToString()).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1250,8 +1295,8 @@ namespace GameCore
|
|||||||
_diamondShopRefreshTime = new DateTime(now.Year, now.Month, now.Day).AddDays(1) + timeSpan;
|
_diamondShopRefreshTime = new DateTime(now.Year, now.Month, now.Day).AddDays(1) + timeSpan;
|
||||||
|
|
||||||
_diamondShopRefreshCount = 0;
|
_diamondShopRefreshCount = 0;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("DiamondShopRefreshCount", _diamondShopRefreshCount.ToString());
|
SaveStore.Write("DiamondShopRefreshCount", _diamondShopRefreshCount.ToString()).RequireAccepted();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("DiamondShopRefreshTime", _diamondShopRefreshTime.ToString());
|
SaveStore.Write("DiamondShopRefreshTime", _diamondShopRefreshTime.ToString()).RequireAccepted();
|
||||||
RefreshItemShop();
|
RefreshItemShop();
|
||||||
}
|
}
|
||||||
private void RefreshItemShop()
|
private void RefreshItemShop()
|
||||||
@@ -1326,7 +1371,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("DiamondShopItemRecords", JsonConvert.SerializeObject(_diamondShopItemRecords));
|
SaveStore.Write("DiamondShopItemRecords", JsonConvert.SerializeObject(_diamondShopItemRecords)).RequireAccepted();
|
||||||
SetItemShopRedPoint();
|
SetItemShopRedPoint();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
using LitJson;
|
using LitJson;
|
||||||
@@ -29,6 +29,8 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public class SigninData
|
public class SigninData
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
|
||||||
private cfg.Tables _tables;
|
private cfg.Tables _tables;
|
||||||
public SigninData(cfg.Tables tables)
|
public SigninData(cfg.Tables tables)
|
||||||
{
|
{
|
||||||
@@ -37,6 +39,19 @@ namespace GameCore
|
|||||||
|
|
||||||
MonthlySignEvent _monthlySignEvent = null;
|
MonthlySignEvent _monthlySignEvent = null;
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVMonthlySignState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) => game.PlayerDataStorage.PlayerKVSaveSchema.DecodeMonthlySign(raw,errors);
|
||||||
|
internal void ResetForKVLoad() { _monthlySignEvent = null; }
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVMonthlySignState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new ArgumentNullException(nameof(state));
|
||||||
|
_monthlySignEvent = !state.IsPresent ? null : new MonthlySignEvent
|
||||||
|
{
|
||||||
|
index = state.Index,
|
||||||
|
dailySignEvent = new DailySignEvent { ID=state.DailyId, index=state.DailyIndex, lastID=state.LastId, time=state.Time }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public DailySignEvent dailySignEvent
|
public DailySignEvent dailySignEvent
|
||||||
{
|
{
|
||||||
get => _monthlySignEvent == null ? null : _monthlySignEvent.dailySignEvent;
|
get => _monthlySignEvent == null ? null : _monthlySignEvent.dailySignEvent;
|
||||||
@@ -89,7 +104,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
if (isSave)
|
if (isSave)
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("MonthlySignEvent", JsonMapper.ToJson(_monthlySignEvent));
|
SaveStore.Write("MonthlySignEvent", JsonMapper.ToJson(_monthlySignEvent)).RequireAccepted();
|
||||||
}
|
}
|
||||||
bool isReward = CanDailySign();
|
bool isReward = CanDailySign();
|
||||||
if (isReward)
|
if (isReward)
|
||||||
@@ -141,7 +156,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
//GContext.Publish(new ShowData());
|
//GContext.Publish(new ShowData());
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("MonthlySignEvent", JsonMapper.ToJson(_monthlySignEvent));
|
SaveStore.Write("MonthlySignEvent", JsonMapper.ToJson(_monthlySignEvent)).RequireAccepted();
|
||||||
GContext.Publish(new OnSignEvent() { itemDataList = monthlySignReward });
|
GContext.Publish(new OnSignEvent() { itemDataList = monthlySignReward });
|
||||||
}
|
}
|
||||||
return isSign;
|
return isSign;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public class SmallGameData
|
public class SmallGameData
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
private cfg.Tables _tables;
|
private cfg.Tables _tables;
|
||||||
IUserService userService;
|
IUserService userService;
|
||||||
ICustomServerMgr customServerMgr;
|
ICustomServerMgr customServerMgr;
|
||||||
@@ -47,6 +48,26 @@ namespace GameCore
|
|||||||
public int FishHuntGameCount => _fishHuntGameCount;
|
public int FishHuntGameCount => _fishHuntGameCount;
|
||||||
public int BombGameCount => _bombGameCount;
|
public int BombGameCount => _bombGameCount;
|
||||||
|
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
_heistGameCount=_bombGameCount=_fishHuntGameCount=0;
|
||||||
|
opponentItemDatas=new List<OpponentItemData>(); opponentFriendItemDatas=new List<OpponentItemData>();
|
||||||
|
opponentNotFriendItemDatas=new List<OpponentItemData>(); opponentFriend=new List<OpponentItemData>();
|
||||||
|
opponentFriendDic=new Dictionary<string,OpponentItemData>(); opponentEnemy=new Dictionary<EnemyType,List<OpponentItemData>>();
|
||||||
|
opponentItemDatasPre=new List<OpponentItemData>(); opponentFriendItemDatasPre=new List<OpponentItemData>();
|
||||||
|
opponentNotFriendItemDatasPre=new List<OpponentItemData>(); powerData=new Dictionary<string,float>();
|
||||||
|
opponentData=null; nextOpponent=null; curEnemyType=EnemyType.Aquarium; RobotMapId=nextRobotMapId=0;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVCoreState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
_heistGameCount=state.Integer(16); _bombGameCount=state.Integer(17); _fishHuntGameCount=state.Integer(18);
|
||||||
|
}
|
||||||
|
internal bool IsOpponentEmptyForKVValidation => opponentItemDatas.Count==0 && opponentFriendItemDatas.Count==0 &&
|
||||||
|
opponentNotFriendItemDatas.Count==0 && opponentFriend.Count==0 && opponentFriendDic.Count==0 && opponentEnemy.Count==0 &&
|
||||||
|
opponentItemDatasPre.Count==0 && opponentFriendItemDatasPre.Count==0 && opponentNotFriendItemDatasPre.Count==0 &&
|
||||||
|
powerData.Count==0 && opponentData==null && nextOpponent==null && RobotMapId==0 && nextRobotMapId==0;
|
||||||
|
|
||||||
//public UnityEngine.Vector3 image_extra_pos { set; get; }
|
//public UnityEngine.Vector3 image_extra_pos { set; get; }
|
||||||
|
|
||||||
public void SetHeistGameCount(int value)
|
public void SetHeistGameCount(int value)
|
||||||
@@ -56,7 +77,7 @@ namespace GameCore
|
|||||||
public void SaveHeistGameCount()
|
public void SaveHeistGameCount()
|
||||||
{
|
{
|
||||||
_heistGameCount++;
|
_heistGameCount++;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("HeistGameCount", _heistGameCount.ToString());
|
playerSaveStore.Write("HeistGameCount", _heistGameCount.ToString()).RequireAccepted();
|
||||||
}
|
}
|
||||||
public void SetBombGameCount(int value)
|
public void SetBombGameCount(int value)
|
||||||
{
|
{
|
||||||
@@ -65,7 +86,7 @@ namespace GameCore
|
|||||||
public void SaveBombGameCount()
|
public void SaveBombGameCount()
|
||||||
{
|
{
|
||||||
_bombGameCount++;
|
_bombGameCount++;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("BombGameCount", _bombGameCount.ToString());
|
playerSaveStore.Write("BombGameCount", _bombGameCount.ToString()).RequireAccepted();
|
||||||
}
|
}
|
||||||
public void SetFishHuntGameCount(int value)
|
public void SetFishHuntGameCount(int value)
|
||||||
{
|
{
|
||||||
@@ -74,7 +95,7 @@ namespace GameCore
|
|||||||
public void SaveFishHuntGameCount()
|
public void SaveFishHuntGameCount()
|
||||||
{
|
{
|
||||||
_fishHuntGameCount++;
|
_fishHuntGameCount++;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("FishHuntGameCount", _fishHuntGameCount.ToString());
|
playerSaveStore.Write("FishHuntGameCount", _fishHuntGameCount.ToString()).RequireAccepted();
|
||||||
}
|
}
|
||||||
#region 小游戏仇人
|
#region 小游戏仇人
|
||||||
public List<OpponentItemData> opponentItemDatas = new List<OpponentItemData>();
|
public List<OpponentItemData> opponentItemDatas = new List<OpponentItemData>();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
using LitJson;
|
using LitJson;
|
||||||
@@ -38,6 +38,8 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public class TriggerPackData
|
public class TriggerPackData
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
|
||||||
Tables _tables;
|
Tables _tables;
|
||||||
PlayerShopData playerShopData;
|
PlayerShopData playerShopData;
|
||||||
public TriggerPackData(Tables tables)
|
public TriggerPackData(Tables tables)
|
||||||
@@ -52,6 +54,29 @@ namespace GameCore
|
|||||||
|
|
||||||
//VIP 等级叠加
|
//VIP 等级叠加
|
||||||
public Dictionary<string, GiftVIPDData> giftVIPDData = new Dictionary<string, GiftVIPDData>();
|
public Dictionary<string, GiftVIPDData> giftVIPDData = new Dictionary<string, GiftVIPDData>();
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVTriggerState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) => game.PlayerDataStorage.PlayerKVSaveSchema.DecodeTriggers(raw,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
triggerPackList=new List<TriggerPackBuyData>();
|
||||||
|
giftVIPDData=new Dictionary<string,GiftVIPDData>(StringComparer.Ordinal);
|
||||||
|
fixedTimeShopDic=new Dictionary<int,FixedTimeEvent>();
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVTriggerState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
var packs=state.Packs.Select(p=>new TriggerPackBuyData {
|
||||||
|
ID=p.ID,index=p.index,lastID=p.lastID,vipLevel=p.vipLevel,mapID=p.mapID,time=p.time }).ToList();
|
||||||
|
var gifts=state.Gifts.ToDictionary(p=>p.Key,p=>new GiftVIPDData {
|
||||||
|
oldVipLevel=p.Value.oldVipLevel,curVipLevel=p.Value.curVipLevel,timer=p.Value.timer },StringComparer.Ordinal);
|
||||||
|
var fixedValues=state.Fixed.ToDictionary(p=>p.Key,p=>new FixedTimeEvent { id=p.Value.id,endTime=p.Value.endTime });
|
||||||
|
triggerPackList=packs; giftVIPDData=gifts; fixedTimeShopDic=fixedValues;
|
||||||
|
}
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
internal FixedTimeEvent FixedForKVValidation(int key) => fixedTimeShopDic.TryGetValue(key,out var value) ? value : null;
|
||||||
|
internal bool IsEmptyForKVValidation => triggerPackList.Count==0 && giftVIPDData.Count==0 && fixedTimeShopDic.Count==0;
|
||||||
|
#endif
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
playerShopData = GContext.container.Resolve<PlayerShopData>();
|
playerShopData = GContext.container.Resolve<PlayerShopData>();
|
||||||
@@ -197,7 +222,7 @@ namespace GameCore
|
|||||||
id = t.ID,
|
id = t.ID,
|
||||||
endTime = dateTime.AddSeconds(fixedTime.EndTime).ToString(),
|
endTime = dateTime.AddSeconds(fixedTime.EndTime).ToString(),
|
||||||
};
|
};
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic));
|
SaveStore.Write("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)).RequireAccepted();
|
||||||
|
|
||||||
TriggerPackBuyData _newSignEvent = null;
|
TriggerPackBuyData _newSignEvent = null;
|
||||||
for (int i = 0; i < triggerPackList.Count; i++)
|
for (int i = 0; i < triggerPackList.Count; i++)
|
||||||
@@ -228,7 +253,7 @@ namespace GameCore
|
|||||||
_newSignEvent.vipLevel = GetVIPLevel(t.PackType);
|
_newSignEvent.vipLevel = GetVIPLevel(t.PackType);
|
||||||
}
|
}
|
||||||
GContext.container.Resolve<IFaceUIService>().AddGiftFaceUIOnLogin(_newSignEvent.ID, UITypes.AdsPackPanel, _newSignEvent.lastID);
|
GContext.container.Resolve<IFaceUIService>().AddGiftFaceUIOnLogin(_newSignEvent.ID, UITypes.AdsPackPanel, _newSignEvent.lastID);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TriggerPackDataList", JsonMapper.ToJson(triggerPackList));
|
SaveStore.Write("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,7 +289,7 @@ namespace GameCore
|
|||||||
endTime = time,
|
endTime = time,
|
||||||
};
|
};
|
||||||
fixedTimeShopDic[t.ID] = fixedTimeEvent;
|
fixedTimeShopDic[t.ID] = fixedTimeEvent;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic));
|
SaveStore.Write("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)).RequireAccepted();
|
||||||
}
|
}
|
||||||
else if (t.TimeDefinition is LimitedTime)
|
else if (t.TimeDefinition is LimitedTime)
|
||||||
{
|
{
|
||||||
@@ -283,7 +308,7 @@ namespace GameCore
|
|||||||
};
|
};
|
||||||
triggerPackList.Insert(0, _newSignEvent);
|
triggerPackList.Insert(0, _newSignEvent);
|
||||||
playerShopData.AddShopPackDailyBuyCount(t.PackType, 1, false);
|
playerShopData.AddShopPackDailyBuyCount(t.PackType, 1, false);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TriggerPackDataList", JsonMapper.ToJson(triggerPackList));
|
SaveStore.Write("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -314,7 +339,7 @@ namespace GameCore
|
|||||||
endTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(fixedTime.StartTime).ToString(),
|
endTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(fixedTime.StartTime).ToString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic));
|
SaveStore.Write("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)).RequireAccepted();
|
||||||
}
|
}
|
||||||
if (FixedTimeEventExpired(t.ID))
|
if (FixedTimeEventExpired(t.ID))
|
||||||
{
|
{
|
||||||
@@ -347,7 +372,7 @@ namespace GameCore
|
|||||||
endTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(fixedTime.StartTime).ToString(),
|
endTime = ZZTimeHelper.UtcNow().UtcNowOffset().AddSeconds(fixedTime.StartTime).ToString(),
|
||||||
};
|
};
|
||||||
|
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic));
|
SaveStore.Write("FixedTimeShopDic", JsonMapper.ToJson(fixedTimeShopDic)).RequireAccepted();
|
||||||
}
|
}
|
||||||
if (FixedTimeEventExpired(t.ID))
|
if (FixedTimeEventExpired(t.ID))
|
||||||
{
|
{
|
||||||
@@ -449,7 +474,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
if (isUpdate)
|
if (isUpdate)
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("GiftVIPDData", JsonMapper.ToJson(giftVIPDData));
|
SaveStore.Write("GiftVIPDData", JsonMapper.ToJson(giftVIPDData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -493,7 +518,7 @@ namespace GameCore
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
giftVIPDData[PackType] = giftVIPD;
|
giftVIPDData[PackType] = giftVIPD;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("GiftVIPDData", JsonMapper.ToJson(giftVIPDData));
|
SaveStore.Write("GiftVIPDData", JsonMapper.ToJson(giftVIPDData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#region 触发礼包
|
#region 触发礼包
|
||||||
@@ -550,7 +575,7 @@ namespace GameCore
|
|||||||
};
|
};
|
||||||
triggerPackList.Insert(0, _newSignEvent);
|
triggerPackList.Insert(0, _newSignEvent);
|
||||||
playerShopData.AddShopPackDailyBuyCount(t.PackType, 1, false);
|
playerShopData.AddShopPackDailyBuyCount(t.PackType, 1, false);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TriggerPackDataList", JsonMapper.ToJson(triggerPackList));
|
SaveStore.Write("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void AddTriggerPackCount(int id)
|
public void AddTriggerPackCount(int id)
|
||||||
@@ -563,7 +588,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
triggerPackList.Remove(triggerPackList[i]);
|
triggerPackList.Remove(triggerPackList[i]);
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TriggerPackDataList", JsonMapper.ToJson(triggerPackList));
|
SaveStore.Write("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)).RequireAccepted();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -618,7 +643,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
triggerPackList.Remove(dailySignEvent);
|
triggerPackList.Remove(dailySignEvent);
|
||||||
GContext.Publish(new TriggerPackEvent());
|
GContext.Publish(new TriggerPackEvent());
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("TriggerPackDataList", JsonMapper.ToJson(triggerPackList));
|
SaveStore.Write("TriggerPackDataList", JsonMapper.ToJson(triggerPackList)).RequireAccepted();
|
||||||
}
|
}
|
||||||
return endTime - curTime;
|
return endTime - curTime;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using GameCore;
|
|||||||
using cfg;
|
using cfg;
|
||||||
public class EventPackData
|
public class EventPackData
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
private Tables _tables = GContext.container.Resolve<Tables>();
|
private Tables _tables = GContext.container.Resolve<Tables>();
|
||||||
private struct Data
|
private struct Data
|
||||||
{
|
{
|
||||||
@@ -19,6 +20,19 @@ public class EventPackData
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Data _data;
|
private Data _data;
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVEventPackState DecodeForKVLoad(System.Collections.Generic.IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodeEventPack(raw,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad() { _data=default(Data); }
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVEventPackState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new System.ArgumentNullException(nameof(state));
|
||||||
|
_data=new Data { currentEventID=state.EventId,purchaseCount=state.PurchaseCount,
|
||||||
|
VIPLvlWhenEventActivate=state.VipLevel,redirectID=state.RedirectId };
|
||||||
|
}
|
||||||
|
internal game.PlayerDataStorage.PlayerKVEventPackState SnapshotForKVValidation() =>
|
||||||
|
new game.PlayerDataStorage.PlayerKVEventPackState(_data.currentEventID,_data.purchaseCount,_data.VIPLvlWhenEventActivate,_data.redirectID);
|
||||||
public int CurrentEventID { get { return _data.currentEventID; } }
|
public int CurrentEventID { get { return _data.currentEventID; } }
|
||||||
public int PurchaseCount { get { return _data.purchaseCount; } }
|
public int PurchaseCount { get { return _data.purchaseCount; } }
|
||||||
public int VIPLvlWhenEventActivated { get { return _data.VIPLvlWhenEventActivate; } }
|
public int VIPLvlWhenEventActivated { get { return _data.VIPLvlWhenEventActivate; } }
|
||||||
@@ -87,8 +101,8 @@ public class EventPackData
|
|||||||
}
|
}
|
||||||
public void SaveEventPackData()
|
public void SaveEventPackData()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("EventPackData",
|
playerSaveStore.Write("EventPackData",
|
||||||
Newtonsoft.Json.JsonConvert.SerializeObject(_data));
|
Newtonsoft.Json.JsonConvert.SerializeObject(_data)).RequireAccepted();
|
||||||
}
|
}
|
||||||
private void TriggerEventPack()
|
private void TriggerEventPack()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
@@ -100,8 +100,55 @@ namespace DataCenter
|
|||||||
// EventPartnerGather 管理器
|
// EventPartnerGather 管理器
|
||||||
public class EventPartnerGatherManager : IAutoMatchManagerContext
|
public class EventPartnerGatherManager : IAutoMatchManagerContext
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
|
||||||
private const bool EnableTraceLogs = false;
|
private const bool EnableTraceLogs = false;
|
||||||
public const string SaveKey = "EventPartnerGatherData";
|
public const string SaveKey = "EventPartnerGatherData";
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVPartnerState DecodeForKVLoad(
|
||||||
|
IReadOnlyDictionary<string,string> raw,game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) => game.PlayerDataStorage.PlayerKVSaveSchema.DecodePartner(raw,snapshot,errors);
|
||||||
|
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
// Only a fresh controlled container is admitted. Never detach active gameplay work.
|
||||||
|
if(_isInit || _act!=null || _disposables!=null || _autoMatchStatusInFlight!=null || PartnerInfoManager.HasSubscriptionsForKVLoad)
|
||||||
|
throw new InvalidOperationException("Active partner module cannot enter KV load.");
|
||||||
|
var partner=new PartnerInfoManager();
|
||||||
|
var robot=new EventPartnerGatherRobotInvitationSystem();
|
||||||
|
GatherData=null; _isEventDataChanged=false; CurrentBuildPartner=null;
|
||||||
|
PartnerInfoManager=partner; RobotInvitationSystem=robot;
|
||||||
|
_fishingEvent=null; EventPartnerMineMainData=null; EventPartnerMineSpinPointList=null; EventPartnerMineInitData=null;
|
||||||
|
_nodeCumulativeSteps.Clear(); _nodeSteps.Clear(); _stageDropList.Clear(); StartTime=default; EndTime=default;
|
||||||
|
_isInit=false; _spinId=-1; _userGm=false; BonusPercent=0; BonusExpireDuration=0;
|
||||||
|
_dateTimeForGetEvent=default; startTime=0; delta=0; _lastAutoMatchStatusUtc=default; _cachedAutoMatchStatus=null;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVPartnerState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
if(!state.Present) { GatherData=null; return; }
|
||||||
|
GatherData=new EventPartnerGatherData
|
||||||
|
{
|
||||||
|
FirstOpen=state.FirstOpen,EventId=state.EventId,StartTime=state.StartTime,EndTime=state.EndTime,
|
||||||
|
CurrentPoints=state.CurrentPoints,CurrentMiningProgress=state.CurrentMiningProgress,Token=state.Token,
|
||||||
|
InvitedCount=state.InvitedCount,TicketCount=state.TicketCount,
|
||||||
|
CompletedNodesList=state.CompletedNodesList.Select(n=>new List<int>(n)).ToList(),
|
||||||
|
BuilderPartnerScore=new List<(int,int)>(state.BuilderPartnerScore),PartnerBonus=(state.BonusPercent,state.BonusExpireUtc),
|
||||||
|
FreeSpinNum=state.FreeSpinNum,Bots=state.Bots.ToDictionary(p=>p.Key,p=>new EventBuildBotInfo
|
||||||
|
{ Id=p.Value.Id,ScorePlayer=p.Value.ScorePlayer,ScoreBot=p.Value.ScoreBot,Grade=p.Value.Grade,
|
||||||
|
TargetScore=p.Value.TargetScore,WakeStartTime=p.Value.WakeStartTime,WakingSeconds=p.Value.WakingSeconds }),
|
||||||
|
IsRecvFinalReward=state.IsRecvFinalReward,UIFinishedPartners=new List<bool>(state.UIFinishedPartners),
|
||||||
|
IsFinished=state.IsFinished,SpinState=(ESpinState)state.SpinState,InflationRate=state.InflationRate,
|
||||||
|
IsEnableAutoMatch=state.IsEnableAutoMatch,LastAutoMatchTime=state.LastAutoMatchTime
|
||||||
|
};
|
||||||
|
}
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
internal bool RuntimeEmptyForKVValidation => !_isInit && !_isEventDataChanged && _act==null && _disposables==null &&
|
||||||
|
_autoMatchStatusInFlight==null && _cachedAutoMatchStatus==null && _fishingEvent==null && CurrentBuildPartner==null &&
|
||||||
|
EventPartnerMineMainData==null && EventPartnerMineSpinPointList==null && EventPartnerMineInitData==null &&
|
||||||
|
_nodeCumulativeSteps.Count==0 && _nodeSteps.Count==0 && _stageDropList.Count==0 && StartTime==default && EndTime==default &&
|
||||||
|
_spinId==-1 && !_userGm && BonusPercent==0 && BonusExpireDuration==0 && _dateTimeForGetEvent==default &&
|
||||||
|
startTime==0 && delta==0 && _lastAutoMatchStatusUtc==default && !PartnerInfoManager.HasSubscriptionsForKVLoad;
|
||||||
|
#endif
|
||||||
[Inject] public Tables _tables { get; set; }
|
[Inject] public Tables _tables { get; set; }
|
||||||
|
|
||||||
[Inject] public EventPartnerService EventPartnerService { get; set; }
|
[Inject] public EventPartnerService EventPartnerService { get; set; }
|
||||||
@@ -819,7 +866,7 @@ namespace DataCenter
|
|||||||
Trace($"SaveData eventId={EventId}");
|
Trace($"SaveData eventId={EventId}");
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, JsonConvert.SerializeObject(GatherData));
|
SaveStore.Write(SaveKey, JsonConvert.SerializeObject(GatherData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void LoadData(string dataValue)
|
public void LoadData(string dataValue)
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ namespace game
|
|||||||
{
|
{
|
||||||
public class EventPinballDataManager
|
public class EventPinballDataManager
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private bool m_IsCheckCondition = true;
|
private bool m_IsCheckCondition = true;
|
||||||
@@ -375,7 +376,7 @@ namespace game
|
|||||||
public void SyncData()
|
public void SyncData()
|
||||||
{
|
{
|
||||||
if (!m_IsSyncData) return;
|
if (!m_IsSyncData) return;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(EventPinballConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_PinballData));
|
playerSaveStore.Write(EventPinballConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_PinballData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
@@ -449,6 +450,38 @@ namespace game
|
|||||||
|
|
||||||
#region 数据相关
|
#region 数据相关
|
||||||
private EventPinballData m_PinballData;
|
private EventPinballData m_PinballData;
|
||||||
|
internal bool IsInactiveForKVValidation => m_Tables==null && m_TbEventPinballMain==null && m_TbEventPinballPoint==null &&
|
||||||
|
m_TbEventPinballReward==null && m_UIPanel==null && m_InfoPanel==null && m_RewardList.Count==0 &&
|
||||||
|
m_PointWeightList.Count==0 && !m_IsSimulatorMode && !m_IsMultipleMax && m_CumulativeResponseNumber==0 &&
|
||||||
|
m_AccumulatedTriggerCount==0 && m_TemporaryScore==0 && m_TemporaryConsumedToken==0 && m_MagnificationListIndex==0 && m_BonusResponseNumber==10;
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVPinballState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodePinball(raw,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
m_PinballData=null; m_BonusResponseNumber=10; m_CumulativeResponseNumber=m_AccumulatedTriggerCount=m_TemporaryScore=m_TemporaryConsumedToken=m_MagnificationListIndex=0;
|
||||||
|
m_IsMultipleMax=false; m_IsSimulatorMode=false; m_RewardList=new List<float>(); m_PointWeightList=new List<float>(); m_UIPanel=m_InfoPanel=null;
|
||||||
|
m_Tables=null; m_TbEventPinballMain=null; m_TbEventPinballPoint=null; m_TbEventPinballReward=null;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVPinballState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
m_PinballData=!state.IsPresent ? null : new EventPinballData
|
||||||
|
{
|
||||||
|
EventID=state.EventID,
|
||||||
|
PinballMainID=state.PinballMainID,
|
||||||
|
SpinPoint=state.SpinPoint,
|
||||||
|
Scores=state.Scores,
|
||||||
|
Multiple=state.Multiple,
|
||||||
|
Token=state.Token,
|
||||||
|
ConsumedToken=state.ConsumedToken,
|
||||||
|
RewardIndex=state.RewardIndex,
|
||||||
|
Force=state.Force,
|
||||||
|
LuckyValue=state.LuckyValue,
|
||||||
|
InflationRate=state.InflationRate
|
||||||
|
};
|
||||||
|
}
|
||||||
public EventPinballData PinballData { get { return m_PinballData; } }
|
public EventPinballData PinballData { get { return m_PinballData; } }
|
||||||
public int RewardMaxIndex
|
public int RewardMaxIndex
|
||||||
{
|
{
|
||||||
@@ -957,4 +990,4 @@ namespace game
|
|||||||
|
|
||||||
public const int MultipleMax = 10;
|
public const int MultipleMax = 10;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ namespace game
|
|||||||
{
|
{
|
||||||
public class EventPotionDataManager
|
public class EventPotionDataManager
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private bool m_IsCheckCondition = true;
|
private bool m_IsCheckCondition = true;
|
||||||
private bool m_IsSyncData = true;
|
private bool m_IsSyncData = true;
|
||||||
@@ -125,6 +126,55 @@ namespace game
|
|||||||
|
|
||||||
#region 数据相关
|
#region 数据相关
|
||||||
private EventPotionData m_PotionData;
|
private EventPotionData m_PotionData;
|
||||||
|
|
||||||
|
internal static PlayerDataStorage.PlayerKVPotionState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
PlayerDataStorage.PlayerKVSchemaDiagnostics errors) => PlayerDataStorage.PlayerKVSaveSchema.DecodePotion(raw,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
m_PotionData=null; m_PendingFirstPlayedEventId=0; m_SpriteAtlas=null; m_Tables=null;
|
||||||
|
m_TbEventPotionMain=null; m_TbEventPotionStage=null; m_TbEventPotionBlock=null; m_TbEventPotionBottle=null;
|
||||||
|
m_PotionResDict=new Dictionary<int,EventPotionResource>(); m_WallsBefore=new List<PotionItemData>(); m_WallsAfter=new List<PotionItemData>();
|
||||||
|
m_UIPanel=m_InfoPanel=m_RewardPopupPanel=null; m_ScrollerDataList=new List<PotionItemData>();
|
||||||
|
}
|
||||||
|
static PotionItemData MaterializeKVPotionItem(PlayerDataStorage.PlayerKVPotionItem value) => new PotionItemData {
|
||||||
|
name=value.Name,index=value.Index,isOver=value.IsOver,DataType=(EventPotionDataType)value.DataType,
|
||||||
|
ColorTypeList=new List<int>(value.Colors),ShelfTypeList=value.Shelves.Select(n=>(EventPotionShelfType)n).ToList(),
|
||||||
|
GridStateList=value.Grids.Select(n=>(EventPotionGridState)n).ToList(),FromDisplayAreaIndexList=new List<int>(value.FromDisplay)
|
||||||
|
};
|
||||||
|
internal void ReplaceFromKVDecoded(PlayerDataStorage.PlayerKVPotionState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
m_PotionData=!state.IsPresent ? null : new EventPotionData {
|
||||||
|
EventID=state.EventID,
|
||||||
|
PotionID=state.PotionID,
|
||||||
|
StageID=state.StageID,
|
||||||
|
Stage1TotalLevel=state.Stage1TotalLevel,
|
||||||
|
Stage2TotalLevel=state.Stage2TotalLevel,
|
||||||
|
LevelID=state.LevelID,
|
||||||
|
LevelIndex=state.LevelIndex,
|
||||||
|
CorrectNum=state.CorrectNum,
|
||||||
|
SubmitNum=state.SubmitNum,
|
||||||
|
Token=state.Token,
|
||||||
|
ConsumedToken=state.ConsumedToken,
|
||||||
|
Rule=state.Rule,
|
||||||
|
PreEventID=state.PreEventID,
|
||||||
|
PrePotionID=state.PrePotionID,
|
||||||
|
PreStageID=state.PreStageID,
|
||||||
|
PreLevelID=state.PreLevelID,
|
||||||
|
Round=state.Round,
|
||||||
|
FirstPlayedEventId=state.FirstPlayedEventId,
|
||||||
|
IsOver=state.IsOver,
|
||||||
|
Name=state.Name,
|
||||||
|
InflationRate=state.InflationRate,
|
||||||
|
LevelTargetData=MaterializeKVPotionItem(state.LevelTargetData),
|
||||||
|
LevelDisplayData=MaterializeKVPotionItem(state.LevelDisplayData),
|
||||||
|
LevelProcessedList=state.LevelProcessedList.Select(MaterializeKVPotionItem).ToList()
|
||||||
|
};
|
||||||
|
}
|
||||||
|
internal bool IsInactiveForKVValidation => m_PendingFirstPlayedEventId==0 && m_SpriteAtlas==null && m_Tables==null &&
|
||||||
|
m_TbEventPotionMain==null && m_TbEventPotionStage==null && m_TbEventPotionBlock==null && m_TbEventPotionBottle==null &&
|
||||||
|
m_PotionResDict.Count==0 && m_WallsBefore.Count==0 && m_WallsAfter.Count==0 && m_ScrollerDataList.Count==0 &&
|
||||||
|
m_UIPanel==null && m_InfoPanel==null && m_RewardPopupPanel==null;
|
||||||
public EventPotionData PotionData { get { return m_PotionData; } }
|
public EventPotionData PotionData { get { return m_PotionData; } }
|
||||||
|
|
||||||
public void InitLevel()
|
public void InitLevel()
|
||||||
@@ -523,7 +573,7 @@ namespace game
|
|||||||
public void SyncData()
|
public void SyncData()
|
||||||
{
|
{
|
||||||
if (!m_IsSyncData) return;
|
if (!m_IsSyncData) return;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(EventPotionConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_PotionData));
|
playerSaveStore.Write(EventPotionConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_PotionData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
public PotionItemData GetOperationItemData()
|
public PotionItemData GetOperationItemData()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ namespace game
|
|||||||
{
|
{
|
||||||
public class EventScratchTicketDataManager
|
public class EventScratchTicketDataManager
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private bool m_IsCheckCondition = true;
|
private bool m_IsCheckCondition = true;
|
||||||
private bool m_IsSyncData = true;
|
private bool m_IsSyncData = true;
|
||||||
@@ -94,6 +95,45 @@ namespace game
|
|||||||
|
|
||||||
#region 数据相关
|
#region 数据相关
|
||||||
private EventScratchTicketData m_ScratchTicketData;
|
private EventScratchTicketData m_ScratchTicketData;
|
||||||
|
internal bool IsInactiveForKVValidation => m_Tables==null && m_TbEventScratchMain==null && m_TbEventScratchCard==null &&
|
||||||
|
m_TbEventScratchReward==null && m_ChainPackData==null && m_NormalPackData==null && m_SpriteAtlas==null && m_SpriteDict==null &&
|
||||||
|
m_UIPanel==null && m_InfoPanel==null && m_RewardPanel==null && m_ChainPackPanel==null && m_PackPanel==null &&
|
||||||
|
m_RecordList.Count==0 && m_PointWeightList.Count==0 && m_ScratchStampList.Count==0 &&
|
||||||
|
TempRecordRewardTaskID==0 && TempRecordRewardTaskConsumedToken==0;
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVScratchState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodeScratch(raw,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
m_ScratchTicketData=null; TempRecordRewardTaskID=TempRecordRewardTaskConsumedToken=0; m_RecordList=new List<EventScratchTicketRecordData>();
|
||||||
|
m_PointWeightList=new List<float>(); m_ScratchStampList=new List<int>(); m_ChainPackData=null; m_NormalPackData=null;
|
||||||
|
m_UIPanel=m_InfoPanel=m_RewardPanel=m_ChainPackPanel=m_PackPanel=null; m_SpriteAtlas=null; m_SpriteDict=null;
|
||||||
|
m_Tables=null; m_TbEventScratchMain=null; m_TbEventScratchCard=null; m_TbEventScratchReward=null;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVScratchState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
m_ScratchTicketData=!state.IsPresent ? null : new EventScratchTicketData
|
||||||
|
{
|
||||||
|
EventID=state.EventID,
|
||||||
|
ScratchMainID=state.ScratchMainID,
|
||||||
|
ChainPackID=state.ChainPackID,
|
||||||
|
Token=state.Token,
|
||||||
|
ConsumedToken=state.ConsumedToken,
|
||||||
|
RewardTaskConsumedToken=state.RewardTaskConsumedToken,
|
||||||
|
EventScratchRewardTaskID=state.EventScratchRewardTaskID,
|
||||||
|
EventScratchCardID=state.EventScratchCardID,
|
||||||
|
TotalConsumedToken=state.TotalConsumedToken,
|
||||||
|
ChainPackProgress=state.ChainPackProgress,
|
||||||
|
magIndex=state.magIndex,
|
||||||
|
IsOver=state.IsOver,
|
||||||
|
LuckyValue=state.LuckyValue,
|
||||||
|
InflationRate=state.InflationRate,
|
||||||
|
StampRewardList=new List<int>(state.StampRewardList),
|
||||||
|
StampRewardDict=state.StampRewardDict.ToDictionary(p=>p.Key,p=>new EventScratchTicketOwnedStampRewardData { EventScratchCardID=p.Value.EventScratchCardID,Count=p.Value.Count })
|
||||||
|
};
|
||||||
|
}
|
||||||
public EventScratchTicketData ScratchTicketData { get { return m_ScratchTicketData; } }
|
public EventScratchTicketData ScratchTicketData { get { return m_ScratchTicketData; } }
|
||||||
public EventScratchMain GetFreshScratchTicketData()
|
public EventScratchMain GetFreshScratchTicketData()
|
||||||
{
|
{
|
||||||
@@ -555,7 +595,7 @@ namespace game
|
|||||||
public void SyncData()
|
public void SyncData()
|
||||||
{
|
{
|
||||||
if (!m_IsSyncData) return;
|
if (!m_IsSyncData) return;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(EventScratchTicketConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_ScratchTicketData));
|
playerSaveStore.Write(EventScratchTicketConfig.SAVE_DATA_KEY, Newtonsoft.Json.JsonConvert.SerializeObject(m_ScratchTicketData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
List<int> magList = new List<int>() { 1, 5, 10, 20 };
|
List<int> magList = new List<int>() { 1, 5, 10, 20 };
|
||||||
|
|||||||
@@ -13,6 +13,20 @@ public class FishingBoxData
|
|||||||
public Dictionary<int, int> FishingNewBoxs = new();
|
public Dictionary<int, int> FishingNewBoxs = new();
|
||||||
public Dictionary<int, int> FishingBoxOpenNum = new();
|
public Dictionary<int, int> FishingBoxOpenNum = new();
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVIntMapState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
IReadOnlyDictionary<string,string> modern, game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodeFishingBox(raw,modern,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
FishingNewBoxs = new Dictionary<int,int>();
|
||||||
|
FishingBoxOpenNum = new Dictionary<int,int>();
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVIntMapState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new ArgumentNullException(nameof(state));
|
||||||
|
FishingBoxOpenNum = state.Values.ToDictionary(p=>p.Key,p=>p.Value);
|
||||||
|
}
|
||||||
|
|
||||||
public void InitData(string data)
|
public void InitData(string data)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(data) == false)
|
if (string.IsNullOrEmpty(data) == false)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
@@ -40,6 +40,8 @@ public class FishingChallengeData
|
|||||||
|
|
||||||
public class FishingChallengeManager
|
public class FishingChallengeManager
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
|
||||||
//
|
//
|
||||||
private const string SaveKey = "FishingChallengeData";
|
private const string SaveKey = "FishingChallengeData";
|
||||||
|
|
||||||
@@ -61,6 +63,44 @@ public class FishingChallengeManager
|
|||||||
private DateTime EndTime;
|
private DateTime EndTime;
|
||||||
//
|
//
|
||||||
public FishingChallengeData fishingChallengeData { get; private set; }
|
public FishingChallengeData fishingChallengeData { get; private set; }
|
||||||
|
internal bool IsInactiveForKVValidation => !IsInit && CurFishingEventData==null && eventChallengeMain==null &&
|
||||||
|
eventChallengeConfig==null && challengeMapData==null && _stageDropList.Count==0 && _eliminateListScore.Count==0;
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVChallengeState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodeChallenge(raw,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
fishingChallengeData=null; IsInit=false; PrefabName=null;
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
_cheatingScore=0;
|
||||||
|
#endif
|
||||||
|
TopRankTier=Rank=FullStep=PlayerFullNumber=PreScore=0;
|
||||||
|
CurFishingEventData=null; StartTime=EndTime=default; eventChallengeMain=null; eventChallengeConfig=null; challengeMapData=null; itemDataList=null;
|
||||||
|
_stageDropList.Clear(); _eliminateListScore.Clear(); _eventTrackStageList=new List<int>(); _eventTrackNormalRewardList=new List<int>(); InVisibleReason=string.Empty;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVChallengeState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
fishingChallengeData=!state.IsPresent || state.IsExplicitNull ? null : new FishingChallengeData
|
||||||
|
{
|
||||||
|
FirstOpen=state.FirstOpen,
|
||||||
|
EventId=state.EventId,
|
||||||
|
RankTierLevel=state.RankTierLevel,
|
||||||
|
Finished=state.Finished,
|
||||||
|
RedirectID=state.RedirectID,
|
||||||
|
Score=state.Score,
|
||||||
|
ProcessedScore=state.ProcessedScore,
|
||||||
|
step=state.step,
|
||||||
|
uiStep=state.uiStep,
|
||||||
|
index=state.index,
|
||||||
|
StartTime=state.StartTime,
|
||||||
|
EndTime=state.EndTime,
|
||||||
|
eliminateNumber=new List<int>(state.eliminateNumber),
|
||||||
|
robotAccountList=new List<int>(state.robotAccountList),
|
||||||
|
InflationRate=state.InflationRate
|
||||||
|
};
|
||||||
|
}
|
||||||
public EventChallengeMain eventChallengeMain { get; private set; }
|
public EventChallengeMain eventChallengeMain { get; private set; }
|
||||||
public EventChallengeConfig eventChallengeConfig { get; private set; }
|
public EventChallengeConfig eventChallengeConfig { get; private set; }
|
||||||
public MapData challengeMapData { get; private set; }
|
public MapData challengeMapData { get; private set; }
|
||||||
@@ -1047,7 +1087,7 @@ public class FishingChallengeManager
|
|||||||
|
|
||||||
private void DoSave()
|
private void DoSave()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, JsonConvert.SerializeObject(fishingChallengeData));
|
SaveStore.Write(SaveKey, JsonConvert.SerializeObject(fishingChallengeData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public string GetOpenEventKey()
|
public string GetOpenEventKey()
|
||||||
@@ -1071,4 +1111,4 @@ public class FishingChallengeManager
|
|||||||
_stageDropList.Clear();
|
_stageDropList.Clear();
|
||||||
_eventTrackStageList = new();
|
_eventTrackStageList = new();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
if (Pack1A1Data == null)
|
if (Pack1A1Data == null)
|
||||||
{
|
{
|
||||||
string json_duelData = PlayFabMgr.Instance.GetLocalData(Pack1A1DataKey);
|
string json_duelData = playerSaveStore.Read(Pack1A1DataKey).ValueOrThrow();
|
||||||
if (json_duelData != null)
|
if (json_duelData != null)
|
||||||
{
|
{
|
||||||
Pack1A1Data = Newtonsoft.Json.JsonConvert.DeserializeObject<TriggerPackBuyData>(json_duelData);
|
Pack1A1Data = Newtonsoft.Json.JsonConvert.DeserializeObject<TriggerPackBuyData>(json_duelData);
|
||||||
@@ -42,7 +42,7 @@ namespace GameCore
|
|||||||
};
|
};
|
||||||
RedPointManager.Instance.SetRedPointState(HomeBtnOneOnePack.redKey, false);
|
RedPointManager.Instance.SetRedPointState(HomeBtnOneOnePack.redKey, false);
|
||||||
|
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(Pack1A1DataKey, JsonMapper.ToJson(Pack1A1Data));
|
playerSaveStore.Write(Pack1A1DataKey, JsonMapper.ToJson(Pack1A1Data)).RequireAccepted();
|
||||||
}
|
}
|
||||||
public void SetPack1A1Index(int index)
|
public void SetPack1A1Index(int index)
|
||||||
{
|
{
|
||||||
@@ -58,7 +58,7 @@ namespace GameCore
|
|||||||
GContext.Publish(new TargetEvent(Pack1A1Data.lastID, 3, 11));
|
GContext.Publish(new TargetEvent(Pack1A1Data.lastID, 3, 11));
|
||||||
}
|
}
|
||||||
RedPointManager.Instance.SetRedPointState(HomeBtnOneOnePack.redKey, Pack1A1Data.index == 1);
|
RedPointManager.Instance.SetRedPointState(HomeBtnOneOnePack.redKey, Pack1A1Data.index == 1);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(Pack1A1DataKey, JsonMapper.ToJson(Pack1A1Data));
|
playerSaveStore.Write(Pack1A1DataKey, JsonMapper.ToJson(Pack1A1Data)).RequireAccepted();
|
||||||
}
|
}
|
||||||
public int GetPack1A1Index()
|
public int GetPack1A1Index()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ namespace GameCore
|
|||||||
{
|
{
|
||||||
if (Pack1A2Data == null)
|
if (Pack1A2Data == null)
|
||||||
{
|
{
|
||||||
string json_duelData = PlayFabMgr.Instance.GetLocalData(Pack1A2DataKey);
|
string json_duelData = playerSaveStore.Read(Pack1A2DataKey).ValueOrThrow();
|
||||||
if (json_duelData != null)
|
if (json_duelData != null)
|
||||||
{
|
{
|
||||||
Pack1A2Data = Newtonsoft.Json.JsonConvert.DeserializeObject<Pack1A2Data>(json_duelData);
|
Pack1A2Data = Newtonsoft.Json.JsonConvert.DeserializeObject<Pack1A2Data>(json_duelData);
|
||||||
@@ -74,7 +74,7 @@ namespace GameCore
|
|||||||
SetType();
|
SetType();
|
||||||
SetRodDstId();
|
SetRodDstId();
|
||||||
SetChainPackRed();
|
SetChainPackRed();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(Pack1A2DataKey, JsonMapper.ToJson(Pack1A2Data));
|
playerSaveStore.Write(Pack1A2DataKey, JsonMapper.ToJson(Pack1A2Data)).RequireAccepted();
|
||||||
}
|
}
|
||||||
void SetType()
|
void SetType()
|
||||||
{
|
{
|
||||||
@@ -109,7 +109,7 @@ namespace GameCore
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Pack1A2Data.index++;
|
Pack1A2Data.index++;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(Pack1A2DataKey, JsonMapper.ToJson(Pack1A2Data));
|
playerSaveStore.Write(Pack1A2DataKey, JsonMapper.ToJson(Pack1A2Data)).RequireAccepted();
|
||||||
SetChainPackRed();
|
SetChainPackRed();
|
||||||
}
|
}
|
||||||
void SetChainPackRed()
|
void SetChainPackRed()
|
||||||
|
|||||||
@@ -87,9 +87,12 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public async void ShowRankTierChange()
|
public async void ShowRankTierChange()
|
||||||
{
|
{
|
||||||
|
var store = playerSaveStore;
|
||||||
|
if (!store.IsCurrent) return;
|
||||||
if (rankTierChangeState > 0 && curSolomain != null)
|
if (rankTierChangeState > 0 && curSolomain != null)
|
||||||
{
|
{
|
||||||
GameObject go = await UIManager.Instance.ShowUI(UITypes.EventFishingDuelRankChangePopupPanel);
|
GameObject go = await UIManager.Instance.ShowUI(UITypes.EventFishingDuelRankChangePopupPanel);
|
||||||
|
if (!store.IsCurrent) return;
|
||||||
EventFishingDuelRankChangePopupPanel changePopupPanel = go.GetComponent<EventFishingDuelRankChangePopupPanel>();
|
EventFishingDuelRankChangePopupPanel changePopupPanel = go.GetComponent<EventFishingDuelRankChangePopupPanel>();
|
||||||
changePopupPanel.SetRank(rankTierChangeState == 1, curSolomain);
|
changePopupPanel.SetRank(rankTierChangeState == 1, curSolomain);
|
||||||
rankTierChangeState = 0;
|
rankTierChangeState = 0;
|
||||||
@@ -98,7 +101,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public void SoloCheckClaimReward()
|
public void SoloCheckClaimReward()
|
||||||
{
|
{
|
||||||
string json_duelData = PlayFabMgr.Instance.GetLocalData(FishingDuelManager.SoloDataKey);
|
string json_duelData = playerSaveStore.Read(FishingDuelManager.SoloDataKey).ValueOrThrow();
|
||||||
if (json_duelData != null)
|
if (json_duelData != null)
|
||||||
{
|
{
|
||||||
duelData = Newtonsoft.Json.JsonConvert.DeserializeObject<DuelData>(json_duelData);
|
duelData = Newtonsoft.Json.JsonConvert.DeserializeObject<DuelData>(json_duelData);
|
||||||
@@ -120,7 +123,7 @@ namespace GameCore
|
|||||||
duelData.rewardEventID = 0;
|
duelData.rewardEventID = 0;
|
||||||
duelData.preProgress = 0;
|
duelData.preProgress = 0;
|
||||||
string json_duelData = Newtonsoft.Json.JsonConvert.SerializeObject(duelData);
|
string json_duelData = Newtonsoft.Json.JsonConvert.SerializeObject(duelData);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(FishingDuelManager.SoloDataKey, json_duelData);
|
playerSaveStore.Write(FishingDuelManager.SoloDataKey, json_duelData).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public void GMAddSoloProgress(int count)
|
public void GMAddSoloProgress(int count)
|
||||||
@@ -133,7 +136,7 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public void InitSoloData(FishingEvent t)
|
public void InitSoloData(FishingEvent t)
|
||||||
{
|
{
|
||||||
string json_duelData = PlayFabMgr.Instance.GetLocalData(FishingDuelManager.SoloDataKey);
|
string json_duelData = playerSaveStore.Read(FishingDuelManager.SoloDataKey).ValueOrThrow();
|
||||||
if (json_duelData != null)
|
if (json_duelData != null)
|
||||||
{
|
{
|
||||||
duelData = Newtonsoft.Json.JsonConvert.DeserializeObject<DuelData>(json_duelData);
|
duelData = Newtonsoft.Json.JsonConvert.DeserializeObject<DuelData>(json_duelData);
|
||||||
@@ -262,7 +265,7 @@ namespace GameCore
|
|||||||
public void AddPVPToken(int value)
|
public void AddPVPToken(int value)
|
||||||
{
|
{
|
||||||
PVPToken += value;
|
PVPToken += value;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("PVPToken", PVPToken.ToString());
|
playerSaveStore.Write("PVPToken", PVPToken.ToString()).RequireAccepted();
|
||||||
if (value < 0 && duelData != null)
|
if (value < 0 && duelData != null)
|
||||||
{
|
{
|
||||||
duelData.rePVPToken -= value;
|
duelData.rePVPToken -= value;
|
||||||
@@ -272,7 +275,7 @@ namespace GameCore
|
|||||||
public void SaveDuelData()
|
public void SaveDuelData()
|
||||||
{
|
{
|
||||||
string json_duelData = Newtonsoft.Json.JsonConvert.SerializeObject(duelData);
|
string json_duelData = Newtonsoft.Json.JsonConvert.SerializeObject(duelData);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(FishingDuelManager.SoloDataKey, json_duelData);
|
playerSaveStore.Write(FishingDuelManager.SoloDataKey, json_duelData).RequireAccepted();
|
||||||
}
|
}
|
||||||
#endregion SoloData
|
#endregion SoloData
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace DataCenter
|
|||||||
|
|
||||||
public class OfferChainsChestManager
|
public class OfferChainsChestManager
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
|
|
||||||
public const string SaveKey = "OfferChainsChestData";
|
public const string SaveKey = "OfferChainsChestData";
|
||||||
[Inject] public Tables _tables { get; set; }
|
[Inject] public Tables _tables { get; set; }
|
||||||
@@ -51,6 +52,28 @@ namespace DataCenter
|
|||||||
public List<EventOfferChainsChestRewards> OfferChainsChestRewards { get; set; }
|
public List<EventOfferChainsChestRewards> OfferChainsChestRewards { get; set; }
|
||||||
// 当前可保存数据
|
// 当前可保存数据
|
||||||
public TOfferChainsData OfferChainsData { get; private set; }
|
public TOfferChainsData OfferChainsData { get; private set; }
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVOfferState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodeOffer(raw,false,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
OfferChainsData=null; ValidIds=new List<int>(); _fishingEvent=null; _isInit=false;
|
||||||
|
OfferChainsChestMain=null; OfferChainsChestRewards=null;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVOfferState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new ArgumentNullException(nameof(state));
|
||||||
|
OfferChainsData=!state.IsPresent ? null : new TOfferChainsData
|
||||||
|
{
|
||||||
|
FirstOpen=state.FirstOpen,EventId=state.EventId,StartTime=state.StartTime,EndTime=state.EndTime,
|
||||||
|
ItemId=state.ItemId,LotteryNum=state.LotteryNum,
|
||||||
|
Items=state.Items.Select(item=>new TOfferChainsData.TItem {
|
||||||
|
Id=item.Id,Item=item.Item,Number=item.Number,Status=item.Status }).ToList(),
|
||||||
|
RewardList=new List<int>(state.RewardList),Finished=state.Finished,ChestReward=state.ChestReward
|
||||||
|
};
|
||||||
|
}
|
||||||
|
internal bool IsInactiveForKVValidation => !_isInit && _fishingEvent == null;
|
||||||
public List<int> ValidIds;
|
public List<int> ValidIds;
|
||||||
|
|
||||||
public bool IsFirstOpen
|
public bool IsFirstOpen
|
||||||
@@ -255,7 +278,7 @@ namespace DataCenter
|
|||||||
private void SaveData()
|
private void SaveData()
|
||||||
{
|
{
|
||||||
ELog($"SaveData-> {JsonConvert.SerializeObject(OfferChainsData)}");
|
ELog($"SaveData-> {JsonConvert.SerializeObject(OfferChainsData)}");
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, JsonConvert.SerializeObject(OfferChainsData));
|
playerSaveStore.Write(SaveKey, JsonConvert.SerializeObject(OfferChainsData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadData(string dataValue)
|
public void LoadData(string dataValue)
|
||||||
@@ -267,6 +290,7 @@ namespace DataCenter
|
|||||||
// 进入游戏舞台
|
// 进入游戏舞台
|
||||||
public async void OnEnterGameAct()
|
public async void OnEnterGameAct()
|
||||||
{
|
{
|
||||||
|
if (!playerSaveStore.IsCurrent) return;
|
||||||
Log("OnEnterGameAct()");
|
Log("OnEnterGameAct()");
|
||||||
IsFirstOpen = false;
|
IsFirstOpen = false;
|
||||||
await UIManager.Instance.ShowUI(new UIType(OfferChainsChestMain.UIPanel));
|
await UIManager.Instance.ShowUI(new UIType(OfferChainsChestMain.UIPanel));
|
||||||
@@ -546,4 +570,4 @@ namespace DataCenter
|
|||||||
return iAPItemList;
|
return iAPItemList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ namespace DataCenter
|
|||||||
// Disco Manager
|
// Disco Manager
|
||||||
public class OfferDiscoPartyManager
|
public class OfferDiscoPartyManager
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
public const string SaveKey = "OfferDiscoPartyManager";
|
public const string SaveKey = "OfferDiscoPartyManager";
|
||||||
|
|
||||||
// 免费抽奖次数
|
// 免费抽奖次数
|
||||||
@@ -61,6 +62,28 @@ namespace DataCenter
|
|||||||
|
|
||||||
public TOfferDiscoPartyData OfferDiscoPartyData { get; private set; }
|
public TOfferDiscoPartyData OfferDiscoPartyData { get; private set; }
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVOfferState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodeOffer(raw,true,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
OfferDiscoPartyData=null; ValidIds=new List<int>(); _fishingEvent=null; _isInit=false;
|
||||||
|
OfferDiscoParty=null; OfferDiscoPartyRewards=null; FreeTime=1;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVOfferState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new ArgumentNullException(nameof(state));
|
||||||
|
OfferDiscoPartyData=!state.IsPresent ? null : new TOfferDiscoPartyData
|
||||||
|
{
|
||||||
|
FirstOpen=state.FirstOpen,EventId=state.EventId,StartTime=state.StartTime,EndTime=state.EndTime,
|
||||||
|
ItemId=state.ItemId,LotteryNum=state.LotteryNum,
|
||||||
|
Items=state.Items.Select(item=>new TOfferDiscoPartyData.TItem {
|
||||||
|
Id=item.Id,Item=item.Item,Number=item.Number,Status=(TItemStatues) item.Status }).ToList(),
|
||||||
|
RewardList=new List<int>(state.RewardList)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
internal bool IsInactiveForKVValidation => !_isInit && _fishingEvent == null;
|
||||||
|
|
||||||
|
|
||||||
public List<int> ValidIds; //
|
public List<int> ValidIds; //
|
||||||
|
|
||||||
@@ -269,7 +292,7 @@ namespace DataCenter
|
|||||||
|
|
||||||
private void SaveData()
|
private void SaveData()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, JsonConvert.SerializeObject(OfferDiscoPartyData));
|
playerSaveStore.Write(SaveKey, JsonConvert.SerializeObject(OfferDiscoPartyData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadData(string dataValue)
|
public void LoadData(string dataValue)
|
||||||
@@ -287,6 +310,7 @@ namespace DataCenter
|
|||||||
|
|
||||||
public async void OnEnterGameAct()
|
public async void OnEnterGameAct()
|
||||||
{
|
{
|
||||||
|
if (!playerSaveStore.IsCurrent) return;
|
||||||
ELog("OnEnterGameAct()");
|
ELog("OnEnterGameAct()");
|
||||||
IsFirstOpen = false;
|
IsFirstOpen = false;
|
||||||
await UIManager.Instance.ShowUI(new UIType(OfferDiscoParty.UIPanel));
|
await UIManager.Instance.ShowUI(new UIType(OfferDiscoParty.UIPanel));
|
||||||
@@ -561,4 +585,4 @@ namespace DataCenter
|
|||||||
return iAPItemList;
|
return iAPItemList;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ using game;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
public class PiggyBankPackData
|
public class PiggyBankPackData
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore playerSaveStore { get; set; }
|
||||||
private readonly Tables _tables = GContext.container.Resolve<Tables>();
|
private readonly Tables _tables = GContext.container.Resolve<Tables>();
|
||||||
private readonly TbEventPackManager _epm
|
private readonly TbEventPackManager _epm
|
||||||
= GContext.container.Resolve<Tables>().TbEventPackManager;
|
= GContext.container.Resolve<Tables>().TbEventPackManager;
|
||||||
@@ -34,14 +35,47 @@ public class PiggyBankPackData
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Data _data;
|
private Data _data;
|
||||||
|
|
||||||
|
private bool _kvLoadPresent;
|
||||||
|
internal bool KVLoadPresent => _kvLoadPresent;
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVPiggyBankState DecodeForKVLoad(
|
||||||
|
IReadOnlyDictionary<string, string> raw, game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodePiggyBank(raw, snapshot, errors);
|
||||||
|
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
_kvLoadPresent = false;
|
||||||
|
_data = default(Data);
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVPiggyBankState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new ArgumentNullException(nameof(state));
|
||||||
|
if (!state.IsPresent) { ResetForKVLoad(); return; }
|
||||||
|
var replacement = new Data
|
||||||
|
{
|
||||||
|
currentEventID = state.currentEventID,
|
||||||
|
purchaseCount = state.purchaseCount,
|
||||||
|
VIPLvlWhenEventActivate = state.VIPLvlWhenEventActivate,
|
||||||
|
savingProgress = state.savingProgress,
|
||||||
|
redirectID = state.redirectID,
|
||||||
|
doNeedTrigger = state.doNeedTrigger,
|
||||||
|
isTriggered = state.isTriggered,
|
||||||
|
inflation = state.inflation,
|
||||||
|
};
|
||||||
|
_data = replacement;
|
||||||
|
_kvLoadPresent = true;
|
||||||
|
}
|
||||||
|
internal game.PlayerDataStorage.PlayerKVPiggyBankState SnapshotForKVValidation() =>
|
||||||
|
new game.PlayerDataStorage.PlayerKVPiggyBankState(_kvLoadPresent, _data.currentEventID, _data.purchaseCount, _data.VIPLvlWhenEventActivate, _data.savingProgress, _data.redirectID, _data.doNeedTrigger, _data.isTriggered, _data.inflation);
|
||||||
public bool IsWithinEventTime
|
public bool IsWithinEventTime
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
if (!_tables.TbFishingEvent.DataMap.Keys.Contains(_data.currentEventID))
|
var fishingEvent = _tables.TbFishingEvent.GetOrDefault(_data.currentEventID);
|
||||||
return false;
|
if (!(fishingEvent?.TimeDefinition is LimitedTime time)) return false;
|
||||||
var et = DateTime.Parse((_tables.TbFishingEvent[_data.currentEventID].TimeDefinition as LimitedTime).EndTime);
|
var et = DateTime.Parse(time.EndTime);
|
||||||
var st = DateTime.Parse((_tables.TbFishingEvent[_data.currentEventID].TimeDefinition as LimitedTime).StartTime);
|
var st = DateTime.Parse(time.StartTime);
|
||||||
return ZZTimeHelper.UtcNow() >= st && ZZTimeHelper.UtcNow() < et;
|
return ZZTimeHelper.UtcNow() >= st && ZZTimeHelper.UtcNow() < et;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -160,8 +194,8 @@ public class PiggyBankPackData
|
|||||||
}
|
}
|
||||||
public void SaveData()
|
public void SaveData()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("PiggyBankPackData",
|
playerSaveStore.Write("PiggyBankPackData",
|
||||||
Newtonsoft.Json.JsonConvert.SerializeObject(_data));
|
Newtonsoft.Json.JsonConvert.SerializeObject(_data)).RequireAccepted();
|
||||||
}
|
}
|
||||||
public bool AddProgress(int fishTier, int magnification)
|
public bool AddProgress(int fishTier, int magnification)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ namespace GameCore
|
|||||||
public void SaveInitRodAccessoriesData()
|
public void SaveInitRodAccessoriesData()
|
||||||
{
|
{
|
||||||
string value = Newtonsoft.Json.JsonConvert.SerializeObject(rodAccessoriesData);
|
string value = Newtonsoft.Json.JsonConvert.SerializeObject(rodAccessoriesData);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(InitRodAccessoriesDataKey, value);
|
playerSaveStore.Write(InitRodAccessoriesDataKey, value).RequireAccepted();
|
||||||
}
|
}
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// 手是否解锁
|
/// 手是否解锁
|
||||||
@@ -272,7 +272,7 @@ namespace GameCore
|
|||||||
.AddContent("rod_chips_consume", rquiredFragments);
|
.AddContent("rod_chips_consume", rquiredFragments);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("RodData", JsonMapper.ToJson(rodData));
|
playerSaveStore.Write("RodData", JsonMapper.ToJson(rodData)).RequireAccepted();
|
||||||
//鱼竿红点数据修改
|
//鱼竿红点数据修改
|
||||||
CheckRodRedPointUp();
|
CheckRodRedPointUp();
|
||||||
//合成鱼竿
|
//合成鱼竿
|
||||||
@@ -354,7 +354,7 @@ namespace GameCore
|
|||||||
public void SaveHonorLevelData()
|
public void SaveHonorLevelData()
|
||||||
{
|
{
|
||||||
string value = Newtonsoft.Json.JsonConvert.SerializeObject(_honorlevel);
|
string value = Newtonsoft.Json.JsonConvert.SerializeObject(_honorlevel);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(HonorLevelDataKey, value);
|
playerSaveStore.Write(HonorLevelDataKey, value).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion 荣耀等级
|
#endregion 荣耀等级
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
using System;
|
using System;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
using LitJson;
|
using LitJson;
|
||||||
@@ -17,12 +17,14 @@ namespace GameCore
|
|||||||
}
|
}
|
||||||
public class TotalRechargeManager
|
public class TotalRechargeManager
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
public const string TotalRechargeDataKey = "EventTotalRecharge";
|
public const string TotalRechargeDataKey = "EventTotalRecharge";
|
||||||
public TotalRechargeData GetEventData()
|
public TotalRechargeData GetEventData()
|
||||||
{
|
{
|
||||||
var totalRechargeData = new TotalRechargeData();
|
var totalRechargeData = new TotalRechargeData();
|
||||||
|
|
||||||
string data = PlayFabMgr.Instance.GetLocalData(TotalRechargeDataKey);
|
string data = saveStore.Read(TotalRechargeDataKey).ValueOrThrow();
|
||||||
if (!string.IsNullOrEmpty(data))
|
if (!string.IsNullOrEmpty(data))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -175,7 +177,7 @@ namespace GameCore
|
|||||||
|
|
||||||
void SaveTotalRechargeData(TotalRechargeData totalRechargeData)
|
void SaveTotalRechargeData(TotalRechargeData totalRechargeData)
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(TotalRechargeDataKey, JsonMapper.ToJson(totalRechargeData));
|
saveStore.Write(TotalRechargeDataKey, JsonMapper.ToJson(totalRechargeData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using game;
|
using game;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using IngameDebugConsole;
|
using IngameDebugConsole;
|
||||||
@@ -720,7 +720,7 @@ public class DebugFunc
|
|||||||
}
|
}
|
||||||
static void ClearLastPaymentTime()
|
static void ClearLastPaymentTime()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("LastPaymentTime", "");
|
GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>().Write("LastPaymentTime", "").RequireAccepted();
|
||||||
}
|
}
|
||||||
static void HookWheelForecActive()
|
static void HookWheelForecActive()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -607,6 +607,12 @@ public class EventFishingDuelPanel : BasePanel
|
|||||||
}
|
}
|
||||||
void CreateMatchmakingTicket()
|
void CreateMatchmakingTicket()
|
||||||
{
|
{
|
||||||
|
if (GContext.container.Resolve<IUserService>() is not PlayFabUserService)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("KV matchmaking service is not connected.");
|
||||||
|
FDM.MachingEnd(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
int MaxMatchTime = FDM.eventSoloConfig.MaxMatchTime;
|
int MaxMatchTime = FDM.eventSoloConfig.MaxMatchTime;
|
||||||
//可匹配段位列表,杯数,选择倍率,地图列表,随机种子seed,鱼卡等级
|
//可匹配段位列表,杯数,选择倍率,地图列表,随机种子seed,鱼卡等级
|
||||||
List<int> matchTierList = FDM.eventSolomain.MatchTierList;
|
List<int> matchTierList = FDM.eventSolomain.MatchTierList;
|
||||||
@@ -631,8 +637,8 @@ public class EventFishingDuelPanel : BasePanel
|
|||||||
{
|
{
|
||||||
Entity = new EntityKey
|
Entity = new EntityKey
|
||||||
{
|
{
|
||||||
Id = userService.entityKey.Id,
|
Id = ((PlayFabUserService)userService).entityKey.Id,
|
||||||
Type = userService.entityKey.Type
|
Type = ((PlayFabUserService)userService).entityKey.Type
|
||||||
},
|
},
|
||||||
Attributes = new MatchmakingPlayerAttributes
|
Attributes = new MatchmakingPlayerAttributes
|
||||||
{
|
{
|
||||||
@@ -717,6 +723,12 @@ public class EventFishingDuelPanel : BasePanel
|
|||||||
}
|
}
|
||||||
void GetMatchDetails(string matchId)
|
void GetMatchDetails(string matchId)
|
||||||
{
|
{
|
||||||
|
if (GContext.container.Resolve<IUserService>() is not PlayFabUserService)
|
||||||
|
{
|
||||||
|
Debug.LogWarning("KV matchmaking service is not connected.");
|
||||||
|
FDM.MachingEnd(null);
|
||||||
|
return;
|
||||||
|
}
|
||||||
var request = new PlayFab.MultiplayerModels.GetMatchRequest
|
var request = new PlayFab.MultiplayerModels.GetMatchRequest
|
||||||
{
|
{
|
||||||
MatchId = matchId,
|
MatchId = matchId,
|
||||||
@@ -745,7 +757,7 @@ public class EventFishingDuelPanel : BasePanel
|
|||||||
for (int i = 0; i < result.Members.Count; i++)
|
for (int i = 0; i < result.Members.Count; i++)
|
||||||
{
|
{
|
||||||
MatchmakingPlayerWithTeamAssignment member = result.Members[i];
|
MatchmakingPlayerWithTeamAssignment member = result.Members[i];
|
||||||
if (member.Entity.Id != userService.entityKey.Id)
|
if (member.Entity.Id != ((PlayFabUserService)userService).entityKey.Id)
|
||||||
{
|
{
|
||||||
JObject dataObject = JObject.FromObject(result.Members[i].Attributes.DataObject);
|
JObject dataObject = JObject.FromObject(result.Members[i].Attributes.DataObject);
|
||||||
string[] tierArray = dataObject["Tier"].ToObject<string[]>();
|
string[] tierArray = dataObject["Tier"].ToObject<string[]>();
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ namespace game
|
|||||||
GContext.OnEvent<TargetEvent>().Subscribe(OnEvent_TargetEvent).AddTo(Disposables);
|
GContext.OnEvent<TargetEvent>().Subscribe(OnEvent_TargetEvent).AddTo(Disposables);
|
||||||
}
|
}
|
||||||
private Tables _tables;
|
private Tables _tables;
|
||||||
|
[Inject] public PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
bool disposed;
|
||||||
|
|
||||||
[Inject]
|
[Inject]
|
||||||
public Tables Tables
|
public Tables Tables
|
||||||
@@ -28,6 +30,7 @@ namespace game
|
|||||||
|
|
||||||
public virtual void Dispose()
|
public virtual void Dispose()
|
||||||
{
|
{
|
||||||
|
disposed = true;
|
||||||
Disposables?.Dispose();
|
Disposables?.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,6 +41,7 @@ namespace game
|
|||||||
|
|
||||||
protected virtual void OnEvent_TargetEvent(TargetEvent targetEvent)
|
protected virtual void OnEvent_TargetEvent(TargetEvent targetEvent)
|
||||||
{
|
{
|
||||||
|
if (disposed || SaveStore == null || !SaveStore.IsCurrent) return;
|
||||||
if (targetEvent.type == EventType && targetEvent.subType == EventSubType) RefreshData(targetEvent.id);
|
if (targetEvent.type == EventType && targetEvent.subType == EventSubType) RefreshData(targetEvent.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,7 +58,8 @@ namespace game
|
|||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
Debug.Log($"jsd {typeof(T).Name} SaveData {JsonConvert.SerializeObject(Data)}");
|
Debug.Log($"jsd {typeof(T).Name} SaveData {JsonConvert.SerializeObject(Data)}");
|
||||||
#endif
|
#endif
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(typeof(T).Name, JsonConvert.SerializeObject(Data));
|
if (disposed) throw new ObjectDisposedException(GetType().Name);
|
||||||
|
SaveStore.Write(typeof(T).Name, JsonConvert.SerializeObject(Data)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void SaveData(T data)
|
protected virtual void SaveData(T data)
|
||||||
@@ -62,7 +67,8 @@ namespace game
|
|||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
Debug.Log($"jsd {typeof(T).Name} SaveData {JsonConvert.SerializeObject(data)}");
|
Debug.Log($"jsd {typeof(T).Name} SaveData {JsonConvert.SerializeObject(data)}");
|
||||||
#endif
|
#endif
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(typeof(T).Name, JsonConvert.SerializeObject(data));
|
if (disposed) throw new ObjectDisposedException(GetType().Name);
|
||||||
|
SaveStore.Write(typeof(T).Name, JsonConvert.SerializeObject(data)).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void RefreshData(int eventId)
|
protected virtual void RefreshData(int eventId)
|
||||||
@@ -82,7 +88,8 @@ namespace game
|
|||||||
|
|
||||||
protected T GetCacheData()
|
protected T GetCacheData()
|
||||||
{
|
{
|
||||||
var dataStr = PlayFabMgr.Instance.GetLocalData(typeof(T).Name);
|
if (disposed) throw new ObjectDisposedException(GetType().Name);
|
||||||
|
var dataStr = SaveStore.Read(typeof(T).Name).ValueOrThrow();
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
Debug.Log($"jsd {typeof(T).Name} LoadData sData {dataStr}");
|
Debug.Log($"jsd {typeof(T).Name} LoadData sData {dataStr}");
|
||||||
#endif
|
#endif
|
||||||
@@ -133,4 +140,4 @@ namespace game
|
|||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using System;
|
using System;
|
||||||
@@ -410,6 +410,8 @@ public class EventBingoStepState
|
|||||||
|
|
||||||
public class EventBingoPlayfabData
|
public class EventBingoPlayfabData
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
public int EventId, TicketCount, RoundCount, StepInRound, Seed, ChainProgress, ChainTaskTokenProgress;
|
public int EventId, TicketCount, RoundCount, StepInRound, Seed, ChainProgress, ChainTaskTokenProgress;
|
||||||
public float InflationRate;
|
public float InflationRate;
|
||||||
private const int TokenCount = 8;
|
private const int TokenCount = 8;
|
||||||
@@ -473,12 +475,12 @@ public class EventBingoPlayfabData
|
|||||||
|
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(Key, Serialize());
|
saveStore.Write(Key, Serialize()).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EventBingoPlayfabData Load()
|
public static EventBingoPlayfabData Load()
|
||||||
{
|
{
|
||||||
var s = PlayFabMgr.Instance.GetLocalData(Key);
|
var s = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>().Read(Key).ValueOrThrow();
|
||||||
return Deserialize(s);
|
return Deserialize(s);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using SystemRandom = System.Random;
|
using SystemRandom = System.Random;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
@@ -152,6 +152,8 @@ public class DrillModel : IHasChainPack
|
|||||||
|
|
||||||
public class EventBreakPfData
|
public class EventBreakPfData
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
public int EventId { get; set; }
|
public int EventId { get; set; }
|
||||||
public int TicketCount { get; set; }
|
public int TicketCount { get; set; }
|
||||||
public int ChainPackProgress { get; set; }
|
public int ChainPackProgress { get; set; }
|
||||||
@@ -238,7 +240,7 @@ public class EventBreakPfData
|
|||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
var s = Serialize();
|
var s = Serialize();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(PfKey, s);
|
saveStore.Write(PfKey, s).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -350,6 +350,8 @@ public class EventCanProgressTaskInfo
|
|||||||
|
|
||||||
public class EventCanPlayfabData
|
public class EventCanPlayfabData
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
public const string PlayFabKey = "EventCan";
|
public const string PlayFabKey = "EventCan";
|
||||||
private const char Splitter = '|', Comma = ',';
|
private const char Splitter = '|', Comma = ',';
|
||||||
private const int SerializedTokenCount = 11;
|
private const int SerializedTokenCount = 11;
|
||||||
@@ -433,7 +435,7 @@ public class EventCanPlayfabData
|
|||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
var s = Serialize();
|
var s = Serialize();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(PlayFabKey, s);
|
saveStore.Write(PlayFabKey, s).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Log()
|
public void Log()
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// EventCubeMeltManager.cs
|
// EventCubeMeltManager.cs
|
||||||
// 锻刀大赛
|
// 锻刀大赛
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
@@ -22,6 +22,8 @@ using Random = UnityEngine.Random;
|
|||||||
|
|
||||||
public class EventCubeMeltManager
|
public class EventCubeMeltManager
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
|
||||||
//
|
//
|
||||||
public const string SaveKey = "EventCubeMeltData";
|
public const string SaveKey = "EventCubeMeltData";
|
||||||
|
|
||||||
@@ -137,7 +139,7 @@ public class EventCubeMeltManager
|
|||||||
{
|
{
|
||||||
ELog($"SaveData()-> {eventDataJson}");
|
ELog($"SaveData()-> {eventDataJson}");
|
||||||
}
|
}
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(SaveKey, eventDataJson);
|
SaveStore.Write(SaveKey, eventDataJson).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddTicket(int costValue)
|
public void AddTicket(int costValue)
|
||||||
@@ -168,6 +170,34 @@ public class EventCubeMeltManager
|
|||||||
[Inject] public Tables _tables { get; set; }
|
[Inject] public Tables _tables { get; set; }
|
||||||
|
|
||||||
public EventCubeMeltData EventData { get; private set; }
|
public EventCubeMeltData EventData { get; private set; }
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVCubeState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaSnapshot snapshot,game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
game.PlayerDataStorage.PlayerKVSaveSchema.DecodeCube(raw,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
EventData=null; _isInit=false; _fishingEvent=null;
|
||||||
|
EventCubeMeltMainData=null; EventCubeMeltConfig=null; EventCubeMeltStageData=null; EventCubeMeltCollectionData=null;
|
||||||
|
EventCubeMeltPieces=null; EventCubeMeltPieceItems=new List<PieceItem>(); EventCubeMeltItems=null; EventCubeMeltCollections=null;
|
||||||
|
EventStageList=null; StageCount=0; StartTime=EndTime=default; CurrentPieceItems=new List<PieceItem>(); _pieceDimension=default;
|
||||||
|
PrevData=null; NextData=null; PrevBoardData=null; PrevPieceDatas=null; CurrentBoardData=null; CurrentPieceDatas=null; GuideIndex=0;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVCubeState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
EventData=!state.IsPresent ? null : new EventCubeMeltData {
|
||||||
|
TicketCount=state.TicketCount,FirstOpen=state.FirstOpen,IsFinished=state.IsFinished,EventId=state.EventId,
|
||||||
|
IsInGuide=state.IsInGuide,StartTime=state.StartTime,EndTime=state.EndTime,CurrentStagetId=state.CurrentStagetId,
|
||||||
|
CollectItems=state.CollectItems.Select(p=>new CollectItem { ItemId=p.ItemId,Count=p.Count,MaxCount=p.MaxCount,ItemTrueId=p.ItemTrueId }).ToList(),
|
||||||
|
BoardData=new List<int>(state.BoardData),BoardViewSize=new Vector2Int(state.Width,state.Height),
|
||||||
|
CollectRewardsId=new List<int>(state.CollectRewardsId),IsFinalRewardGet=state.IsFinalRewardGet,
|
||||||
|
PieceDatas=state.PieceDatas.Select(p=>new List<int>(p)).ToList(),Cycle=state.Cycle,InflationRate=state.InflationRate
|
||||||
|
};
|
||||||
|
}
|
||||||
|
internal bool IsInactiveForKVValidation => !_isInit && _fishingEvent==null && EventCubeMeltMainData==null &&
|
||||||
|
EventCubeMeltStageData==null && EventCubeMeltCollectionData==null && EventCubeMeltPieces==null &&
|
||||||
|
EventCubeMeltPieceItems.Count==0 && CurrentPieceItems.Count==0 && PrevData==null && NextData==null &&
|
||||||
|
PrevBoardData==null && CurrentBoardData==null && PrevPieceDatas==null && CurrentPieceDatas==null;
|
||||||
|
|
||||||
public FishingEvent FishingEvent {get => _fishingEvent;set => _fishingEvent = value;}
|
public FishingEvent FishingEvent {get => _fishingEvent;set => _fishingEvent = value;}
|
||||||
|
|
||||||
@@ -1711,4 +1741,4 @@ public class EventCubeMeltManager
|
|||||||
var cubeMeltData = _tables.TbEventCubeMeltCollection.DataList.FirstOrDefault(data => data.ID == stageId);
|
var cubeMeltData = _tables.TbEventCubeMeltCollection.DataList.FirstOrDefault(data => data.ID == stageId);
|
||||||
return cubeMeltData?.CollectingReward?? 0;
|
return cubeMeltData?.CollectingReward?? 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using asap.core;
|
using asap.core;
|
||||||
@@ -265,6 +265,8 @@ public class EventGatherCoreRewardInfo
|
|||||||
|
|
||||||
public class EventGatherCorePlayfabData
|
public class EventGatherCorePlayfabData
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
public int EventId { get; set; }
|
public int EventId { get; set; }
|
||||||
public int TicketCount { get; set; }
|
public int TicketCount { get; set; }
|
||||||
public int ChainPackID { get; set; }
|
public int ChainPackID { get; set; }
|
||||||
@@ -312,12 +314,12 @@ public class EventGatherCorePlayfabData
|
|||||||
|
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(Key, Serialize());
|
saveStore.Write(Key, Serialize()).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static EventGatherCorePlayfabData Load()
|
public static EventGatherCorePlayfabData Load()
|
||||||
{
|
{
|
||||||
var s = PlayFabMgr.Instance.GetLocalData(Key);
|
var s = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>().Read(Key).ValueOrThrow();
|
||||||
var res = new EventGatherCorePlayfabData();
|
var res = new EventGatherCorePlayfabData();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using System;
|
using System;
|
||||||
@@ -11,6 +11,8 @@ using UnityEngine;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class EventLuckyGameModel : ILuckyTaskGetData
|
public class EventLuckyGameModel : ILuckyTaskGetData
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
public static EventLuckyGameModel Get()
|
public static EventLuckyGameModel Get()
|
||||||
{
|
{
|
||||||
var model = GContext.container.Resolve<EventLuckyGameModel>();
|
var model = GContext.container.Resolve<EventLuckyGameModel>();
|
||||||
@@ -57,7 +59,7 @@ public class EventLuckyGameModel : ILuckyTaskGetData
|
|||||||
|
|
||||||
string s = Newtonsoft.Json.JsonConvert.SerializeObject(eventLuckGameRecord);
|
string s = Newtonsoft.Json.JsonConvert.SerializeObject(eventLuckGameRecord);
|
||||||
//Debug.Log($"[EventLuckGameModel] Save EventLuckGameRecord: {s}");
|
//Debug.Log($"[EventLuckGameModel] Save EventLuckGameRecord: {s}");
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(Key, s);
|
saveStore.Write(Key, s).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
//=========================以下是活动数据=========================
|
//=========================以下是活动数据=========================
|
||||||
@@ -163,7 +165,7 @@ public class EventLuckyGameModel : ILuckyTaskGetData
|
|||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
string s = PlayFabMgr.Instance.GetLocalData(Key);
|
string s = saveStore.Read(Key).ValueOrThrow();
|
||||||
if (string.IsNullOrEmpty(s))
|
if (string.IsNullOrEmpty(s))
|
||||||
{
|
{
|
||||||
eventLuckGameRecord = new EventLuckGameRecord();
|
eventLuckGameRecord = new EventLuckGameRecord();
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using asap.core;
|
using asap.core;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -261,6 +261,8 @@ public class EventOfferJourneyBlockData
|
|||||||
|
|
||||||
public class EventOfferJourneyPlayfabData
|
public class EventOfferJourneyPlayfabData
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
public int EventId, Progress, TicketCount, VipLvlOnTrigger, RoundCount;
|
public int EventId, Progress, TicketCount, VipLvlOnTrigger, RoundCount;
|
||||||
public float InflationRate;
|
public float InflationRate;
|
||||||
private const string Key = "EventOfferJourneyData";
|
private const string Key = "EventOfferJourneyData";
|
||||||
@@ -319,14 +321,14 @@ public class EventOfferJourneyPlayfabData
|
|||||||
|
|
||||||
public static EventOfferJourneyPlayfabData Load()
|
public static EventOfferJourneyPlayfabData Load()
|
||||||
{
|
{
|
||||||
var s = PlayFabMgr.Instance.GetLocalData(Key);
|
var s = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>().Read(Key).ValueOrThrow();
|
||||||
return Deserialize(s);
|
return Deserialize(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
var s = Serialize();
|
var s = Serialize();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(Key, s);
|
saveStore.Write(Key, s).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -156,6 +156,8 @@ public class EventOfferJourneyLvlTriggerData : AEventOfferJourneyData
|
|||||||
|
|
||||||
public class EventOfferJourneyLvlTriggerPlayfabData
|
public class EventOfferJourneyLvlTriggerPlayfabData
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
public int Progress, TicketCount, RoundCount;
|
public int Progress, TicketCount, RoundCount;
|
||||||
private const string Key = "EventOfferJourneyLvlTriggerData";
|
private const string Key = "EventOfferJourneyLvlTriggerData";
|
||||||
private const int TokenCount = 3;
|
private const int TokenCount = 3;
|
||||||
@@ -195,13 +197,13 @@ public class EventOfferJourneyLvlTriggerPlayfabData
|
|||||||
|
|
||||||
public static EventOfferJourneyLvlTriggerPlayfabData Load()
|
public static EventOfferJourneyLvlTriggerPlayfabData Load()
|
||||||
{
|
{
|
||||||
var s = PlayFabMgr.Instance.GetLocalData(Key);
|
var s = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>().Read(Key).ValueOrThrow();
|
||||||
return Deserialize(s);
|
return Deserialize(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
var s = Serialize();
|
var s = Serialize();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(Key, s);
|
saveStore.Write(Key, s).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -24,7 +24,7 @@ namespace EventPartnerGather
|
|||||||
public class PartnerInfoManager : IDisposable
|
public class PartnerInfoManager : IDisposable
|
||||||
{
|
{
|
||||||
// [Inject]
|
// [Inject]
|
||||||
private static Tables _tables { get; set; } = GContext.container.Resolve<Tables>();
|
private readonly Tables _tables = GContext.container.Resolve<Tables>();
|
||||||
private FriendService _friendService { get; set; } = GContext.container.Resolve<FriendService>();
|
private FriendService _friendService { get; set; } = GContext.container.Resolve<FriendService>();
|
||||||
private IUserService _userService { get; } = GContext.container.Resolve<IUserService>();
|
private IUserService _userService { get; } = GContext.container.Resolve<IUserService>();
|
||||||
|
|
||||||
@@ -41,9 +41,15 @@ namespace EventPartnerGather
|
|||||||
public int EventId { get; set; }
|
public int EventId { get; set; }
|
||||||
|
|
||||||
//
|
//
|
||||||
public static readonly int BuilderCapacity = _tables.TbEventPartnerConfig.InvitationCount[1];
|
// D4: current-context read. Unlike the old field, this is not frozen across configuration changes.
|
||||||
|
public static int BuilderCapacity => GContext.container.Resolve<Tables>().TbEventPartnerConfig.InvitationCount[1];
|
||||||
|
|
||||||
public readonly BuildPartner[] BuildPartners = new BuildPartner[BuilderCapacity];
|
public readonly BuildPartner[] BuildPartners;
|
||||||
|
public PartnerInfoManager()
|
||||||
|
{
|
||||||
|
BuildPartners = new BuildPartner[_tables.TbEventPartnerConfig.InvitationCount[1]];
|
||||||
|
}
|
||||||
|
internal bool HasSubscriptionsForKVLoad => disposables != null;
|
||||||
//
|
//
|
||||||
public bool IsFullyMatched => BuildPartners.All(b => b != null && b.IsValid());
|
public bool IsFullyMatched => BuildPartners.All(b => b != null && b.IsValid());
|
||||||
|
|
||||||
@@ -387,9 +393,9 @@ namespace EventPartnerGather
|
|||||||
public bool AddBuildPartner(BuildPartner buildPartner)
|
public bool AddBuildPartner(BuildPartner buildPartner)
|
||||||
{
|
{
|
||||||
var index = buildPartner.SlotId;
|
var index = buildPartner.SlotId;
|
||||||
if (index >= BuilderCapacity)
|
if (index >= BuildPartners.Length)
|
||||||
{
|
{
|
||||||
LogWarning($"AddBuildPartnerFailed eventId={EventId} reason=SlotOutOfRange slotId={index} capacity={BuilderCapacity}");
|
LogWarning($"AddBuildPartnerFailed eventId={EventId} reason=SlotOutOfRange slotId={index} capacity={BuildPartners.Length}");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,4 +481,4 @@ namespace EventPartnerGather
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
@@ -564,6 +564,8 @@ public class RewardItemNewFlyToStashRequest
|
|||||||
|
|
||||||
public class EventLuckMagicPlayfabData
|
public class EventLuckMagicPlayfabData
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
public int EventId;
|
public int EventId;
|
||||||
public int TicketCount;
|
public int TicketCount;
|
||||||
public int ChainProgress;
|
public int ChainProgress;
|
||||||
@@ -668,7 +670,7 @@ public class EventLuckMagicPlayfabData
|
|||||||
{
|
{
|
||||||
var s = Serialize();
|
var s = Serialize();
|
||||||
// Debug.Log($"[EventLuckMagic] Save playfab data : \n" + s);
|
// Debug.Log($"[EventLuckMagic] Save playfab data : \n" + s);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(Key, s);
|
saveStore.Write(Key, s).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using System;
|
using System;
|
||||||
@@ -15,6 +15,8 @@ public class WelcomeBackData
|
|||||||
}
|
}
|
||||||
public class EventWelcomeBackManager
|
public class EventWelcomeBackManager
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
string DataKey_WelcomeBack = "WelcomeBack";
|
string DataKey_WelcomeBack = "WelcomeBack";
|
||||||
Tables tables;
|
Tables tables;
|
||||||
public TbEventWelcomeBackConfig eventWelcomeBackConfig;
|
public TbEventWelcomeBackConfig eventWelcomeBackConfig;
|
||||||
@@ -28,7 +30,7 @@ public class EventWelcomeBackManager
|
|||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
string data = PlayFabMgr.Instance.GetLocalData(DataKey_WelcomeBack);
|
string data = saveStore.Read(DataKey_WelcomeBack).ValueOrThrow();
|
||||||
if (!string.IsNullOrEmpty(data))
|
if (!string.IsNullOrEmpty(data))
|
||||||
{
|
{
|
||||||
welcomeBackData = Newtonsoft.Json.JsonConvert.DeserializeObject<WelcomeBackData>(data) ?? new WelcomeBackData();
|
welcomeBackData = Newtonsoft.Json.JsonConvert.DeserializeObject<WelcomeBackData>(data) ?? new WelcomeBackData();
|
||||||
@@ -228,7 +230,7 @@ public class EventWelcomeBackManager
|
|||||||
|
|
||||||
void SaveData()
|
void SaveData()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(DataKey_WelcomeBack, Newtonsoft.Json.JsonConvert.SerializeObject(welcomeBackData));
|
saveStore.Write(DataKey_WelcomeBack, Newtonsoft.Json.JsonConvert.SerializeObject(welcomeBackData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public struct ClaimComeBack
|
public struct ClaimComeBack
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using game.PlayerDataStorage;
|
||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using DG.Tweening;
|
using DG.Tweening;
|
||||||
@@ -6,6 +7,7 @@ using GameCore;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UniRx;
|
using UniRx;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
@@ -23,6 +25,53 @@ public class ShowHandEvent
|
|||||||
[DefaultExecutionOrder(10000)]
|
[DefaultExecutionOrder(10000)]
|
||||||
public partial class FishingBehaviorB : MonoBehaviour
|
public partial class FishingBehaviorB : MonoBehaviour
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
game.PlayerDataStorage.PlayerKVGameplayLoop.FishingAction kvFishingAction;
|
||||||
|
bool KVFishingCurrent()
|
||||||
|
{
|
||||||
|
if(!game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled) return true;
|
||||||
|
return this!=null && isActiveAndEnabled && game.PlayerDataStorage.PlayerKVGameplayLoop.FishingCurrent(kvFishingAction);
|
||||||
|
}
|
||||||
|
void CancelKVFishing(string reason) => game.PlayerDataStorage.PlayerKVGameplayLoop.CancelFishing(kvFishingAction,reason);
|
||||||
|
void TrackKVCastTween(Tween tween)
|
||||||
|
{
|
||||||
|
if(!game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled) return;
|
||||||
|
var action=kvFishingAction;
|
||||||
|
bool completed=false;
|
||||||
|
tween.onComplete+=()=>completed=true;
|
||||||
|
tween.onKill+=()=> { if(!completed) game.PlayerDataStorage.PlayerKVGameplayLoop.CancelFishing(action,"cast tween killed"); };
|
||||||
|
}
|
||||||
|
async Task ConsumeBaitOnKVAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
if(!game.PlayerDataStorage.PlayerKVGameplayLoop.ClaimFishingConsumption(kvFishingAction)) return;
|
||||||
|
if(fishingData.fishItem==null || !fishingData.IsGeneralFish() || fishingData.IsFree || fishingData.IsRetry ||
|
||||||
|
fishingData.IsDuel || fishingData.IsPackItemFish() || fishingData.curFishData==null)
|
||||||
|
throw game.PlayerDataStorage.PlayerKVGameplayLoop.Stop("Only one ordinary paid fishing action is permitted. fishItem.ID="+(fishingData.fishItem==null?"null":fishingData.fishItem.ID.ToString())+", fishItem.SubType="+(fishingData.fishItem==null?"null":fishingData.fishItem.SubType.ToString())+", curFishData.ID="+(fishingData.curFishData==null?"null":fishingData.curFishData.ID.ToString())+", IsFree="+fishingData.IsFree+", IsRetry="+fishingData.IsRetry+", IsDuel="+fishingData.IsDuel);
|
||||||
|
if(Application.internetReachability==NetworkReachability.NotReachable)
|
||||||
|
throw game.PlayerDataStorage.PlayerKVGameplayLoop.Stop("Fishing stopped before consumption: offline.");
|
||||||
|
if(_tables.TbFishingEvent.DataList.Any(e=>e.ConditionList.Any(c=>c.Condition==ConditionType.ConsumeEnergy)))
|
||||||
|
throw game.PlayerDataStorage.PlayerKVGameplayLoop.Stop("ConsumeEnergy activity activation requires separate review.");
|
||||||
|
var player=GContext.container.Resolve<PlayerData>();
|
||||||
|
int mag=player.magnification;
|
||||||
|
if(mag<0 || mag>=_tables.TbEnergyDef.DataList.Count)
|
||||||
|
throw game.PlayerDataStorage.PlayerKVGameplayLoop.Stop("Invalid fishing magnification.");
|
||||||
|
int fish=fishingData.curFishData.ID, rod=fishingData.RodId, map=player.lastMapId;
|
||||||
|
int cost=_tables.TbEnergyDef.DataList[mag].Mag;
|
||||||
|
game.PlayerDataStorage.PlayerKVGameplayLoop.PrepareFishingReward(kvFishingAction,fishingData);
|
||||||
|
await player.ConsumeEnergyForKVLoopAsync(cost,kvFishingAction);
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
if(fishingData.curFishData==null || fishingData.curFishData.ID!=fish || fishingData.RodId!=rod ||
|
||||||
|
player.lastMapId!=map || (int)player.magnification!=mag || fishingData.IsFree || fishingData.IsRetry || fishingData.IsDuel)
|
||||||
|
throw game.PlayerDataStorage.PlayerKVGameplayLoop.Stop("Fishing context changed during confirmation.");
|
||||||
|
game.PlayerDataStorage.PlayerKVGameplayLoop.ContinueFishing(kvFishingAction,WaitForFishBiteED);
|
||||||
|
}
|
||||||
|
catch(Exception e) { game.PlayerDataStorage.PlayerKVGameplayLoop.Fault(e.Message); }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
IPlayerSaveStore saveStore;
|
||||||
Tables _tables;
|
Tables _tables;
|
||||||
[Header("RELATED OBJECT SETTINGS")]
|
[Header("RELATED OBJECT SETTINGS")]
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
@@ -166,6 +215,7 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
}
|
}
|
||||||
public void Init()
|
public void Init()
|
||||||
{
|
{
|
||||||
|
saveStore = GContext.container.Resolve<IPlayerSaveStore>();
|
||||||
fishingData = GContext.container.Resolve<FishingData>();
|
fishingData = GContext.container.Resolve<FishingData>();
|
||||||
fishingBehaviorConf = fishingData.fishingBehaviorConf;
|
fishingBehaviorConf = fishingData.fishingBehaviorConf;
|
||||||
collectingData = GContext.container.Resolve<CollectingData>();
|
collectingData = GContext.container.Resolve<CollectingData>();
|
||||||
@@ -213,7 +263,13 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
{
|
{
|
||||||
Addressables.ReleaseInstance(handAB);
|
Addressables.ReleaseInstance(handAB);
|
||||||
}
|
}
|
||||||
handAB = await Addressables.InstantiateAsync(gloveData.Fbx, transform).Task;
|
var loadedHand = await Addressables.InstantiateAsync(gloveData.Fbx, transform).Task;
|
||||||
|
if (this == null)
|
||||||
|
{
|
||||||
|
if (loadedHand != null) Addressables.ReleaseInstance(loadedHand);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
handAB = loadedHand;
|
||||||
if (handAB != null)
|
if (handAB != null)
|
||||||
{
|
{
|
||||||
HandController = handAB.GetComponent<HandController>();
|
HandController = handAB.GetComponent<HandController>();
|
||||||
@@ -225,7 +281,13 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
}
|
}
|
||||||
async void LoadBait()
|
async void LoadBait()
|
||||||
{
|
{
|
||||||
baitAB = await Addressables.InstantiateAsync("BaitRoot", _bait.transform).Task;
|
var loadedBait = await Addressables.InstantiateAsync("BaitRoot", _bait.transform).Task;
|
||||||
|
if (this == null)
|
||||||
|
{
|
||||||
|
if (loadedBait != null) Addressables.ReleaseInstance(loadedBait);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
baitAB = loadedBait;
|
||||||
baitAB.transform.localPosition = Vector3.zero;
|
baitAB.transform.localPosition = Vector3.zero;
|
||||||
baitAB.transform.localRotation = Quaternion.identity;
|
baitAB.transform.localRotation = Quaternion.identity;
|
||||||
baitAB.transform.localScale = Vector3.one;
|
baitAB.transform.localScale = Vector3.one;
|
||||||
@@ -421,10 +483,20 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
|
|
||||||
float FishingScale = fishRodSkinData.FishingScale;
|
float FishingScale = fishRodSkinData.FishingScale;
|
||||||
var goPrefab = await Addressables.LoadAssetAsync<GameObject>(path).Task;
|
var goPrefab = await Addressables.LoadAssetAsync<GameObject>(path).Task;
|
||||||
|
if (this == null)
|
||||||
|
{
|
||||||
|
if (goPrefab != null) Addressables.Release(goPrefab);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (goPrefab == null)
|
if (goPrefab == null)
|
||||||
{
|
{
|
||||||
Debug.LogError("Load Rod Elemental as Default Rod");
|
Debug.LogError("Load Rod Elemental as Default Rod");
|
||||||
goPrefab = await Addressables.LoadAssetAsync<GameObject>("Rod_elemental").Task;
|
goPrefab = await Addressables.LoadAssetAsync<GameObject>("Rod_elemental").Task;
|
||||||
|
if (this == null)
|
||||||
|
{
|
||||||
|
if (goPrefab != null) Addressables.Release(goPrefab);
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_bait.transform.SetParent(transform);
|
_bait.transform.SetParent(transform);
|
||||||
if (goPrefab != null)
|
if (goPrefab != null)
|
||||||
@@ -690,9 +762,25 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
//开始抛鱼线
|
//开始抛鱼线
|
||||||
public async void CastLineBehavior()
|
public async void CastLineBehavior()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var action=game.PlayerDataStorage.PlayerKVGameplayLoop.BeginFishing(this);
|
||||||
|
if(action==null) return;
|
||||||
|
kvFishingAction=action;
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
}
|
||||||
|
catch(Exception e) { game.PlayerDataStorage.PlayerKVGameplayLoop.Fault(e.Message); return; }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
//计算主画布分辨率下的宽高和屏幕的宽高的比列:
|
//计算主画布分辨率下的宽高和屏幕的宽高的比列:
|
||||||
fishingData.mainCamera.DOLocalRotateQuaternion(Quaternion.identity, 0.1f);
|
fishingData.mainCamera.DOLocalRotateQuaternion(Quaternion.identity, 0.1f);
|
||||||
await Awaiters.NextFrame;
|
await Awaiters.NextFrame;
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
CastBait();
|
CastBait();
|
||||||
//播放抛竿动画
|
//播放抛竿动画
|
||||||
@@ -703,12 +791,18 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
rodHandleAni.SetBool("_idle", false);
|
rodHandleAni.SetBool("_idle", false);
|
||||||
rodHandleAni.SetTrigger("_drawing");
|
rodHandleAni.SetTrigger("_drawing");
|
||||||
await Awaiters.Seconds(fishingBehaviorConf.audioDelay);
|
await Awaiters.Seconds(fishingBehaviorConf.audioDelay);
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
#endif
|
||||||
GContext.Publish(new EventFishingSound(SoundType.ThrowingAudio));
|
GContext.Publish(new EventFishingSound(SoundType.ThrowingAudio));
|
||||||
GContext.Publish(new VibrationData(1));
|
GContext.Publish(new VibrationData(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ConsumeBait()
|
private void ConsumeBait()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled) { _=ConsumeBaitOnKVAsync(); return; }
|
||||||
|
#endif
|
||||||
if (fishingData.IsFree)
|
if (fishingData.IsFree)
|
||||||
{
|
{
|
||||||
WaitForFishBiteED();
|
WaitForFishBiteED();
|
||||||
@@ -761,8 +855,8 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
{
|
{
|
||||||
GContext.Publish(new ConditionTypeEvent(ConditionType.ConsumeEnergy, energy));
|
GContext.Publish(new ConditionTypeEvent(ConditionType.ConsumeEnergy, energy));
|
||||||
}
|
}
|
||||||
var success = await PlayFabMgr.Instance.SyncDataImmidiate("NewPlayerDataDic",
|
var success = (await saveStore.WriteAndConfirmAsync("NewPlayerDataDic",
|
||||||
Newtonsoft.Json.JsonConvert.SerializeObject(commonDatas));
|
Newtonsoft.Json.JsonConvert.SerializeObject(commonDatas))).Confirmed;
|
||||||
Debug.Log($"[FishBehaviourB::ConsumeBaitOnPlayfab] {success}");
|
Debug.Log($"[FishBehaviourB::ConsumeBaitOnPlayfab] {success}");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -910,6 +1004,9 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
}
|
}
|
||||||
public void BaitMove()
|
public void BaitMove()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
#endif
|
||||||
flyEndPosTrue = _bait.transform.position;
|
flyEndPosTrue = _bait.transform.position;
|
||||||
|
|
||||||
GContext.Publish(new EventFishingSound(SoundType.audio_fishing_throwing_baitintowater));
|
GContext.Publish(new EventFishingSound(SoundType.audio_fishing_throwing_baitintowater));
|
||||||
@@ -920,9 +1017,12 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
var fishEffect = _effectDic["fx_fishing_splashloopwaiting"];
|
var fishEffect = _effectDic["fx_fishing_splashloopwaiting"];
|
||||||
float z = WaitingZ();
|
float z = WaitingZ();
|
||||||
float timer = Mathf.Lerp(fishingBehaviorConf.waitingLineDrawMinTime, fishingBehaviorConf.waitingLineDrawMaxTime, Random.value);
|
float timer = Mathf.Lerp(fishingBehaviorConf.waitingLineDrawMinTime, fishingBehaviorConf.waitingLineDrawMaxTime, Random.value);
|
||||||
_bait.transform.DOLocalMoveZ(z, timer).OnUpdate(
|
var waitingTween=_bait.transform.DOLocalMoveZ(z, timer).OnUpdate(
|
||||||
(() =>
|
(() =>
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
#endif
|
||||||
flyEndPosTrue = _bait.transform.position;
|
flyEndPosTrue = _bait.transform.position;
|
||||||
if (fishEffect)
|
if (fishEffect)
|
||||||
{
|
{
|
||||||
@@ -931,6 +1031,9 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
fishEffect.transform.position = vector;
|
fishEffect.transform.position = vector;
|
||||||
}
|
}
|
||||||
})); ;
|
})); ;
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
TrackKVCastTween(waitingTween);
|
||||||
|
#endif
|
||||||
StartCoroutine(WaitForFishBite(timer));
|
StartCoroutine(WaitForFishBite(timer));
|
||||||
}
|
}
|
||||||
IEnumerator PlayWaitingFx()
|
IEnumerator PlayWaitingFx()
|
||||||
@@ -953,6 +1056,9 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
}
|
}
|
||||||
private IEnumerator WaitForFishBite(float timer)
|
private IEnumerator WaitForFishBite(float timer)
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!KVFishingCurrent()) yield break;
|
||||||
|
#endif
|
||||||
EventFishingSound eventFishingSound1 = new EventFishingSound(SoundType.audio_fishing_waiting);
|
EventFishingSound eventFishingSound1 = new EventFishingSound(SoundType.audio_fishing_waiting);
|
||||||
EventFishingSound eventFishingSound2 = new EventFishingSound(SoundType.ReelingAudio, loop: true);
|
EventFishingSound eventFishingSound2 = new EventFishingSound(SoundType.ReelingAudio, loop: true);
|
||||||
|
|
||||||
@@ -962,6 +1068,9 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
timer += Mathf.Lerp(fishingBehaviorConf.waitingMinTime, fishingBehaviorConf.waitingMaxTime, Random.value) * (1 - EnhancedWaitingTime);
|
timer += Mathf.Lerp(fishingBehaviorConf.waitingMinTime, fishingBehaviorConf.waitingMaxTime, Random.value) * (1 - EnhancedWaitingTime);
|
||||||
|
|
||||||
yield return new WaitForSeconds(timer);
|
yield return new WaitForSeconds(timer);
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!KVFishingCurrent()) yield break;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (eventFishingSound2.Sound != null)
|
if (eventFishingSound2.Sound != null)
|
||||||
{
|
{
|
||||||
@@ -1085,18 +1194,27 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
}
|
}
|
||||||
private async void CastBait()
|
private async void CastBait()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
#endif
|
||||||
InitEffect();
|
InitEffect();
|
||||||
if (fishingBehaviorConf.fishFreeControlTime > 0f)
|
if (fishingBehaviorConf.fishFreeControlTime > 0f)
|
||||||
{
|
{
|
||||||
await new WaitForSeconds(fishingBehaviorConf.fishFreeControlTime);
|
await new WaitForSeconds(fishingBehaviorConf.fishFreeControlTime);
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
#endif
|
||||||
_isCastLine = true;
|
_isCastLine = true;
|
||||||
_bait.transform.SetParent(transform);
|
_bait.transform.SetParent(transform);
|
||||||
_bait.transform.DOMoveX(0, fishingBehaviorConf.flyToWaterTime);
|
var castX=_bait.transform.DOMoveX(0, fishingBehaviorConf.flyToWaterTime);
|
||||||
_bait.transform.DOMoveZ(fishingBehaviorConf.flyDistance, fishingBehaviorConf.flyToWaterTime).SetEase(fishingBehaviorConf.flyForwardCurve);
|
var castZ=_bait.transform.DOMoveZ(fishingBehaviorConf.flyDistance, fishingBehaviorConf.flyToWaterTime).SetEase(fishingBehaviorConf.flyForwardCurve);
|
||||||
_cameraAnimator.SetTrigger("_waiting");
|
_cameraAnimator.SetTrigger("_waiting");
|
||||||
_bait.transform.DOMoveY(_waterHeight, fishingBehaviorConf.flyToWaterTime)
|
var castY=_bait.transform.DOMoveY(_waterHeight, fishingBehaviorConf.flyToWaterTime)
|
||||||
.SetEase(fishingBehaviorConf.flyDownCurve).OnComplete((() =>
|
.SetEase(fishingBehaviorConf.flyDownCurve).OnComplete((() =>
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
#endif
|
||||||
fishingRodAnimator.SetTrigger("_waiting");
|
fishingRodAnimator.SetTrigger("_waiting");
|
||||||
GContext.Publish(ERightState.Waiting);
|
GContext.Publish(ERightState.Waiting);
|
||||||
LoadEffect("fx_fishing_splashinto");
|
LoadEffect("fx_fishing_splashinto");
|
||||||
@@ -1106,16 +1224,25 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
BaitMove();
|
BaitMove();
|
||||||
_bait.SetActive(false);
|
_bait.SetActive(false);
|
||||||
}));
|
}));
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
TrackKVCastTween(castX); TrackKVCastTween(castZ); TrackKVCastTween(castY);
|
||||||
|
#endif
|
||||||
AddLinePos();
|
AddLinePos();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
await new WaitForSeconds(1.15f);
|
await new WaitForSeconds(1.15f);
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
#endif
|
||||||
//当前动画_fishingRodAnimator播放时间
|
//当前动画_fishingRodAnimator播放时间
|
||||||
float time = fishingRodAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime;
|
float time = fishingRodAnimator.GetCurrentAnimatorStateInfo(0).normalizedTime;
|
||||||
_isCastLine = true;
|
_isCastLine = true;
|
||||||
_cameraAnimator.SetTrigger("_waiting");
|
_cameraAnimator.SetTrigger("_waiting");
|
||||||
await new WaitForSeconds(time);
|
await new WaitForSeconds(time);
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!KVFishingCurrent()) return;
|
||||||
|
#endif
|
||||||
_bait.transform.SetParent(transform);
|
_bait.transform.SetParent(transform);
|
||||||
_bait.SetActive(false);
|
_bait.SetActive(false);
|
||||||
//鱼漂位置
|
//鱼漂位置
|
||||||
@@ -1259,7 +1386,7 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
}
|
}
|
||||||
void SetIKTarget(Transform target)
|
void SetIKTarget(Transform target)
|
||||||
{
|
{
|
||||||
if (RodBehaviour.cCDIK)
|
if (RodBehaviour != null && RodBehaviour.cCDIK)
|
||||||
{
|
{
|
||||||
RodBehaviour.cCDIK.solver.target = target;
|
RodBehaviour.cCDIK.solver.target = target;
|
||||||
}
|
}
|
||||||
@@ -1896,6 +2023,9 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
_cameraAnimator.SetBool("_reeling", false);
|
_cameraAnimator.SetBool("_reeling", false);
|
||||||
fishingRodAnimator.SetBool("_pulling", false);
|
fishingRodAnimator.SetBool("_pulling", false);
|
||||||
CameraPullingEnd();
|
CameraPullingEnd();
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled && (!KVFishingCurrent() || !game.PlayerDataStorage.PlayerKVGameplayLoop.RewardCanAdvance)) yield break;
|
||||||
|
#endif
|
||||||
fishingData.IsCaughtFish = true;
|
fishingData.IsCaughtFish = true;
|
||||||
PlayCollectingEffect();
|
PlayCollectingEffect();
|
||||||
if (fx_fishing_splashwaveloop != null)
|
if (fx_fishing_splashwaveloop != null)
|
||||||
@@ -2308,6 +2438,9 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
|
|
||||||
private void OnDisable()
|
private void OnDisable()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
CancelKVFishing("disabled");
|
||||||
|
#endif
|
||||||
CloseAllEffect();
|
CloseAllEffect();
|
||||||
}
|
}
|
||||||
public void CloseAllEffect()
|
public void CloseAllEffect()
|
||||||
@@ -2331,6 +2464,9 @@ public partial class FishingBehaviorB : MonoBehaviour
|
|||||||
}
|
}
|
||||||
private void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
CancelKVFishing("destroyed");
|
||||||
|
#endif
|
||||||
disposables?.Dispose();
|
disposables?.Dispose();
|
||||||
disposables = null;
|
disposables = null;
|
||||||
foreach (var o in _effectDic)
|
foreach (var o in _effectDic)
|
||||||
|
|||||||
@@ -522,6 +522,22 @@ public class FishingUpdateSys : MonoBehaviour
|
|||||||
int isFailCount = 0;
|
int isFailCount = 0;
|
||||||
// 按了收线按钮
|
// 按了收线按钮
|
||||||
public void PiercingFish(int waitingZone)
|
public void PiercingFish(int waitingZone)
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!game.PlayerDataStorage.PlayerKVGameplayLoop.BeginRewardDrawing(this)) return;
|
||||||
|
using(game.PlayerDataStorage.PlayerKVGameplayLoop.BeginRewardSegment("strike")) PiercingFishCore(waitingZone);
|
||||||
|
}
|
||||||
|
catch(System.Exception e) { game.PlayerDataStorage.PlayerKVGameplayLoop.Fault(e.Message); }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
PiercingFishCore(waitingZone);
|
||||||
|
}
|
||||||
|
void PiercingFishCore(int waitingZone)
|
||||||
{
|
{
|
||||||
//waitingZone==100表示鱼没有开启刺鱼
|
//waitingZone==100表示鱼没有开启刺鱼
|
||||||
if (!fishingData.IsDrawing)
|
if (!fishingData.IsDrawing)
|
||||||
@@ -623,6 +639,9 @@ public class FishingUpdateSys : MonoBehaviour
|
|||||||
if (piercingToComboB > 0)
|
if (piercingToComboB > 0)
|
||||||
{
|
{
|
||||||
await Awaiters.Seconds(damageProtectionTime);
|
await Awaiters.Seconds(damageProtectionTime);
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!game.PlayerDataStorage.PlayerKVGameplayLoop.RewardCanAdvance) return;
|
||||||
|
#endif
|
||||||
_comboMultiplayer += Random.Range(piercingToComboA, piercingToComboB);
|
_comboMultiplayer += Random.Range(piercingToComboA, piercingToComboB);
|
||||||
//新技能生效 刺鱼触发全力收线进度
|
//新技能生效 刺鱼触发全力收线进度
|
||||||
PublishPerkEvent(RodPerkType.BattlePerk_PiercingToCombo);
|
PublishPerkEvent(RodPerkType.BattlePerk_PiercingToCombo);
|
||||||
@@ -632,6 +651,9 @@ public class FishingUpdateSys : MonoBehaviour
|
|||||||
public async void EternalDeath()
|
public async void EternalDeath()
|
||||||
{
|
{
|
||||||
await Awaiters.Seconds(damageProtectionTime);
|
await Awaiters.Seconds(damageProtectionTime);
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!game.PlayerDataStorage.PlayerKVGameplayLoop.RewardCanAdvance) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
StopAllCoroutines();
|
StopAllCoroutines();
|
||||||
OnFishingIsOver();
|
OnFishingIsOver();
|
||||||
@@ -1042,6 +1064,10 @@ public class FishingUpdateSys : MonoBehaviour
|
|||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!game.PlayerDataStorage.PlayerKVGameplayLoop.RewardCanAdvance) return;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (fishingData.IsDrawing)
|
if (fishingData.IsDrawing)
|
||||||
{
|
{
|
||||||
Vector3 fishPos = fishingBehavior.GetFishPos();
|
Vector3 fishPos = fishingBehavior.GetFishPos();
|
||||||
@@ -1219,6 +1245,34 @@ public class FishingUpdateSys : MonoBehaviour
|
|||||||
}
|
}
|
||||||
|
|
||||||
void FishEnd()
|
void FishEnd()
|
||||||
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if(!game.PlayerDataStorage.PlayerKVGameplayLoop.BeginRewardEnding(this,fishingData.IsCaughtFish && !isFail)) return;
|
||||||
|
using(game.PlayerDataStorage.PlayerKVGameplayLoop.BeginRewardSegment("ending")) FishEndCore();
|
||||||
|
_=ShowKVRewardPanelAsync();
|
||||||
|
}
|
||||||
|
catch(System.Exception e) { game.PlayerDataStorage.PlayerKVGameplayLoop.Fault(e.Message); }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
FishEndCore();
|
||||||
|
}
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
async Task ShowKVRewardPanelAsync()
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var panel=await UIManager.Instance.ShowUI(UITypes.FishingRewardPanel);
|
||||||
|
if(!game.PlayerDataStorage.PlayerKVGameplayLoop.RewardRunCurrent && panel!=null) Destroy(panel);
|
||||||
|
}
|
||||||
|
catch(System.Exception e) { game.PlayerDataStorage.PlayerKVGameplayLoop.Fault(e.Message); }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
void FishEndCore()
|
||||||
{
|
{
|
||||||
if (isFail)
|
if (isFail)
|
||||||
{
|
{
|
||||||
@@ -1297,6 +1351,9 @@ public class FishingUpdateSys : MonoBehaviour
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled) return; // Wrapper opens UI after S2 disposal.
|
||||||
|
#endif
|
||||||
_ = UIManager.Instance.ShowUI(UITypes.FishingRewardPanel);
|
_ = UIManager.Instance.ShowUI(UITypes.FishingRewardPanel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1746,6 +1803,15 @@ public class FishingUpdateSys : MonoBehaviour
|
|||||||
//全力收线
|
//全力收线
|
||||||
public async void FullCombo()
|
public async void FullCombo()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled)
|
||||||
|
{
|
||||||
|
if(!game.PlayerDataStorage.PlayerKVGameplayLoop.RewardCanAdvance) return;
|
||||||
|
try { game.PlayerDataStorage.PlayerKVGameplayLoop.CheckRewardGuide(); }
|
||||||
|
catch(System.Exception e) { game.PlayerDataStorage.PlayerKVGameplayLoop.Fault(e.Message); return; }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
if (_isCombo == 1 && curFishingStateName != FishingStateName.UIEating)
|
if (_isCombo == 1 && curFishingStateName != FishingStateName.UIEating)
|
||||||
{
|
{
|
||||||
if (comboToExDmg > 0 && comboToExDmgCount < curComboToExDmgCount)
|
if (comboToExDmg > 0 && comboToExDmgCount < curComboToExDmgCount)
|
||||||
@@ -1786,6 +1852,9 @@ public class FishingUpdateSys : MonoBehaviour
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
await Awaiters.Seconds(0.2f);
|
await Awaiters.Seconds(0.2f);
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(!game.PlayerDataStorage.PlayerKVGameplayLoop.RewardCanAdvance) return;
|
||||||
|
#endif
|
||||||
lockCombo = false;
|
lockCombo = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3130,6 +3199,10 @@ public class FishingUpdateSys : MonoBehaviour
|
|||||||
}
|
}
|
||||||
private void OnDisable()
|
private void OnDisable()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
game.PlayerDataStorage.PlayerKVGameplayLoop.CancelReward(this,"controller disabled");
|
||||||
|
#endif
|
||||||
|
|
||||||
StopSoundCombo();
|
StopSoundCombo();
|
||||||
StopRodAudio();
|
StopRodAudio();
|
||||||
StopNotReeling();
|
StopNotReeling();
|
||||||
@@ -3176,6 +3249,10 @@ public class FishingUpdateSys : MonoBehaviour
|
|||||||
}
|
}
|
||||||
private void OnDestroy()
|
private void OnDestroy()
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
game.PlayerDataStorage.PlayerKVGameplayLoop.CancelReward(this,"controller destroyed");
|
||||||
|
#endif
|
||||||
|
|
||||||
disposables?.Dispose();
|
disposables?.Dispose();
|
||||||
_comboDisposable?.Dispose();
|
_comboDisposable?.Dispose();
|
||||||
_hpcoroutine = null;
|
_hpcoroutine = null;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
@@ -6,6 +6,8 @@ using UnityEngine;
|
|||||||
|
|
||||||
public class InfiniteBuildingData
|
public class InfiniteBuildingData
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
public int Lvl, Step, StepLvl = 1, LastHangingBlock = -1;
|
public int Lvl, Step, StepLvl = 1, LastHangingBlock = -1;
|
||||||
public List<BlockRecord> Record = new List<BlockRecord>();
|
public List<BlockRecord> Record = new List<BlockRecord>();
|
||||||
// private readonly TbConstructionUnits BlocksTable = GContext.container.Resolve<Tables>().TbConstructionUnits;
|
// private readonly TbConstructionUnits BlocksTable = GContext.container.Resolve<Tables>().TbConstructionUnits;
|
||||||
@@ -64,7 +66,7 @@ public class InfiniteBuildingData
|
|||||||
//Debug.Log("Upload!!!!!!!!!!!!!!");
|
//Debug.Log("Upload!!!!!!!!!!!!!!");
|
||||||
//Debug.Log(s);
|
//Debug.Log(s);
|
||||||
GContext.container.Resolve<PlayerData>().InfiniteBuildingData = s;
|
GContext.container.Resolve<PlayerData>().InfiniteBuildingData = s;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("InfiniteBuildingData", s);
|
saveStore.Write("InfiniteBuildingData", s).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void DownloadData(string s)
|
public void DownloadData(string s)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
@@ -9,6 +9,8 @@ using UnityEngine;
|
|||||||
|
|
||||||
public class LuckyADTaskPopupPanel : LuckyTaskPanelBase
|
public class LuckyADTaskPopupPanel : LuckyTaskPanelBase
|
||||||
{
|
{
|
||||||
|
game.PlayerDataStorage.IPlayerSaveStore saveStore;
|
||||||
|
|
||||||
List<LuckyTaskItemData> taskList;
|
List<LuckyTaskItemData> taskList;
|
||||||
List<LuckyADTaskItem> taskItems = new List<LuckyADTaskItem>();
|
List<LuckyADTaskItem> taskItems = new List<LuckyADTaskItem>();
|
||||||
List<LuckyADTaskItemData> taskADList = new List<LuckyADTaskItemData>();
|
List<LuckyADTaskItemData> taskADList = new List<LuckyADTaskItemData>();
|
||||||
@@ -18,6 +20,7 @@ public class LuckyADTaskPopupPanel : LuckyTaskPanelBase
|
|||||||
System.DateTime refreshTime;
|
System.DateTime refreshTime;
|
||||||
protected override void Awake()
|
protected override void Awake()
|
||||||
{
|
{
|
||||||
|
saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
base.Awake();
|
base.Awake();
|
||||||
luckyTaskItem = transform.Find("root/hook_missions_object").GetComponent<LuckyADTask>();
|
luckyTaskItem = transform.Find("root/hook_missions_object").GetComponent<LuckyADTask>();
|
||||||
text_time = transform.Find("root/text_time").GetComponent<TMP_Text>();
|
text_time = transform.Find("root/text_time").GetComponent<TMP_Text>();
|
||||||
@@ -120,7 +123,7 @@ public class LuckyADTaskPopupPanel : LuckyTaskPanelBase
|
|||||||
int round = taskData.GetValueOrDefault(-1, 0);
|
int round = taskData.GetValueOrDefault(-1, 0);
|
||||||
float inflationRate = taskData.GetValueOrDefault(-3, 0) / 100f;
|
float inflationRate = taskData.GetValueOrDefault(-3, 0) / 100f;
|
||||||
int group = taskData.GetValueOrDefault(-4, 0);
|
int group = taskData.GetValueOrDefault(-4, 0);
|
||||||
string adData = PlayFabMgr.Instance.GetLocalData(LuckyTaskData.ADTaskADKey);
|
string adData = saveStore.Read(LuckyTaskData.ADTaskADKey).ValueOrThrow();
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int curDay = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
int curDay = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
||||||
if (!string.IsNullOrEmpty(adData))
|
if (!string.IsNullOrEmpty(adData))
|
||||||
@@ -134,13 +137,13 @@ public class LuckyADTaskPopupPanel : LuckyTaskPanelBase
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
adData = $"{index}|{curDay}";
|
adData = $"{index}|{curDay}";
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(LuckyTaskData.ADTaskADKey, adData);
|
saveStore.Write(LuckyTaskData.ADTaskADKey, adData).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
adData = $"{index}|{curDay}";
|
adData = $"{index}|{curDay}";
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(LuckyTaskData.ADTaskADKey, adData);
|
saveStore.Write(LuckyTaskData.ADTaskADKey, adData).RequireAccepted();
|
||||||
}
|
}
|
||||||
List<LuckyADTaskItemData> taskADList = new List<LuckyADTaskItemData>();
|
List<LuckyADTaskItemData> taskADList = new List<LuckyADTaskItemData>();
|
||||||
TbEventLuckyTask eventLuckyTask = LuckyTaskData.GetTbEventLuckyTask(luckyModel.EventId, round, group);
|
TbEventLuckyTask eventLuckyTask = LuckyTaskData.GetTbEventLuckyTask(luckyModel.EventId, round, group);
|
||||||
@@ -180,7 +183,7 @@ public class LuckyADTaskPopupPanel : LuckyTaskPanelBase
|
|||||||
|
|
||||||
luckyADTaskItem.Play();
|
luckyADTaskItem.Play();
|
||||||
|
|
||||||
string adData = PlayFabMgr.Instance.GetLocalData(LuckyTaskData.ADTaskADKey);
|
string adData = saveStore.Read(LuckyTaskData.ADTaskADKey).ValueOrThrow();
|
||||||
int index = 0;
|
int index = 0;
|
||||||
int day = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
int day = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
||||||
if (!string.IsNullOrEmpty(adData))
|
if (!string.IsNullOrEmpty(adData))
|
||||||
@@ -195,7 +198,7 @@ public class LuckyADTaskPopupPanel : LuckyTaskPanelBase
|
|||||||
//保存进度
|
//保存进度
|
||||||
index++;
|
index++;
|
||||||
adData = $"{index}|{day}";
|
adData = $"{index}|{day}";
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(LuckyTaskData.ADTaskADKey, adData);
|
saveStore.Write(LuckyTaskData.ADTaskADKey, adData).RequireAccepted();
|
||||||
RefreshADItemState(index);
|
RefreshADItemState(index);
|
||||||
canvasGroup.blocksRaycasts = true;
|
canvasGroup.blocksRaycasts = true;
|
||||||
GContext.Publish(new ShowData());
|
GContext.Publish(new ShowData());
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using TMPro;
|
using TMPro;
|
||||||
@@ -6,6 +7,8 @@ using UnityEngine.UI;
|
|||||||
|
|
||||||
public class LuckyTaskBtn : MonoBehaviour, IUIRedPoint
|
public class LuckyTaskBtn : MonoBehaviour, IUIRedPoint
|
||||||
{
|
{
|
||||||
|
game.PlayerDataStorage.IPlayerSaveStore saveStore;
|
||||||
|
|
||||||
Button btn;
|
Button btn;
|
||||||
ILuckyTaskGetData model;
|
ILuckyTaskGetData model;
|
||||||
|
|
||||||
@@ -15,6 +18,7 @@ public class LuckyTaskBtn : MonoBehaviour, IUIRedPoint
|
|||||||
public TMP_Text text_redpoint_big;
|
public TMP_Text text_redpoint_big;
|
||||||
void Awake()
|
void Awake()
|
||||||
{
|
{
|
||||||
|
saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
btn = GetComponent<Button>();
|
btn = GetComponent<Button>();
|
||||||
btn.onClick.AddListener(OnClick);
|
btn.onClick.AddListener(OnClick);
|
||||||
}
|
}
|
||||||
@@ -29,6 +33,7 @@ public class LuckyTaskBtn : MonoBehaviour, IUIRedPoint
|
|||||||
if (model != null)
|
if (model != null)
|
||||||
{
|
{
|
||||||
GameObject taskPanelName = await UIManager.Instance.ShowUI(new UIType(model.TaskPanelName));
|
GameObject taskPanelName = await UIManager.Instance.ShowUI(new UIType(model.TaskPanelName));
|
||||||
|
if (this == null || !saveStore.IsCurrent) return;
|
||||||
if (taskPanelName != null)
|
if (taskPanelName != null)
|
||||||
{
|
{
|
||||||
var panel = taskPanelName.GetComponent<LuckyTaskPanelBase>();
|
var panel = taskPanelName.GetComponent<LuckyTaskPanelBase>();
|
||||||
@@ -61,7 +66,7 @@ public class LuckyTaskBtn : MonoBehaviour, IUIRedPoint
|
|||||||
int count = RedPointManager.Instance.GetRedPointCount(key);
|
int count = RedPointManager.Instance.GetRedPointCount(key);
|
||||||
if (!state)
|
if (!state)
|
||||||
{
|
{
|
||||||
string adData = PlayFabMgr.Instance.GetLocalData(LuckyTaskData.ADTaskADKey);
|
string adData = saveStore.Read(LuckyTaskData.ADTaskADKey).ValueOrThrow();
|
||||||
if (!string.IsNullOrEmpty(adData))
|
if (!string.IsNullOrEmpty(adData))
|
||||||
{
|
{
|
||||||
string[] strings = adData.Split("|");
|
string[] strings = adData.Split("|");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
@@ -7,13 +7,21 @@ using UnityEngine;
|
|||||||
|
|
||||||
public class LuckyTaskPanel : LuckyTaskPanelBase
|
public class LuckyTaskPanel : LuckyTaskPanelBase
|
||||||
{
|
{
|
||||||
|
protected override void Awake()
|
||||||
|
{
|
||||||
|
saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
base.Awake();
|
||||||
|
}
|
||||||
|
|
||||||
|
game.PlayerDataStorage.IPlayerSaveStore saveStore;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// luckyModel 也作为是否自动全部领奖的标志
|
/// luckyModel 也作为是否自动全部领奖的标志
|
||||||
/// </summary>
|
/// </summary>
|
||||||
List<LuckyTaskItem> taskItems = new List<LuckyTaskItem>();
|
List<LuckyTaskItem> taskItems = new List<LuckyTaskItem>();
|
||||||
protected override void SetItem()
|
protected override void SetItem()
|
||||||
{
|
{
|
||||||
string adData = PlayFabMgr.Instance.GetLocalData(LuckyTaskData.ADTaskADKey);
|
string adData = saveStore.Read(LuckyTaskData.ADTaskADKey).ValueOrThrow();
|
||||||
int curDay = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
int curDay = ZZTimeHelper.UtcNow().UtcNowOffset().DayOfYear;
|
||||||
if (!string.IsNullOrEmpty(adData))
|
if (!string.IsNullOrEmpty(adData))
|
||||||
{
|
{
|
||||||
@@ -22,13 +30,13 @@ public class LuckyTaskPanel : LuckyTaskPanelBase
|
|||||||
if (strings.Length != 2 || !int.TryParse(strings[1], out day) || day != curDay)
|
if (strings.Length != 2 || !int.TryParse(strings[1], out day) || day != curDay)
|
||||||
{
|
{
|
||||||
adData = $"{0}|{curDay}";
|
adData = $"{0}|{curDay}";
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(LuckyTaskData.ADTaskADKey, adData);
|
saveStore.Write(LuckyTaskData.ADTaskADKey, adData).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
adData = $"{0}|{curDay}";
|
adData = $"{0}|{curDay}";
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(LuckyTaskData.ADTaskADKey, adData);
|
saveStore.Write(LuckyTaskData.ADTaskADKey, adData).RequireAccepted();
|
||||||
}
|
}
|
||||||
List<LuckyTaskItemData> taskList = new List<LuckyTaskItemData>();
|
List<LuckyTaskItemData> taskList = new List<LuckyTaskItemData>();
|
||||||
int level = taskData.GetValueOrDefault(-2, 0);
|
int level = taskData.GetValueOrDefault(-2, 0);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using LitJson;
|
using LitJson;
|
||||||
@@ -36,6 +36,8 @@ public enum FlipResult
|
|||||||
|
|
||||||
public class EventMatchGameManager
|
public class EventMatchGameManager
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
public string EventMatchGameDataKey => "EventMatchGameDataKey";
|
public string EventMatchGameDataKey => "EventMatchGameDataKey";
|
||||||
public int ItemSubType => 3;
|
public int ItemSubType => 3;
|
||||||
public int ItemType => 6;
|
public int ItemType => 6;
|
||||||
@@ -59,7 +61,7 @@ public class EventMatchGameManager
|
|||||||
{
|
{
|
||||||
var matchGameData = new MatchGameData();
|
var matchGameData = new MatchGameData();
|
||||||
|
|
||||||
string data = PlayFabMgr.Instance.GetLocalData(EventMatchGameDataKey);
|
string data = saveStore.Read(EventMatchGameDataKey).ValueOrThrow();
|
||||||
if (!string.IsNullOrEmpty(data))
|
if (!string.IsNullOrEmpty(data))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -491,7 +493,7 @@ public class EventMatchGameManager
|
|||||||
|
|
||||||
public void SaveData(MatchGameData matchGameData)
|
public void SaveData(MatchGameData matchGameData)
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(EventMatchGameDataKey, JsonMapper.ToJson(matchGameData));
|
saveStore.Write(EventMatchGameDataKey, JsonMapper.ToJson(matchGameData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
@@ -53,6 +53,8 @@ public interface IMiniBattlePassDataProvider
|
|||||||
|
|
||||||
public class MiniBattlePassDataProvider : IMiniBattlePassDataProvider
|
public class MiniBattlePassDataProvider : IMiniBattlePassDataProvider
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
private Tables _tables;
|
private Tables _tables;
|
||||||
PlayerItemData _playerItemData;
|
PlayerItemData _playerItemData;
|
||||||
string newDataKey => "MiniBPKeyNew";
|
string newDataKey => "MiniBPKeyNew";
|
||||||
@@ -138,10 +140,11 @@ public class MiniBattlePassDataProvider : IMiniBattlePassDataProvider
|
|||||||
|
|
||||||
public MiniBattlePassRecord GetMiniBattlePassRecord(string key)
|
public MiniBattlePassRecord GetMiniBattlePassRecord(string key)
|
||||||
{
|
{
|
||||||
|
if (!saveStore.IsCurrent) throw new System.InvalidOperationException("Expired battle pass session.");
|
||||||
MiniBattlePassRecord Data;
|
MiniBattlePassRecord Data;
|
||||||
if (datas == null)
|
if (datas == null)
|
||||||
{
|
{
|
||||||
string dataStr = PlayFabMgr.Instance.GetLocalData(newDataKey);
|
string dataStr = saveStore.Read(newDataKey).ValueOrThrow();
|
||||||
//Debug.Log($"GetMiniBattlePassRecord: dataStr = {dataStr}");
|
//Debug.Log($"GetMiniBattlePassRecord: dataStr = {dataStr}");
|
||||||
if (string.IsNullOrEmpty(dataStr))
|
if (string.IsNullOrEmpty(dataStr))
|
||||||
{
|
{
|
||||||
@@ -168,7 +171,7 @@ public class MiniBattlePassDataProvider : IMiniBattlePassDataProvider
|
|||||||
public void SetMiniBattlePassRecord(string key, MiniBattlePassRecord record)
|
public void SetMiniBattlePassRecord(string key, MiniBattlePassRecord record)
|
||||||
{
|
{
|
||||||
datas[key] = record;
|
datas[key] = record;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(newDataKey, JsonConvert.SerializeObject(datas));
|
saveStore.Write(newDataKey, JsonConvert.SerializeObject(datas)).RequireAccepted();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public class MiniBattlePassProgressInfo
|
public class MiniBattlePassProgressInfo
|
||||||
|
|||||||
@@ -101,7 +101,7 @@ public class ZZTimeHelper
|
|||||||
HttpClient client = new HttpClient();
|
HttpClient client = new HttpClient();
|
||||||
client.Timeout = TimeSpan.FromSeconds(5);
|
client.Timeout = TimeSpan.FromSeconds(5);
|
||||||
IConfig config = GContext.container.Resolve<IConfig>();
|
IConfig config = GContext.container.Resolve<IConfig>();
|
||||||
string apiUrl = config.Get<string>(GConstant.K_Event_API_URL, "http://192.168.9.101:5292/");
|
string apiUrl = config.Get<string>(GConstant.K_Event_API_URL, "http://s101.local:18080/");
|
||||||
string url = $"{apiUrl}account/svrtime";
|
string url = $"{apiUrl}account/svrtime";
|
||||||
var svrTimeStr = await client.GetStringAsync(url);
|
var svrTimeStr = await client.GetStringAsync(url);
|
||||||
// var svrTimeStr = await client.GetStringAsync(timeUrl);
|
// var svrTimeStr = await client.GetStringAsync(timeUrl);
|
||||||
|
|||||||
@@ -27,6 +27,26 @@ namespace Script.RuntimeScript
|
|||||||
private DiggingGameModel _dataModel;
|
private DiggingGameModel _dataModel;
|
||||||
public DiggingGameModel DataModel => _dataModel;
|
public DiggingGameModel DataModel => _dataModel;
|
||||||
|
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVEmptyModuleState DecodeForKVLoad() =>
|
||||||
|
game.PlayerDataStorage.PlayerKVEmptyModuleState.Instance;
|
||||||
|
internal bool CanResetForKVLoad => _monoBehaviour==null && _digAni==null && _cameraVir==null && _tables==null &&
|
||||||
|
fx_DgSanddig==null && fx_DgSanddighard==null && fx_DgSanddisappear==null && diggingMoveCurve==null &&
|
||||||
|
_broadLogic==null && _broadContainer==null && _gridContianer==null && _gridPropContianer==null &&
|
||||||
|
_propContainer==null && _showPropPositon==null && _explosionManager==null && sanddig_dig_sound==null &&
|
||||||
|
sanddig_dig_audio==null && sanddig_dighard_audio==null && _fxRoot==null && _onCloseAwardPanel==null &&
|
||||||
|
(_dataModel==null || (_dataModel.CurActivityId==0 && _dataModel.digActivityConfig==null && _dataModel.AllClamps.Count==0));
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
if(!CanResetForKVLoad) throw new InvalidOperationException("KV digging module is active.");
|
||||||
|
_dataModel=new DiggingGameModel(); _broadLogic=null; _gameState=SandDigGameState.Normal;
|
||||||
|
IsCanClick=true; ClampIsPass=false; itemDatas=new List<ItemData>(); _awardPanelIsOpen=false;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVEmptyModuleState state)
|
||||||
|
{
|
||||||
|
if(state==null) throw new ArgumentNullException(nameof(state));
|
||||||
|
if(!CanResetForKVLoad || _dataModel==null) throw new InvalidOperationException("KV digging reset required.");
|
||||||
|
}
|
||||||
|
|
||||||
private Animation _digAni;
|
private Animation _digAni;
|
||||||
|
|
||||||
private CinemachineVirtualCamera _cameraVir;
|
private CinemachineVirtualCamera _cameraVir;
|
||||||
@@ -785,4 +805,4 @@ namespace Script.RuntimeScript
|
|||||||
Special,
|
Special,
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
@@ -15,6 +15,8 @@ using UnityEngine.ResourceManagement.AsyncOperations;
|
|||||||
|
|
||||||
public class DiggingGameModel
|
public class DiggingGameModel
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
#region 协议Const区域
|
#region 协议Const区域
|
||||||
|
|
||||||
//工具个数
|
//工具个数
|
||||||
@@ -78,8 +80,8 @@ public class DiggingGameModel
|
|||||||
redDot = cycle.RedDot;
|
redDot = cycle.RedDot;
|
||||||
}
|
}
|
||||||
DiggingGameManager.LogError("沙滩寻宝开启");
|
DiggingGameManager.LogError("沙滩寻宝开启");
|
||||||
string countJson = PlayFabMgr.Instance.GetLocalData(DigCountKey);
|
string countJson = saveStore.Read(DigCountKey).ValueOrThrow();
|
||||||
string digGridDataJson = PlayFabMgr.Instance.GetLocalData(DigGridDataKey);
|
string digGridDataJson = saveStore.Read(DigGridDataKey).ValueOrThrow();
|
||||||
if (string.IsNullOrEmpty(countJson))
|
if (string.IsNullOrEmpty(countJson))
|
||||||
{
|
{
|
||||||
SaveNull();
|
SaveNull();
|
||||||
@@ -105,8 +107,8 @@ public class DiggingGameModel
|
|||||||
MaxCount = digActivityConfig.StageCount;
|
MaxCount = digActivityConfig.StageCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
string countJson = PlayFabMgr.Instance.GetLocalData(DigCountKey);
|
string countJson = saveStore.Read(DigCountKey).ValueOrThrow();
|
||||||
string digGridDataJson = PlayFabMgr.Instance.GetLocalData(DigGridDataKey);
|
string digGridDataJson = saveStore.Read(DigGridDataKey).ValueOrThrow();
|
||||||
DoServerData(countJson, digGridDataJson);
|
DoServerData(countJson, digGridDataJson);
|
||||||
await InitClientData(ClientDataHandleEnum.Init);
|
await InitClientData(ClientDataHandleEnum.Init);
|
||||||
}
|
}
|
||||||
@@ -460,7 +462,7 @@ public class DiggingGameModel
|
|||||||
dataJson.ActivityId = _curActivityId;
|
dataJson.ActivityId = _curActivityId;
|
||||||
dataJson.DigCount = _serverDigCount;
|
dataJson.DigCount = _serverDigCount;
|
||||||
string json = JsonConvert.SerializeObject(dataJson);
|
string json = JsonConvert.SerializeObject(dataJson);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(DigCountKey, json);
|
saveStore.Write(DigCountKey, json).RequireAccepted();
|
||||||
GContext.container.Resolve<FishingEventData>().SaveTransitionData(dataJson.ActivityId, dataJson.DigCount);
|
GContext.container.Resolve<FishingEventData>().SaveTransitionData(dataJson.ActivityId, dataJson.DigCount);
|
||||||
}
|
}
|
||||||
void SetRedPoint()
|
void SetRedPoint()
|
||||||
@@ -493,7 +495,7 @@ public class DiggingGameModel
|
|||||||
|
|
||||||
string json = JsonConvert.SerializeObject(dataJson);
|
string json = JsonConvert.SerializeObject(dataJson);
|
||||||
//DiggingGameManager.LogError(json);
|
//DiggingGameManager.LogError(json);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(DigGridDataKey, json);
|
saveStore.Write(DigGridDataKey, json).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveAll()
|
public void SaveAll()
|
||||||
@@ -509,7 +511,7 @@ public class DiggingGameModel
|
|||||||
{
|
{
|
||||||
_serverDigCount = GContext.container.Resolve<FishingEventData>().GetInitWelcomeGift(_curActivityId);
|
_serverDigCount = GContext.container.Resolve<FishingEventData>().GetInitWelcomeGift(_curActivityId);
|
||||||
SaveDigCount();
|
SaveDigCount();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(DigGridDataKey, string.Empty);
|
saveStore.Write(DigGridDataKey, string.Empty).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
8
Client/Assets/Scripts/Services/Account.meta
Normal file
8
Client/Assets/Scripts/Services/Account.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4930c4a417ba4c908416717d26695848
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
224
Client/Assets/Scripts/Services/Account/S101AccountSession.cs
Normal file
224
Client/Assets/Scripts/Services/Account/S101AccountSession.cs
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
using System;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.IO;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
|
namespace game.Account
|
||||||
|
{
|
||||||
|
public enum AccountLoginError { None, Validation, Http, Rejected, Protocol, Network, Timeout, Cancelled }
|
||||||
|
|
||||||
|
public sealed class AccountLoginResult
|
||||||
|
{
|
||||||
|
public bool Success => Error == AccountLoginError.None;
|
||||||
|
public AccountLoginError Error { get; }
|
||||||
|
public int? StatusCode { get; }
|
||||||
|
internal AccountLoginResult(AccountLoginError error, int? status = null)
|
||||||
|
{ Error = error; StatusCode = status; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Minimal Tuyou-ID authentication, independent of gameplay and PlayFab storage.
|
||||||
|
/// Each login owns a fresh cookie jar; dispose the session on logout.
|
||||||
|
/// </summary>
|
||||||
|
public sealed class S101AccountSession : IDisposable
|
||||||
|
{
|
||||||
|
public const string DefaultApiUrl = "http://s101.local:18080/";
|
||||||
|
readonly object gate = new object();
|
||||||
|
readonly Uri api;
|
||||||
|
readonly Func<CookieContainer, HttpMessageHandler> handlerFactory;
|
||||||
|
HttpClient http;
|
||||||
|
int generation;
|
||||||
|
bool disposed;
|
||||||
|
|
||||||
|
public bool IsAuthenticated { get; private set; }
|
||||||
|
public string PlayerId { get; private set; }
|
||||||
|
public uint InternalId { get; private set; }
|
||||||
|
public DateTime CreateTimeUtc { get; private set; }
|
||||||
|
public DateTime ServerTimeUtc { get; private set; }
|
||||||
|
public bool NewlyCreated { get; private set; }
|
||||||
|
public CookieContainer Cookies { get; private set; }
|
||||||
|
public Uri ApiBaseUri => api;
|
||||||
|
|
||||||
|
public S101AccountSession() : this(new Uri(DefaultApiUrl)) { }
|
||||||
|
|
||||||
|
// The factory is optional for transport tests. Returned handlers are owned by this session.
|
||||||
|
public S101AccountSession(Uri api, Func<CookieContainer, HttpMessageHandler> handlerFactory = null)
|
||||||
|
{
|
||||||
|
if (api == null || !api.IsAbsoluteUri ||
|
||||||
|
(api.Scheme != "http" && api.Scheme != "https") ||
|
||||||
|
!string.IsNullOrEmpty(api.Query) || !string.IsNullOrEmpty(api.Fragment) ||
|
||||||
|
!string.IsNullOrEmpty(api.UserInfo))
|
||||||
|
throw new ArgumentException("An absolute HTTP(S) API base URI is required.", nameof(api));
|
||||||
|
this.api = new Uri(api.AbsoluteUri.TrimEnd('/') + "/");
|
||||||
|
this.handlerFactory = handlerFactory ?? (jar => new HttpClientHandler
|
||||||
|
{
|
||||||
|
CookieContainer = jar, UseCookies = true, AllowAutoRedirect = false
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<AccountLoginResult> LoginAsync(string tuyooId, CancellationToken token = default)
|
||||||
|
{
|
||||||
|
HttpClient client;
|
||||||
|
CookieContainer cookies;
|
||||||
|
int requestGeneration;
|
||||||
|
string id;
|
||||||
|
lock (gate)
|
||||||
|
{
|
||||||
|
if (disposed) return Result(AccountLoginError.Cancelled);
|
||||||
|
generation++;
|
||||||
|
ClearIdentity();
|
||||||
|
http?.Dispose();
|
||||||
|
http = null;
|
||||||
|
Cookies = null;
|
||||||
|
if (string.IsNullOrEmpty(tuyooId) ||
|
||||||
|
!long.TryParse(tuyooId, NumberStyles.None, CultureInfo.InvariantCulture, out var numericId) || numericId <= 0)
|
||||||
|
return Result(AccountLoginError.Validation);
|
||||||
|
if (token.IsCancellationRequested) return Result(AccountLoginError.Cancelled);
|
||||||
|
id = numericId.ToString(CultureInfo.InvariantCulture);
|
||||||
|
cookies = new CookieContainer();
|
||||||
|
client = new HttpClient(handlerFactory(cookies)) { Timeout = TimeSpan.FromSeconds(15) };
|
||||||
|
http = client;
|
||||||
|
Cookies = cookies;
|
||||||
|
requestGeneration = generation;
|
||||||
|
}
|
||||||
|
|
||||||
|
int? status = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var request = Request("account/Login", new JObject { ["playerId"] = id }))
|
||||||
|
using (var response = await client.SendAsync(request, token))
|
||||||
|
{
|
||||||
|
status = (int)response.StatusCode;
|
||||||
|
if (response.StatusCode != HttpStatusCode.OK) return Result(AccountLoginError.Http, status);
|
||||||
|
var body = Parse(await response.Content.ReadAsStringAsync());
|
||||||
|
if (body["state"]?.Type != JTokenType.Integer) return Result(AccountLoginError.Protocol, status);
|
||||||
|
if (body["state"].Value<long>() != 0) return Result(AccountLoginError.Rejected, status);
|
||||||
|
if (body["internalId"]?.Type != JTokenType.Integer ||
|
||||||
|
!uint.TryParse(body["internalId"].ToString(), out var internalId) || internalId == 0 ||
|
||||||
|
body["newCreate"]?.Type != JTokenType.Boolean ||
|
||||||
|
!ReadUtc(body["createTime"], out var created) || !ReadUtc(body["svrTime"], out var serverTime) ||
|
||||||
|
cookies.GetCookies(api).Count == 0)
|
||||||
|
return Result(AccountLoginError.Protocol, status);
|
||||||
|
lock (gate)
|
||||||
|
{
|
||||||
|
if (disposed || generation != requestGeneration || token.IsCancellationRequested)
|
||||||
|
return Result(AccountLoginError.Cancelled, status);
|
||||||
|
PlayerId = id;
|
||||||
|
InternalId = internalId;
|
||||||
|
CreateTimeUtc = created;
|
||||||
|
ServerTimeUtc = serverTime;
|
||||||
|
NewlyCreated = body["newCreate"].Value<bool>();
|
||||||
|
IsAuthenticated = true;
|
||||||
|
}
|
||||||
|
return Result(AccountLoginError.None, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
lock (gate)
|
||||||
|
return Result(disposed || generation != requestGeneration || token.IsCancellationRequested
|
||||||
|
? AccountLoginError.Cancelled : AccountLoginError.Timeout, status);
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException) { return Result(AccountLoginError.Cancelled, status); }
|
||||||
|
catch (HttpRequestException) { return Result(AccountLoginError.Network, status); }
|
||||||
|
catch (JsonException) { return Result(AccountLoginError.Protocol, status); }
|
||||||
|
catch (OverflowException) { return Result(AccountLoginError.Protocol, status); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Read-only probe: verifies that the server accepts this session cookie; never writes KV.</summary>
|
||||||
|
public async Task<AccountLoginResult> CheckAuthorizationAsync(CancellationToken token = default)
|
||||||
|
{
|
||||||
|
HttpClient client;
|
||||||
|
int requestGeneration;
|
||||||
|
lock (gate)
|
||||||
|
{
|
||||||
|
if (disposed || !IsAuthenticated) return Result(AccountLoginError.Rejected);
|
||||||
|
client = http;
|
||||||
|
requestGeneration = generation;
|
||||||
|
}
|
||||||
|
int? status = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
using (var request = Request("playerdata/Get", new JObject()))
|
||||||
|
using (var response = await client.SendAsync(request, token))
|
||||||
|
{
|
||||||
|
status = (int)response.StatusCode;
|
||||||
|
lock (gate)
|
||||||
|
{
|
||||||
|
if (disposed || generation != requestGeneration || token.IsCancellationRequested)
|
||||||
|
return Result(AccountLoginError.Cancelled, status);
|
||||||
|
if (status == 401 || status == 403) ClearIdentity();
|
||||||
|
}
|
||||||
|
if (response.StatusCode != HttpStatusCode.OK) return Result(AccountLoginError.Http, status);
|
||||||
|
var body = Parse(await response.Content.ReadAsStringAsync());
|
||||||
|
if (!(body["data"] is JObject data)) return Result(AccountLoginError.Protocol, status);
|
||||||
|
foreach (var item in data.Properties())
|
||||||
|
if (item.Value.Type != JTokenType.String) return Result(AccountLoginError.Protocol, status);
|
||||||
|
lock (gate)
|
||||||
|
return Result(disposed || generation != requestGeneration || token.IsCancellationRequested
|
||||||
|
? AccountLoginError.Cancelled : AccountLoginError.None, status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
lock (gate)
|
||||||
|
return Result(disposed || generation != requestGeneration || token.IsCancellationRequested
|
||||||
|
? AccountLoginError.Cancelled : AccountLoginError.Timeout, status);
|
||||||
|
}
|
||||||
|
catch (ObjectDisposedException) { return Result(AccountLoginError.Cancelled, status); }
|
||||||
|
catch (HttpRequestException) { return Result(AccountLoginError.Network, status); }
|
||||||
|
catch (JsonException) { return Result(AccountLoginError.Protocol, status); }
|
||||||
|
}
|
||||||
|
|
||||||
|
HttpRequestMessage Request(string path, JObject body) => new HttpRequestMessage(HttpMethod.Post, new Uri(api, path))
|
||||||
|
{ Content = new StringContent(body.ToString(Formatting.None), Encoding.UTF8, "application/json") };
|
||||||
|
|
||||||
|
static JObject Parse(string text)
|
||||||
|
{
|
||||||
|
using (var reader = new JsonTextReader(new StringReader(text)) { DateParseHandling = DateParseHandling.None })
|
||||||
|
{
|
||||||
|
var value = JObject.Load(reader);
|
||||||
|
if (reader.Read()) throw new JsonReaderException("Trailing JSON content.");
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool ReadUtc(JToken value, out DateTime date)
|
||||||
|
{
|
||||||
|
date = default;
|
||||||
|
return value?.Type == JTokenType.String && DateTime.TryParse(value.Value<string>(), CultureInfo.InvariantCulture,
|
||||||
|
DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal, out date);
|
||||||
|
}
|
||||||
|
|
||||||
|
static AccountLoginResult Result(AccountLoginError error, int? status = null) => new AccountLoginResult(error, status);
|
||||||
|
void ClearIdentity()
|
||||||
|
{
|
||||||
|
IsAuthenticated = false;
|
||||||
|
PlayerId = null;
|
||||||
|
InternalId = 0;
|
||||||
|
CreateTimeUtc = default;
|
||||||
|
ServerTimeUtc = default;
|
||||||
|
NewlyCreated = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
lock (gate)
|
||||||
|
{
|
||||||
|
if (disposed) return;
|
||||||
|
disposed = true;
|
||||||
|
generation++;
|
||||||
|
ClearIdentity();
|
||||||
|
http?.Dispose();
|
||||||
|
http = null;
|
||||||
|
Cookies = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 748d56d3a1b2489d85e081bfed580314
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -13,6 +13,17 @@ namespace game
|
|||||||
|
|
||||||
public class AggUserService : PlayFabUserService
|
public class AggUserService : PlayFabUserService
|
||||||
{
|
{
|
||||||
|
public AggUserService() { }
|
||||||
|
internal AggUserService(PlayerDataStorage.PlayerKVControlledLoadCapability capability) : base(capability) { }
|
||||||
|
internal IReadOnlyList<PlayerDataStorage.PlayerKVIdentityChannel> KVLinkedAccounts { get; private set; } =
|
||||||
|
Array.Empty<PlayerDataStorage.PlayerKVIdentityChannel>();
|
||||||
|
internal override void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
base.ResetForKVLoad();
|
||||||
|
KVLinkedAccounts=Array.Empty<PlayerDataStorage.PlayerKVIdentityChannel>();
|
||||||
|
}
|
||||||
|
internal override void ReplaceKVLinked(PlayerDataStorage.PlayerKVLoginState state)
|
||||||
|
{ KVLinkedAccounts=new List<PlayerDataStorage.PlayerKVIdentityChannel>(state.Linked).AsReadOnly(); }
|
||||||
protected override string NewPlayerName
|
protected override string NewPlayerName
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@@ -45,6 +56,18 @@ namespace game
|
|||||||
|
|
||||||
public override async Task<ELoginStep> Login(Action<int> progress, bool tryLoginByToken = true)
|
public override async Task<ELoginStep> Login(Action<int> progress, bool tryLoginByToken = true)
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
if(game.PlayerDataStorage.PlayerKVGameplayLoop.Enabled)
|
||||||
|
{
|
||||||
|
CustomId=game.PlayerDataStorage.PlayerKVGameplayLoop.Permit.PlayerId;
|
||||||
|
OnInitData+=InitData;
|
||||||
|
try { return await LoginWithBackend(progress,"kv-loop"); }
|
||||||
|
finally { OnInitData-=InitData; }
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
var backend=CaptureSaveBackend();
|
||||||
|
if(RejectSaveBackend(backend)) return ELoginStep.Api;
|
||||||
|
var generation = logoutGeneration;
|
||||||
if (IsLogin)
|
if (IsLogin)
|
||||||
{
|
{
|
||||||
progress?.Invoke(3);
|
progress?.Invoke(3);
|
||||||
@@ -58,10 +81,12 @@ namespace game
|
|||||||
if (!TYSdkFacade.IsLoggedIn)
|
if (!TYSdkFacade.IsLoggedIn)
|
||||||
{
|
{
|
||||||
loginInfo = await TYSdkFacade.Instance.LoginBySns();
|
loginInfo = await TYSdkFacade.Instance.LoginBySns();
|
||||||
|
if (generation != logoutGeneration) return ELoginStep.Sdk;
|
||||||
|
|
||||||
if (!loginInfo.isSuccess && tryLoginByToken)
|
if (!loginInfo.isSuccess && tryLoginByToken)
|
||||||
{
|
{
|
||||||
loginInfo = await TYSdkFacade.Instance.LoginByToken();
|
loginInfo = await TYSdkFacade.Instance.LoginByToken();
|
||||||
|
if (generation != logoutGeneration) return ELoginStep.Sdk;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!loginInfo.isSuccess)
|
if (!loginInfo.isSuccess)
|
||||||
@@ -69,7 +94,9 @@ namespace game
|
|||||||
var evt = new LoginTypeEvt();
|
var evt = new LoginTypeEvt();
|
||||||
GContext.Publish(evt);
|
GContext.Publish(evt);
|
||||||
var loginType = await evt.loginType.Task;
|
var loginType = await evt.loginType.Task;
|
||||||
|
if (generation != logoutGeneration) return ELoginStep.Sdk;
|
||||||
loginInfo = await TYSdkFacade.Instance.Login(loginType);
|
loginInfo = await TYSdkFacade.Instance.Login(loginType);
|
||||||
|
if (generation != logoutGeneration) return ELoginStep.Sdk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -80,21 +107,18 @@ namespace game
|
|||||||
|
|
||||||
if (!loginInfo.isSuccess) return ELoginStep.Sdk;
|
if (!loginInfo.isSuccess) return ELoginStep.Sdk;
|
||||||
|
|
||||||
progress.Invoke(1);
|
progress?.Invoke(1);
|
||||||
|
|
||||||
CustomId = loginInfo.StrUserId;
|
CustomId = loginInfo.StrUserId;
|
||||||
|
|
||||||
|
|
||||||
OnInitData += InitData;
|
OnInitData += InitData;
|
||||||
|
|
||||||
var step = await base.Login(step => progress?.Invoke(step + 1));
|
ELoginStep step;
|
||||||
if (step != ELoginStep.Done)
|
try { step = await LoginWithBackend(value => progress?.Invoke(value + 1),backend); }
|
||||||
{
|
finally { OnInitData -= InitData; }
|
||||||
OnInitData -= InitData;
|
if (generation != logoutGeneration) return ELoginStep.Sdk;
|
||||||
return step;
|
if (step != ELoginStep.Done) return step;
|
||||||
}
|
|
||||||
|
|
||||||
OnInitData -= InitData;
|
|
||||||
|
|
||||||
if (ChannelManager.IsRustoreStore)
|
if (ChannelManager.IsRustoreStore)
|
||||||
{
|
{
|
||||||
@@ -166,8 +190,9 @@ namespace game
|
|||||||
|
|
||||||
public override void Logout()
|
public override void Logout()
|
||||||
{
|
{
|
||||||
TYSdkFacade.Instance.Logout();
|
|
||||||
base.Logout();
|
base.Logout();
|
||||||
|
if(IsControlledKVInstance) return;
|
||||||
|
TYSdkFacade.Instance.Logout();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override async Task<bool> GetLinkState(EAccoutType accoutType)
|
public override async Task<bool> GetLinkState(EAccoutType accoutType)
|
||||||
@@ -193,8 +218,25 @@ namespace game
|
|||||||
return (linkResult.code, linkResult.userId);
|
return (linkResult.code, linkResult.userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal int KVNotificationCount { get; private set; }
|
||||||
|
internal override async Task<PlayerDataStorage.PlayerKVGameLoadResult> LoadKVForValidationAsync(PlayerDataStorage.PlayerKVGameLoadCapability capability)
|
||||||
|
{
|
||||||
|
EnterKVReceiver(ReceiveKVData);
|
||||||
|
try { return await base.LoadKVForValidationAsync(capability); }
|
||||||
|
finally { ExitKVReceiver(); }
|
||||||
|
}
|
||||||
|
void ReceiveKVData(IDictionary<string,string> data)
|
||||||
|
{
|
||||||
|
if(!IsControlledKVInstance || KVLoadingCopy==null || data.Count!=KVLoadingCopy.Count)
|
||||||
|
throw new InvalidOperationException("Controlled notification window invalid.");
|
||||||
|
KVNotificationCount++;
|
||||||
|
}
|
||||||
private void InitData(IDictionary<string, string> data)
|
private void InitData(IDictionary<string, string> data)
|
||||||
{
|
{
|
||||||
|
#if UNITY_EDITOR && !SERVICE_HOST
|
||||||
|
// Editor loop has no channel SDK login. M31 already replaced account URLs and linked flags.
|
||||||
|
if(PlayerDataStorage.PlayerKVGameplayLoop.Enabled) return;
|
||||||
|
#endif
|
||||||
if (data.TryGetValue(EAccoutType.hwGoogle.ToString(), out var google) && google == "1")
|
if (data.TryGetValue(EAccoutType.hwGoogle.ToString(), out var google) && google == "1")
|
||||||
{
|
{
|
||||||
TYSdkFacade.TYAccountInfo.linkedAccout.Add(EAccoutType.hwGoogle);
|
TYSdkFacade.TYAccountInfo.linkedAccout.Add(EAccoutType.hwGoogle);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using com.fpnn;
|
using com.fpnn;
|
||||||
using com.fpnn.rtm;
|
using com.fpnn.rtm;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using System;
|
using System;
|
||||||
@@ -6,6 +6,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using Newtonsoft.Json.Linq;
|
||||||
|
|
||||||
namespace game
|
namespace game
|
||||||
{
|
{
|
||||||
@@ -31,6 +32,57 @@ namespace game
|
|||||||
}
|
}
|
||||||
public class ClubService //: IClubService
|
public class ClubService //: IClubService
|
||||||
{
|
{
|
||||||
|
[Inject] public PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
// BEGIN B01 fixed prompt owner
|
||||||
|
readonly bool requiresFormalKV;
|
||||||
|
PlayerDataStorage.PlayerKVGameSessionHandle promptOwner;
|
||||||
|
internal PlayerDataStorage.PlayerKVEditResult LastPromptEdit { get; private set; }
|
||||||
|
public ClubService() : this(RequireFrozenSelection()) { }
|
||||||
|
static bool RequireFrozenSelection()
|
||||||
|
{
|
||||||
|
var selection = GContext.container.Resolve<PlayerDataStorage.PlayerKVRuntimeSelection>();
|
||||||
|
if (selection == null) throw DefaultSettingService.PromptFailure("IsOpenClubRed: startup selection missing.");
|
||||||
|
return selection.IsKV;
|
||||||
|
}
|
||||||
|
internal ClubService(bool formalKV) { requiresFormalKV = formalKV; }
|
||||||
|
internal ClubService(PlayerDataStorage.PlayerKVGameSessionHandle owner) : this(true)
|
||||||
|
{
|
||||||
|
promptOwner = owner ?? throw new ArgumentNullException(nameof(owner));
|
||||||
|
RequirePromptOwner();
|
||||||
|
}
|
||||||
|
// The constructor captures the registered startup selection, never a later mutable config value.
|
||||||
|
internal void PreflightFormalPromptOwner(PlayerDataStorage.PlayerKVGameSessionHandle owner)
|
||||||
|
{
|
||||||
|
if (!requiresFormalKV || owner == null || (promptOwner != null && !ReferenceEquals(promptOwner, owner)))
|
||||||
|
throw DefaultSettingService.PromptFailure("IsOpenClubRed: formal owner mismatch.");
|
||||||
|
var read = KVMgr.ReadKV(owner, "IsOpenClubRed");
|
||||||
|
if (!read.Success)
|
||||||
|
throw DefaultSettingService.PromptFailure($"IsOpenClubRed owner={owner.OwnerInstanceId}: {read.Error}");
|
||||||
|
}
|
||||||
|
internal void BindFormalPromptOwner(PlayerDataStorage.PlayerKVGameSessionHandle owner)
|
||||||
|
{
|
||||||
|
PreflightFormalPromptOwner(owner);
|
||||||
|
if (promptOwner == null) promptOwner = owner;
|
||||||
|
RequirePromptOwner();
|
||||||
|
}
|
||||||
|
internal bool HasFormalPromptOwner(PlayerDataStorage.PlayerKVGameSessionHandle owner) =>
|
||||||
|
requiresFormalKV && ReferenceEquals(promptOwner, owner);
|
||||||
|
internal void RequirePromptOwner()
|
||||||
|
{
|
||||||
|
if (promptOwner != null) ReadPrompt();
|
||||||
|
else if (requiresFormalKV)
|
||||||
|
throw DefaultSettingService.PromptFailure("IsOpenClubRed: formal owner not handed off.");
|
||||||
|
}
|
||||||
|
PlayerDataStorage.PlayerKVKeyReadResult ReadPrompt()
|
||||||
|
{
|
||||||
|
if (LastPromptEdit != null && !LastPromptEdit.Accepted)
|
||||||
|
throw DefaultSettingService.PromptFailure($"IsOpenClubRed owner={promptOwner.OwnerInstanceId}: {LastPromptEdit.StateResult.Error}; uncertain={LastPromptEdit.StateResult.LocalCommitMayHaveSucceeded}");
|
||||||
|
var read = KVMgr.ReadKV(promptOwner, "IsOpenClubRed");
|
||||||
|
if (!read.Success)
|
||||||
|
throw DefaultSettingService.PromptFailure($"IsOpenClubRed owner={promptOwner.OwnerInstanceId}: {read.Error}");
|
||||||
|
return read;
|
||||||
|
}
|
||||||
|
// END B01 fixed prompt owner
|
||||||
[Inject]
|
[Inject]
|
||||||
public IUserService userService { get; set; }
|
public IUserService userService { get; set; }
|
||||||
[Inject]
|
[Inject]
|
||||||
@@ -47,6 +99,27 @@ namespace game
|
|||||||
public DateTime? signTime { get; private set; }
|
public DateTime? signTime { get; private set; }
|
||||||
|
|
||||||
LureDonateData lureDonateData;
|
LureDonateData lureDonateData;
|
||||||
|
|
||||||
|
// KV loading owns these three fields only; membership, transport and chat lifecycle stay untouched.
|
||||||
|
internal static PlayerDataStorage.PlayerKVClubState DecodeForKVLoad(IReadOnlyDictionary<string,string> raw,
|
||||||
|
PlayerDataStorage.PlayerKVSchemaSnapshot snapshot, PlayerDataStorage.PlayerKVSchemaDiagnostics errors) =>
|
||||||
|
PlayerDataStorage.PlayerKVSaveSchema.DecodeClub(raw,snapshot,errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
signTime = null;
|
||||||
|
lureDonateData = new LureDonateData();
|
||||||
|
IsOpenClubRed = true;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(PlayerDataStorage.PlayerKVClubState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new ArgumentNullException(nameof(state));
|
||||||
|
var donation = new LureDonateData { DonateCountTime=state.DonateTime,
|
||||||
|
ClubLureDonateCount=state.DonateCount, ClubLureRequestCDEnd=state.RequestEnd };
|
||||||
|
signTime = state.SignTime; lureDonateData = donation; IsOpenClubRed = state.OpenRed;
|
||||||
|
}
|
||||||
|
internal PlayerDataStorage.PlayerKVClubState SnapshotForKVValidation() =>
|
||||||
|
new PlayerDataStorage.PlayerKVClubState(signTime,lureDonateData.DonateCountTime,
|
||||||
|
lureDonateData.ClubLureDonateCount,lureDonateData.ClubLureRequestCDEnd,IsOpenClubRed);
|
||||||
public int ClubLureDonateCount => lureDonateData.ClubLureDonateCount;
|
public int ClubLureDonateCount => lureDonateData.ClubLureDonateCount;
|
||||||
public DateTime ClubLureRequestCDEnd => lureDonateData.ClubLureRequestCDEnd;
|
public DateTime ClubLureRequestCDEnd => lureDonateData.ClubLureRequestCDEnd;
|
||||||
|
|
||||||
@@ -115,7 +188,7 @@ namespace game
|
|||||||
}
|
}
|
||||||
void SaveLureDonateData()
|
void SaveLureDonateData()
|
||||||
{
|
{
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("LureDonateData", Newtonsoft.Json.JsonConvert.SerializeObject(lureDonateData));
|
SaveStore.Write("LureDonateData", Newtonsoft.Json.JsonConvert.SerializeObject(lureDonateData)).RequireAccepted();
|
||||||
}
|
}
|
||||||
//刷新体力求助次数
|
//刷新体力求助次数
|
||||||
public void RefreshLureDonate()
|
public void RefreshLureDonate()
|
||||||
@@ -130,6 +203,22 @@ namespace game
|
|||||||
|
|
||||||
public void SetOpenClubRed()
|
public void SetOpenClubRed()
|
||||||
{
|
{
|
||||||
|
if (requiresFormalKV && promptOwner == null) RequirePromptOwner();
|
||||||
|
if (promptOwner != null)
|
||||||
|
{
|
||||||
|
var read = ReadPrompt();
|
||||||
|
// M14: any present string means read, including "0" and the empty string.
|
||||||
|
if (read.Found != true)
|
||||||
|
{
|
||||||
|
LastPromptEdit = KVMgr.WriteKV(promptOwner, "IsOpenClubRed", "1");
|
||||||
|
if (!LastPromptEdit.Accepted)
|
||||||
|
throw DefaultSettingService.PromptFailure($"IsOpenClubRed owner={promptOwner.OwnerInstanceId}: {LastPromptEdit.StateResult.Error}; uncertain={LastPromptEdit.StateResult.LocalCommitMayHaveSucceeded}");
|
||||||
|
}
|
||||||
|
RequirePromptOwner();
|
||||||
|
IsOpenClubRed = false;
|
||||||
|
SetClubRed();
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (IsOpenClubRed)
|
if (IsOpenClubRed)
|
||||||
{
|
{
|
||||||
IsOpenClubRed = false;
|
IsOpenClubRed = false;
|
||||||
@@ -154,28 +243,37 @@ namespace game
|
|||||||
}
|
}
|
||||||
public async void GetSelfClub()
|
public async void GetSelfClub()
|
||||||
{
|
{
|
||||||
|
if (!userService.IsAuthorized || string.IsNullOrEmpty(userService.ApiPlayerId))
|
||||||
|
return;
|
||||||
|
var sessionVersion = customServerMgr.SessionVersion;
|
||||||
GetSelfClubRequest getSelfClubRequest = new GetSelfClubRequest()
|
GetSelfClubRequest getSelfClubRequest = new GetSelfClubRequest()
|
||||||
{
|
{
|
||||||
playerId = userService.UserId,
|
playerId = userService.ApiPlayerId,
|
||||||
};
|
};
|
||||||
string json = await customServerMgr.ClubRequest("GetSelfClub", getSelfClubRequest);
|
string json = await customServerMgr.ClubRequest("GetSelfClub", getSelfClubRequest);
|
||||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
if (sessionVersion != customServerMgr.SessionVersion) return;
|
||||||
|
if (string.IsNullOrWhiteSpace(json)) return;
|
||||||
|
GetSelfClubResp response;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
GetSelfClubResp getSelfClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetSelfClubResp>(json);
|
var body = JObject.Parse(json);
|
||||||
myClubInfo = getSelfClubResp.clubInfo;
|
if (!body.TryGetValue("clubInfo", out var club) ||
|
||||||
if (myClubInfo != null)
|
(club.Type != JTokenType.Null && club.Type != JTokenType.Object)) return;
|
||||||
{
|
response = body.ToObject<GetSelfClubResp>();
|
||||||
memberRole = getSelfClubResp.role;
|
if (response == null) return;
|
||||||
//signTime = getSelfClubResp.signTime;
|
if (club.Type == JTokenType.Object &&
|
||||||
internalIdToPlayerId = getSelfClubResp.playerIDs;
|
(response.clubInfo == null || response.clubInfo.id == 0 ||
|
||||||
SetClubPlayerProfile(getSelfClubResp.clubPlayerProfiles);
|
body["role"]?.Type != JTokenType.Integer || !Enum.IsDefined(typeof(EMemberRole), response.role))) return;
|
||||||
chatService.GetConversationList((long)myClubInfo.id);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
catch (Newtonsoft.Json.JsonException) { return; }
|
||||||
|
catch (OverflowException) { return; }
|
||||||
|
myClubInfo = response.clubInfo;
|
||||||
|
memberRole = myClubInfo == null ? EMemberRole.Member : response.role;
|
||||||
|
internalIdToPlayerId = response.playerIDs ?? new Dictionary<long, string>();
|
||||||
|
if (myClubInfo != null)
|
||||||
{
|
{
|
||||||
memberRole = EMemberRole.Member;
|
SetClubPlayerProfile(response.clubPlayerProfiles);
|
||||||
myClubInfo = null;
|
chatService.GetConversationList((long)myClubInfo.id);
|
||||||
}
|
}
|
||||||
SetClubRed();
|
SetClubRed();
|
||||||
MyClubInfoChange();
|
MyClubInfoChange();
|
||||||
@@ -218,16 +316,48 @@ namespace game
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static bool IsDecimalPlayerId(string id) =>
|
||||||
|
long.TryParse(id, System.Globalization.NumberStyles.None,
|
||||||
|
System.Globalization.CultureInfo.InvariantCulture, out var number) && number > 0;
|
||||||
|
|
||||||
|
private bool TryGetClubSession(out string playerId, out int version)
|
||||||
|
{
|
||||||
|
playerId = userService.ApiPlayerId;
|
||||||
|
version = customServerMgr.SessionVersion;
|
||||||
|
return userService.IsAuthorized && IsDecimalPlayerId(playerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool IsClubSessionCurrent(string playerId, int version) =>
|
||||||
|
version == customServerMgr.SessionVersion && userService.IsAuthorized && playerId == userService.ApiPlayerId;
|
||||||
|
|
||||||
|
private static bool TryReadClubResponse<T>(string json, out T result, params int[] acceptedCodes) where T : class
|
||||||
|
{
|
||||||
|
result = null;
|
||||||
|
if (string.IsNullOrWhiteSpace(json)) return false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var body = Newtonsoft.Json.Linq.JObject.Parse(json);
|
||||||
|
var code = body["code"];
|
||||||
|
if (code?.Type != Newtonsoft.Json.Linq.JTokenType.Integer || !acceptedCodes.Contains(code.Value<int>())) return false;
|
||||||
|
result = body.ToObject<T>();
|
||||||
|
return result != null;
|
||||||
|
}
|
||||||
|
catch (Newtonsoft.Json.JsonException) { return false; }
|
||||||
|
catch (OverflowException) { return false; }
|
||||||
|
}
|
||||||
|
|
||||||
public async Task<List<SocialInfoItemData>> GetClubDetails(ulong clubID, bool applyState = false)
|
public async Task<List<SocialInfoItemData>> GetClubDetails(ulong clubID, bool applyState = false)
|
||||||
{
|
{
|
||||||
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return null;
|
||||||
ApplyState = false;
|
ApplyState = false;
|
||||||
GetClubDetailsRequest getClubDetailsRequest = new GetClubDetailsRequest()
|
GetClubDetailsRequest getClubDetailsRequest = new GetClubDetailsRequest()
|
||||||
{
|
{
|
||||||
id = clubID,
|
id = clubID,
|
||||||
playerId = userService.UserId,
|
playerId = apiPlayerId,
|
||||||
applyState = applyState,
|
applyState = applyState,
|
||||||
};
|
};
|
||||||
string json = await customServerMgr.ClubRequest("GetClubDetails", getClubDetailsRequest);
|
string json = await customServerMgr.ClubRequest("GetClubDetails", getClubDetailsRequest);
|
||||||
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return null;
|
||||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||||
{
|
{
|
||||||
GetClubDetailsResp clubDetails = Newtonsoft.Json.JsonConvert.DeserializeObject<GetClubDetailsResp>(json);
|
GetClubDetailsResp clubDetails = Newtonsoft.Json.JsonConvert.DeserializeObject<GetClubDetailsResp>(json);
|
||||||
@@ -243,6 +373,7 @@ namespace game
|
|||||||
}
|
}
|
||||||
List<long> longs1 = clubDetails.playerIDs.Keys.ToList();
|
List<long> longs1 = clubDetails.playerIDs.Keys.ToList();
|
||||||
HashSet<long> longs = await chatService.GetOnlineUsers(longs1);
|
HashSet<long> longs = await chatService.GetOnlineUsers(longs1);
|
||||||
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return null;
|
||||||
List<ClubPlayerProfile> clubPlayerProfiles = clubDetails.clubPlayerProfiles;
|
List<ClubPlayerProfile> clubPlayerProfiles = clubDetails.clubPlayerProfiles;
|
||||||
SetClubPlayerProfile(clubPlayerProfiles);
|
SetClubPlayerProfile(clubPlayerProfiles);
|
||||||
|
|
||||||
@@ -284,40 +415,27 @@ namespace game
|
|||||||
|
|
||||||
public async Task<ClubInfo> CreateClub(ClubSettingData clubSettingData)
|
public async Task<ClubInfo> CreateClub(ClubSettingData clubSettingData)
|
||||||
{
|
{
|
||||||
CreateClubRequest createClubRequest = new CreateClubRequest()
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return null;
|
||||||
{
|
var internalId = userService.InternalId;
|
||||||
playerId = userService.UserId,
|
var request = new CreateClubRequest { playerId = apiPlayerId, clubSettingData = clubSettingData };
|
||||||
//entityKey = userService.entityKey.Id,
|
var json = await customServerMgr.ClubRequest("CreateClub", request);
|
||||||
clubSettingData = clubSettingData,
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return null;
|
||||||
};
|
// Code 1 means already a member; returning a club would charge the create UI again.
|
||||||
string json = await customServerMgr.ClubRequest("CreateClub", createClubRequest);
|
if (!TryReadClubResponse<CreateClubResp>(json, out var response, 0) || response.clubInfo == null || response.clubInfo.id == 0)
|
||||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
return null;
|
||||||
{
|
memberRole = EMemberRole.Owner;
|
||||||
CreateClubResp createClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<CreateClubResp>(json);
|
myClubInfo = response.clubInfo;
|
||||||
if (createClubResp.code != 2)
|
internalIdToPlayerId[internalId] = apiPlayerId;
|
||||||
{
|
ShowPromote();
|
||||||
if (createClubResp.code == 0)
|
chatService.GetConversationList((long)myClubInfo.id);
|
||||||
{
|
MyClubInfoChange(true);
|
||||||
memberRole = EMemberRole.Owner;
|
|
||||||
ShowPromote();
|
|
||||||
}
|
|
||||||
myClubInfo = createClubResp.clubInfo;
|
|
||||||
chatService.GetConversationList((long)myClubInfo.id);
|
|
||||||
internalIdToPlayerId[userService.InternalId] = userService.UserId;
|
|
||||||
MyClubInfoChange(true);
|
|
||||||
return myClubInfo;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
myClubInfo = null;
|
|
||||||
}
|
|
||||||
MyClubInfoChange();
|
|
||||||
return myClubInfo;
|
return myClubInfo;
|
||||||
}
|
}
|
||||||
public async void ShowPromote()
|
public async void ShowPromote()
|
||||||
{
|
{
|
||||||
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return;
|
||||||
GameObject go = await UIManager.Instance.ShowUI(UITypes.ClubPromoteNoticePopupPanel);
|
GameObject go = await UIManager.Instance.ShowUI(UITypes.ClubPromoteNoticePopupPanel);
|
||||||
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion) || go == null) return;
|
||||||
var ClubPromoteNoticePopupPanel = go.GetComponent<ClubPromoteNoticePopupPanel>();
|
var ClubPromoteNoticePopupPanel = go.GetComponent<ClubPromoteNoticePopupPanel>();
|
||||||
ClubPromoteNoticePopupPanel.SetRole(memberRole);
|
ClubPromoteNoticePopupPanel.SetRole(memberRole);
|
||||||
}
|
}
|
||||||
@@ -344,19 +462,21 @@ namespace game
|
|||||||
|
|
||||||
public async Task<bool> ApplyClub(ulong clubID)
|
public async Task<bool> ApplyClub(ulong clubID)
|
||||||
{
|
{
|
||||||
memberRole = EMemberRole.Member;
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return false;
|
||||||
ApplyClubRequest applyClubRequest = new ApplyClubRequest()
|
ApplyClubRequest applyClubRequest = new ApplyClubRequest()
|
||||||
{
|
{
|
||||||
playerId = userService.UserId,
|
playerId = apiPlayerId,
|
||||||
//entityKey = userService.entityKey.Id,
|
//entityKey = userService.entityKey.Id,
|
||||||
id = clubID,
|
id = clubID,
|
||||||
};
|
};
|
||||||
string json = await customServerMgr.ClubRequest("ApplyClub", applyClubRequest);
|
string json = await customServerMgr.ClubRequest("ApplyClub", applyClubRequest);
|
||||||
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return false;
|
||||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||||
{
|
{
|
||||||
ApplyClubResp applyClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<ApplyClubResp>(json);
|
ApplyClubResp applyClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<ApplyClubResp>(json);
|
||||||
if (applyClubResp.code == 0)
|
if (applyClubResp.code == 0)
|
||||||
{
|
{
|
||||||
|
memberRole = EMemberRole.Member;
|
||||||
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_41"));
|
ToastPanel.Show(LocalizationMgr.GetText("UI_ToastPanel_41"));
|
||||||
myClubInfo = applyClubResp.clubInfo;
|
myClubInfo = applyClubResp.clubInfo;
|
||||||
internalIdToPlayerId = applyClubResp.playerIDs;
|
internalIdToPlayerId = applyClubResp.playerIDs;
|
||||||
@@ -380,6 +500,10 @@ namespace game
|
|||||||
|
|
||||||
public async void HandleApply(bool isAgree, string applyId)
|
public async void HandleApply(bool isAgree, string applyId)
|
||||||
{
|
{
|
||||||
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return;
|
||||||
|
if (applyId == "" && isAgree) return;
|
||||||
|
if (applyId != "" && !IsDecimalPlayerId(applyId)) return;
|
||||||
|
if (myClubInfo == null) return;
|
||||||
if (isAgree && myClubInfo.curMembers >= myClubInfo.maxMembers)
|
if (isAgree && myClubInfo.curMembers >= myClubInfo.maxMembers)
|
||||||
{
|
{
|
||||||
//人数已满
|
//人数已满
|
||||||
@@ -392,31 +516,32 @@ namespace game
|
|||||||
isAgree = isAgree,
|
isAgree = isAgree,
|
||||||
id = myClubInfo.id,
|
id = myClubInfo.id,
|
||||||
};
|
};
|
||||||
if (applyId == "")
|
|
||||||
{
|
|
||||||
clubPlayerInfos.Clear();
|
|
||||||
RedPointManager.Instance.SetRedPointState(RedPointName.ApplyList, false);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
for (int i = 0; i < clubPlayerInfos.Count; i++)
|
|
||||||
{
|
|
||||||
if (clubPlayerInfos[i].playFabId == applyId)
|
|
||||||
{
|
|
||||||
clubPlayerInfos.RemoveAt(i);
|
|
||||||
RedPointManager.Instance.SetRedPointState(RedPointName.ApplyList, clubPlayerInfos.Count > 0
|
|
||||||
&& CanAccepted);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
string json = await customServerMgr.ClubRequest("HandleApply", handleApplyRequest);
|
string json = await customServerMgr.ClubRequest("HandleApply", handleApplyRequest);
|
||||||
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return;
|
||||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||||
{
|
{
|
||||||
HandleApplyResp handleApplyResp = Newtonsoft.Json.JsonConvert.DeserializeObject<HandleApplyResp>(json);
|
if (!TryReadClubResponse<HandleApplyResp>(json, out var handleApplyResp, applyId == "" ? 4 : 0) || myClubInfo == null) return;
|
||||||
if (handleApplyResp.code == 0)
|
if (handleApplyResp.code == 0 || handleApplyResp.code == 4)
|
||||||
{
|
{
|
||||||
myClubInfo.curMembers++;
|
if (applyId == "")
|
||||||
|
{
|
||||||
|
clubPlayerInfos.Clear();
|
||||||
|
RedPointManager.Instance.SetRedPointState(RedPointName.ApplyList, false);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
for (int i = 0; i < clubPlayerInfos.Count; i++)
|
||||||
|
{
|
||||||
|
if (clubPlayerInfos[i].playFabId == applyId)
|
||||||
|
{
|
||||||
|
clubPlayerInfos.RemoveAt(i);
|
||||||
|
RedPointManager.Instance.SetRedPointState(RedPointName.ApplyList, clubPlayerInfos.Count > 0
|
||||||
|
&& CanAccepted);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (isAgree) myClubInfo.curMembers++;
|
||||||
GContext.Publish(new ClubSttingUpdateEvent());
|
GContext.Publish(new ClubSttingUpdateEvent());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -424,17 +549,19 @@ namespace game
|
|||||||
|
|
||||||
public async void GetApplyList()
|
public async void GetApplyList()
|
||||||
{
|
{
|
||||||
clubPlayerInfos = new List<SocialInfoItemData>();
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return;
|
||||||
RedPointManager.Instance.SetRedPointState(RedPointName.ApplyList, false);
|
if (myClubInfo == null) return;
|
||||||
GetApplyListRequest getApplyListRequest = new GetApplyListRequest()
|
GetApplyListRequest getApplyListRequest = new GetApplyListRequest()
|
||||||
{
|
{
|
||||||
playerId = userService.UserId,
|
playerId = apiPlayerId,
|
||||||
id = myClubInfo.id,
|
id = myClubInfo.id,
|
||||||
};
|
};
|
||||||
string json = await customServerMgr.ClubRequest("GetApplyList", getApplyListRequest);
|
string json = await customServerMgr.ClubRequest("GetApplyList", getApplyListRequest);
|
||||||
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return;
|
||||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||||
{
|
{
|
||||||
GetApplyListResp getApplyListResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetApplyListResp>(json);
|
GetApplyListResp getApplyListResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetApplyListResp>(json);
|
||||||
|
clubPlayerInfos = new List<SocialInfoItemData>();
|
||||||
SetClubPlayerProfile(getApplyListResp.clubPlayerProfiles);
|
SetClubPlayerProfile(getApplyListResp.clubPlayerProfiles);
|
||||||
for (int i = 0; i < getApplyListResp.userIDList.Count; i++)
|
for (int i = 0; i < getApplyListResp.userIDList.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -467,16 +594,12 @@ namespace game
|
|||||||
}
|
}
|
||||||
public async void QuitClub(string appointId = "0")
|
public async void QuitClub(string appointId = "0")
|
||||||
{
|
{
|
||||||
QuitClubRequest quitClubRequest = new QuitClubRequest()
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return;
|
||||||
{
|
if (!string.IsNullOrEmpty(appointId) && appointId != "0" && (!IsDecimalPlayerId(appointId) || appointId == apiPlayerId)) return;
|
||||||
playerId = userService.UserId,
|
var request = new QuitClubRequest { playerId = apiPlayerId, appointId = appointId };
|
||||||
appointId = appointId,
|
var json = await customServerMgr.ClubRequest("QuitClub", request);
|
||||||
};
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return;
|
||||||
string json = await customServerMgr.ClubRequest("QuitClub", quitClubRequest);
|
if (!TryReadClubResponse<QuitClubResp>(json, out var response, 0, 1)) return;
|
||||||
//if (!string.IsNullOrEmpty(json) && json != "[]")
|
|
||||||
//{
|
|
||||||
// QuitClubResp quitClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<QuitClubResp>(json);
|
|
||||||
//}
|
|
||||||
chatService.OnQuit();
|
chatService.OnQuit();
|
||||||
myClubInfo = null;
|
myClubInfo = null;
|
||||||
ClearLikeCursorIds();
|
ClearLikeCursorIds();
|
||||||
@@ -485,36 +608,49 @@ namespace game
|
|||||||
}
|
}
|
||||||
public async void Demote(string playerId)
|
public async void Demote(string playerId)
|
||||||
{
|
{
|
||||||
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return;
|
||||||
|
if (!IsDecimalPlayerId(playerId) || playerId == apiPlayerId) return;
|
||||||
|
if (myClubInfo == null) return;
|
||||||
DemoteClubRequest demoteClubRequest = new DemoteClubRequest()
|
DemoteClubRequest demoteClubRequest = new DemoteClubRequest()
|
||||||
{
|
{
|
||||||
culbId = myClubInfo.id,
|
culbId = myClubInfo.id,
|
||||||
demoteId = playerId,
|
demoteId = playerId,
|
||||||
playerId = userService.UserId,
|
playerId = apiPlayerId,
|
||||||
};
|
};
|
||||||
string json = await customServerMgr.ClubRequest("DemoteClub", demoteClubRequest);
|
string json = await customServerMgr.ClubRequest("DemoteClub", demoteClubRequest);
|
||||||
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return;
|
||||||
}
|
}
|
||||||
public async void Promote(string playerId, EMemberRole role)
|
public async void Promote(string playerId, EMemberRole role)
|
||||||
{
|
{
|
||||||
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return;
|
||||||
|
if (!IsDecimalPlayerId(playerId) || playerId == apiPlayerId) return;
|
||||||
|
if (myClubInfo == null) return;
|
||||||
PromoteClubRequest promoteClubRequest = new PromoteClubRequest()
|
PromoteClubRequest promoteClubRequest = new PromoteClubRequest()
|
||||||
{
|
{
|
||||||
culbId = myClubInfo.id,
|
culbId = myClubInfo.id,
|
||||||
promoteId = playerId,
|
promoteId = playerId,
|
||||||
playerId = userService.UserId,
|
playerId = apiPlayerId,
|
||||||
role = role,
|
role = role,
|
||||||
};
|
};
|
||||||
string json = await customServerMgr.ClubRequest("PromoteClub", promoteClubRequest);
|
string json = await customServerMgr.ClubRequest("PromoteClub", promoteClubRequest);
|
||||||
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return;
|
||||||
}
|
}
|
||||||
public async void Kickout(string playerId)
|
public async void Kickout(string playerId)
|
||||||
{
|
{
|
||||||
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return;
|
||||||
|
if (!IsDecimalPlayerId(playerId) || playerId == apiPlayerId) return;
|
||||||
|
if (myClubInfo == null) return;
|
||||||
KickoutClubRequest kickoutClubRequest = new KickoutClubRequest()
|
KickoutClubRequest kickoutClubRequest = new KickoutClubRequest()
|
||||||
{
|
{
|
||||||
culbId = myClubInfo.id,
|
culbId = myClubInfo.id,
|
||||||
kickoutId = playerId,
|
kickoutId = playerId,
|
||||||
playerId = userService.UserId,
|
playerId = apiPlayerId,
|
||||||
};
|
};
|
||||||
myClubInfo.curMembers--;
|
|
||||||
GContext.Publish(new ClubSttingUpdateEvent());
|
|
||||||
string json = await customServerMgr.ClubRequest("KickoutClub", kickoutClubRequest);
|
string json = await customServerMgr.ClubRequest("KickoutClub", kickoutClubRequest);
|
||||||
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return;
|
||||||
|
if (!TryReadClubResponse<KickoutClubResp>(json, out var response, 0) || myClubInfo == null) return;
|
||||||
|
myClubInfo.curMembers = Math.Max(0, myClubInfo.curMembers - 1);
|
||||||
|
GContext.Publish(new ClubSttingUpdateEvent());
|
||||||
//if (!string.IsNullOrEmpty(json) && json != "[]")
|
//if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||||
//{
|
//{
|
||||||
// KickoutClubResp quitClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<KickoutClubResp>(json);
|
// KickoutClubResp quitClubResp = Newtonsoft.Json.JsonConvert.DeserializeObject<KickoutClubResp>(json);
|
||||||
@@ -522,52 +658,67 @@ namespace game
|
|||||||
}
|
}
|
||||||
public async void ReadClubEvent()
|
public async void ReadClubEvent()
|
||||||
{
|
{
|
||||||
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return;
|
||||||
ReadClubEventRequest readClubEventRequest = new ReadClubEventRequest()
|
ReadClubEventRequest readClubEventRequest = new ReadClubEventRequest()
|
||||||
{
|
{
|
||||||
playerId = userService.UserId,
|
playerId = apiPlayerId,
|
||||||
};
|
};
|
||||||
string json = await customServerMgr.ClubRequest("ReadClubEvent", readClubEventRequest);
|
string json = await customServerMgr.ClubRequest("ReadClubEvent", readClubEventRequest);
|
||||||
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return;
|
||||||
//if (!string.IsNullOrEmpty(json) && json != "[]")
|
//if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||||
//{
|
//{
|
||||||
// ReadClubEventResp readClubEventResp = Newtonsoft.Json.JsonConvert.DeserializeObject<ReadClubEventResp>(json);
|
// ReadClubEventResp readClubEventResp = Newtonsoft.Json.JsonConvert.DeserializeObject<ReadClubEventResp>(json);
|
||||||
//}
|
//}
|
||||||
}
|
}
|
||||||
public async void ClubSingin()
|
private int? signingSession;
|
||||||
|
public async Task ClubSingin()
|
||||||
{
|
{
|
||||||
signTime = ZZTimeHelper.UtcNow().UtcNowOffset();
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return;
|
||||||
ClubSinginRequest clubSinginRequest = new ClubSinginRequest()
|
if (myClubInfo == null) return;
|
||||||
|
if (signingSession == sessionVersion || signTime?.Date == ZZTimeHelper.UtcNow().UtcNowOffset().Date) return;
|
||||||
|
signingSession = sessionVersion;
|
||||||
|
try
|
||||||
{
|
{
|
||||||
playerId = userService.UserId,
|
ClubSinginRequest clubSinginRequest = new ClubSinginRequest()
|
||||||
id = myClubInfo.id,
|
|
||||||
};
|
|
||||||
string json = await customServerMgr.ClubRequest("ClubSingin", clubSinginRequest);
|
|
||||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
|
||||||
{
|
|
||||||
ClubSinginResp clubSinginResp = Newtonsoft.Json.JsonConvert.DeserializeObject<ClubSinginResp>(json);
|
|
||||||
signTime = ZZTimeHelper.UtcNow().UtcNowOffset();
|
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("ClubSignin", signTime.Value.ToString("yyyy-MM-dd HH:mm:ss"));
|
|
||||||
if (clubSinginResp.code == 0)
|
|
||||||
{
|
{
|
||||||
chatService.SendSystemMessage($"{MessageChatType.SI}_{userService.UserId}");
|
playerId = apiPlayerId,
|
||||||
//签到成功奖励
|
id = myClubInfo.id,
|
||||||
GContext.container.Resolve<PlayerItemData>().AddItemByDrop(GContext.container.Resolve<cfg.Tables>().TbServerConfig.ClubSignReward, null);
|
};
|
||||||
GContext.Publish(new ShowData());
|
string json = await customServerMgr.ClubRequest("ClubSingin", clubSinginRequest);
|
||||||
#if AGG
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return;
|
||||||
using (var e = GEvent.GameEvent("guild_sign"))
|
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||||
|
{
|
||||||
|
if (!TryReadClubResponse<ClubSinginResp>(json, out var clubSinginResp, 0)) return;
|
||||||
|
signTime = ZZTimeHelper.UtcNow().UtcNowOffset();
|
||||||
|
SaveStore.Write("ClubSignin", signTime.Value.ToString("yyyy-MM-dd HH:mm:ss")).RequireAccepted();
|
||||||
|
if (clubSinginResp.code == 0)
|
||||||
{
|
{
|
||||||
e.AddContent("guild_id", myClubInfo.id)
|
chatService.SendSystemMessage($"{MessageChatType.SI}_{apiPlayerId}");
|
||||||
.AddContent("drop_list", GContext.container.Resolve<cfg.Tables>().TbServerConfig.ClubSignReward);
|
//签到成功奖励
|
||||||
|
GContext.container.Resolve<PlayerItemData>().AddItemByDrop(GContext.container.Resolve<cfg.Tables>().TbServerConfig.ClubSignReward, null);
|
||||||
|
GContext.Publish(new ShowData());
|
||||||
|
#if AGG
|
||||||
|
using (var e = GEvent.GameEvent("guild_sign"))
|
||||||
|
{
|
||||||
|
e.AddContent("guild_id", myClubInfo.id)
|
||||||
|
.AddContent("drop_list", GContext.container.Resolve<cfg.Tables>().TbServerConfig.ClubSignReward);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
SetClubRed();
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
if (signingSession == sessionVersion) signingSession = null;
|
||||||
}
|
}
|
||||||
SetClubRed();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void SendSystemMessage2(int index)
|
public void SendSystemMessage2(int index)
|
||||||
{
|
{
|
||||||
chatService.SendSystemMessage2($"{userService.UserId}_{index}");
|
if (!TryGetClubSession(out var apiPlayerId, out _)) return;
|
||||||
|
chatService.SendSystemMessage2($"{apiPlayerId}_{index}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -583,15 +734,17 @@ namespace game
|
|||||||
}
|
}
|
||||||
public async void GetServiceEvent()
|
public async void GetServiceEvent()
|
||||||
{
|
{
|
||||||
energyAddCount = 0;
|
if (!TryGetClubSession(out var apiPlayerId, out var sessionVersion)) return;
|
||||||
GetPictureRequest getPictureRequest = new GetPictureRequest()
|
GetPictureRequest getPictureRequest = new GetPictureRequest()
|
||||||
{
|
{
|
||||||
playerId = userService.UserId,
|
playerId = apiPlayerId,
|
||||||
};
|
};
|
||||||
string json = await customServerMgr.ClubRequest("GetPictureList", getPictureRequest);
|
string json = await customServerMgr.ClubRequest("GetPictureList", getPictureRequest);
|
||||||
|
if (!IsClubSessionCurrent(apiPlayerId, sessionVersion)) return;
|
||||||
if (!string.IsNullOrEmpty(json) && json != "[]")
|
if (!string.IsNullOrEmpty(json) && json != "[]")
|
||||||
{
|
{
|
||||||
GetPictureResp getPictureResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetPictureResp>(json);
|
GetPictureResp getPictureResp = Newtonsoft.Json.JsonConvert.DeserializeObject<GetPictureResp>(json);
|
||||||
|
energyAddCount = 0;
|
||||||
//var pictureDatas = getPictureResp.pictureDataList;
|
//var pictureDatas = getPictureResp.pictureDataList;
|
||||||
//if (pictureDatas != null && pictureDatas.Count > 0)
|
//if (pictureDatas != null && pictureDatas.Count > 0)
|
||||||
//{
|
//{
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using asap.core;
|
using asap.core;
|
||||||
using cfg;
|
using cfg;
|
||||||
using game;
|
using game;
|
||||||
@@ -20,6 +20,8 @@ public interface IDeferredRewardStashService
|
|||||||
|
|
||||||
public class DeferredRewardStashService : IDeferredRewardStashService
|
public class DeferredRewardStashService : IDeferredRewardStashService
|
||||||
{
|
{
|
||||||
|
readonly game.PlayerDataStorage.IPlayerSaveStore saveStore = GContext.container.Resolve<game.PlayerDataStorage.IPlayerSaveStore>();
|
||||||
|
|
||||||
private readonly TbItem _itemTable = GContext.container.Resolve<Tables>().TbItem;
|
private readonly TbItem _itemTable = GContext.container.Resolve<Tables>().TbItem;
|
||||||
private readonly PlayerItemData _playerItemData = GContext.container.Resolve<PlayerItemData>();
|
private readonly PlayerItemData _playerItemData = GContext.container.Resolve<PlayerItemData>();
|
||||||
private CompositeDisposable _disposables;
|
private CompositeDisposable _disposables;
|
||||||
@@ -190,13 +192,13 @@ public class DeferredRewardStashService : IDeferredRewardStashService
|
|||||||
public void UploadData()
|
public void UploadData()
|
||||||
{
|
{
|
||||||
var s = Serialize();
|
var s = Serialize();
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(Key, s);
|
saveStore.Write(Key, s).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadData()
|
public void LoadData()
|
||||||
{
|
{
|
||||||
|
var s = saveStore.Read(Key).ValueOrThrow();
|
||||||
Reset();
|
Reset();
|
||||||
var s = PlayFabMgr.Instance.GetLocalData(Key);
|
|
||||||
if (string.IsNullOrEmpty(s))
|
if (string.IsNullOrEmpty(s))
|
||||||
return;
|
return;
|
||||||
_items = Deserialize(s);
|
_items = Deserialize(s);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using System;
|
using System;
|
||||||
public interface IFootPrintService
|
public interface IFootPrintService
|
||||||
{
|
{
|
||||||
public EFootPrint FootPrint { get; }
|
public EFootPrint FootPrint { get; }
|
||||||
@@ -11,7 +11,27 @@ public interface IFootPrintService
|
|||||||
// ReSharper disable once ClassNeverInstantiated.Global
|
// ReSharper disable once ClassNeverInstantiated.Global
|
||||||
public class FootPrintService : IFootPrintService
|
public class FootPrintService : IFootPrintService
|
||||||
{
|
{
|
||||||
|
[asap.core.Inject] public game.PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
|
||||||
private EFootPrint _footPrint;
|
private EFootPrint _footPrint;
|
||||||
|
private ulong _kvCompleteFootPrint;
|
||||||
|
internal ulong CompleteFootPrintForKVValidation => _kvCompleteFootPrint;
|
||||||
|
internal static game.PlayerDataStorage.PlayerKVFootPrintState DecodeForKVLoad(
|
||||||
|
System.Collections.Generic.IReadOnlyDictionary<string, string> raw,
|
||||||
|
game.PlayerDataStorage.PlayerKVSchemaDiagnostics errors)
|
||||||
|
=> game.PlayerDataStorage.PlayerKVSaveSchema.DecodeFootPrint(raw, errors);
|
||||||
|
internal void ResetForKVLoad()
|
||||||
|
{
|
||||||
|
_kvCompleteFootPrint = 0;
|
||||||
|
_footPrint = 0;
|
||||||
|
}
|
||||||
|
internal void ReplaceFromKVDecoded(game.PlayerDataStorage.PlayerKVFootPrintState state)
|
||||||
|
{
|
||||||
|
if (state == null) throw new ArgumentNullException(nameof(state));
|
||||||
|
_kvCompleteFootPrint = state.Bits;
|
||||||
|
// This legacy view contains only the low 32 bits. The ulong field retains the complete KV state.
|
||||||
|
_footPrint = unchecked((EFootPrint)(int)(uint)state.Bits);
|
||||||
|
}
|
||||||
public EFootPrint FootPrint => _footPrint;
|
public EFootPrint FootPrint => _footPrint;
|
||||||
public void UpdateFootPrint(EFootPrint newState)
|
public void UpdateFootPrint(EFootPrint newState)
|
||||||
{
|
{
|
||||||
@@ -21,13 +41,15 @@ public class FootPrintService : IFootPrintService
|
|||||||
|
|
||||||
public void UploadData()
|
public void UploadData()
|
||||||
{
|
{
|
||||||
var data = (ulong)_footPrint;
|
_kvCompleteFootPrint |= unchecked((uint)(int)_footPrint);
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue("FootPrint", data.ToString());
|
var data = _kvCompleteFootPrint;
|
||||||
|
SaveStore.Write("FootPrint", data.ToString()).RequireAccepted();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadData(string data)
|
public void LoadData(string data)
|
||||||
{
|
{
|
||||||
_footPrint = (EFootPrint) ulong.Parse(data);
|
_kvCompleteFootPrint = ulong.Parse(data);
|
||||||
|
_footPrint = unchecked((EFootPrint)(int)(uint)_kvCompleteFootPrint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool HasFootPrint(EFootPrint state)
|
public bool HasFootPrint(EFootPrint state)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
using asap.core;
|
using asap.core;
|
||||||
using asap.playfab.async;
|
using asap.playfab.async;
|
||||||
using GameCore;
|
using GameCore;
|
||||||
using PlayFab.ClientModels;
|
using PlayFab.ClientModels;
|
||||||
@@ -14,6 +14,7 @@ namespace game
|
|||||||
{
|
{
|
||||||
public class FriendService
|
public class FriendService
|
||||||
{
|
{
|
||||||
|
[Inject] public PlayerDataStorage.IPlayerSaveStore SaveStore { get; set; }
|
||||||
[Inject]
|
[Inject]
|
||||||
public IUserService userService { get; set; }
|
public IUserService userService { get; set; }
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ namespace game
|
|||||||
{
|
{
|
||||||
List<cfg.Invite> invites = tables.TbInvite.DataList;
|
List<cfg.Invite> invites = tables.TbInvite.DataList;
|
||||||
//已经领取奖励的数量
|
//已经领取奖励的数量
|
||||||
string receiveRewardCountStr = PlayFabMgr.Instance.GetLocalData(InviteLinkRewardCountKey);
|
string receiveRewardCountStr = SaveStore.Read(InviteLinkRewardCountKey).ValueOrThrow();
|
||||||
int.TryParse(receiveRewardCountStr, out InviteLinkRewardCount);
|
int.TryParse(receiveRewardCountStr, out InviteLinkRewardCount);
|
||||||
int canRewardCount = InviteLinkRewardCount;
|
int canRewardCount = InviteLinkRewardCount;
|
||||||
for (int i = InviteLinkRewardCount; i < invites.Count; i++)
|
for (int i = InviteLinkRewardCount; i < invites.Count; i++)
|
||||||
@@ -93,7 +94,7 @@ namespace game
|
|||||||
GContext.container.Resolve<PlayerItemData>().AddItemByDropList(DropIDs, null);
|
GContext.container.Resolve<PlayerItemData>().AddItemByDropList(DropIDs, null);
|
||||||
GContext.Publish(new ShowData());
|
GContext.Publish(new ShowData());
|
||||||
InviteLinkRewardCount = canRewardCount;
|
InviteLinkRewardCount = canRewardCount;
|
||||||
PlayFabMgr.Instance.UpdateUserDataValue(InviteLinkRewardCountKey, InviteLinkRewardCount.ToString());
|
SaveStore.Write(InviteLinkRewardCountKey, InviteLinkRewardCount.ToString()).RequireAccepted();
|
||||||
RedPointManager.Instance.SetRedPointState(RedPointName.Home_Invite, false);
|
RedPointManager.Instance.SetRedPointState(RedPointName.Home_Invite, false);
|
||||||
#if AGG
|
#if AGG
|
||||||
using (var e = GEvent.GameEvent("invite_reward"))
|
using (var e = GEvent.GameEvent("invite_reward"))
|
||||||
|
|||||||
@@ -37,14 +37,68 @@ public class LocalNotificationService : ILocalNotificationService
|
|||||||
#endif
|
#endif
|
||||||
bool isInit = false;
|
bool isInit = false;
|
||||||
bool initing = false;
|
bool initing = false;
|
||||||
|
DefaultSettingService promptSettings;
|
||||||
|
Task initialization;
|
||||||
|
Task opening;
|
||||||
|
internal bool HasKVPromptOwner => promptSettings != null;
|
||||||
public LocalNotificationService()
|
public LocalNotificationService()
|
||||||
{
|
{
|
||||||
_notificationList = GContext.container.Resolve<cfg.Tables>().TbNotification.DataList;
|
_notificationList = GContext.container.Resolve<cfg.Tables>().TbNotification.DataList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async System.Threading.Tasks.Task Init()
|
internal LocalNotificationService(cfg.Tables tables)
|
||||||
{
|
{
|
||||||
if (isInit) return;
|
_notificationList = (tables ?? throw new ArgumentNullException(nameof(tables))).TbNotification.DataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal LocalNotificationService(DefaultSettingService settings, cfg.Tables tables)
|
||||||
|
{
|
||||||
|
if (settings == null || !settings.HasKVPromptOwner)
|
||||||
|
throw new ArgumentException("Fixed KV settings required.", nameof(settings));
|
||||||
|
promptSettings = settings;
|
||||||
|
_notificationList = (tables ?? throw new ArgumentNullException(nameof(tables))).TbNotification.DataList;
|
||||||
|
RequirePromptOwner();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void RequirePromptOwner(ISettingService expected = null)
|
||||||
|
{
|
||||||
|
if (expected != null && (promptSettings != null || expected is DefaultSettingService setting && setting.HasKVPromptOwner)
|
||||||
|
&& !ReferenceEquals(expected, promptSettings))
|
||||||
|
throw DefaultSettingService.PromptFailure("ShowNotice: notification/settings owner mismatch.");
|
||||||
|
promptSettings?.RequirePromptOwner();
|
||||||
|
}
|
||||||
|
|
||||||
|
internal void PreflightFormalPromptSettings(DefaultSettingService settings)
|
||||||
|
{
|
||||||
|
if (settings == null || !isInit || initing ||
|
||||||
|
(initialization != null && !initialization.IsCompleted) ||
|
||||||
|
(opening != null && !opening.IsCompleted) ||
|
||||||
|
(promptSettings != null && !ReferenceEquals(promptSettings, settings)))
|
||||||
|
throw DefaultSettingService.PromptFailure("ShowNotice: notification handoff is not idle.");
|
||||||
|
}
|
||||||
|
internal void BindFormalPromptSettings(DefaultSettingService settings)
|
||||||
|
{
|
||||||
|
PreflightFormalPromptSettings(settings);
|
||||||
|
if (!settings.HasKVPromptOwner)
|
||||||
|
throw DefaultSettingService.PromptFailure("ShowNotice: notification owner not handed off.");
|
||||||
|
settings.RequirePromptOwner();
|
||||||
|
if (promptSettings == null) promptSettings = settings;
|
||||||
|
RequirePromptOwner(settings);
|
||||||
|
}
|
||||||
|
internal bool HasFormalPromptSettings(DefaultSettingService settings) =>
|
||||||
|
ReferenceEquals(promptSettings, settings);
|
||||||
|
|
||||||
|
public Task Init()
|
||||||
|
{
|
||||||
|
RequirePromptOwner();
|
||||||
|
if (isInit) return Task.CompletedTask;
|
||||||
|
if (initialization != null && !initialization.IsCompleted) return initialization;
|
||||||
|
return initialization = InitCoreAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task InitCoreAsync()
|
||||||
|
{
|
||||||
|
RequirePromptOwner();
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
await System.Threading.Tasks.Task.Yield();
|
await System.Threading.Tasks.Task.Yield();
|
||||||
#else
|
#else
|
||||||
@@ -59,9 +113,11 @@ public class LocalNotificationService : ILocalNotificationService
|
|||||||
Debug.Log("[LocalNotificationService::Init] Channel Inited");
|
Debug.Log("[LocalNotificationService::Init] Channel Inited");
|
||||||
|
|
||||||
await NotificationCenter.RequestPermission();
|
await NotificationCenter.RequestPermission();
|
||||||
|
RequirePromptOwner();
|
||||||
ScheduleDefaultNotification();
|
ScheduleDefaultNotification();
|
||||||
GContext.OnEvent<EventRankData>().Subscribe(ScheduleRankNotification);
|
GContext.OnEvent<EventRankData>().Subscribe(ScheduleRankNotification);
|
||||||
#endif
|
#endif
|
||||||
|
RequirePromptOwner();
|
||||||
isInit = true;
|
isInit = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,14 +142,36 @@ public class LocalNotificationService : ILocalNotificationService
|
|||||||
|
|
||||||
public async void OpenSettings()
|
public async void OpenSettings()
|
||||||
{
|
{
|
||||||
if (initing) return;
|
try { await OpenSettingsAsync(); }
|
||||||
|
catch (Exception ex) { game.DefaultSettingService.LogPromptFailure(ex); }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal Task OpenSettingsAsync()
|
||||||
|
{
|
||||||
|
if (promptSettings == null && GContext.container.Resolve<ISettingService>() is DefaultSettingService pending)
|
||||||
|
pending.RequirePromptOwner();
|
||||||
|
RequirePromptOwner();
|
||||||
|
if (initing && opening == null)
|
||||||
|
throw DefaultSettingService.PromptFailure("ShowNotice: reentrant permission request.");
|
||||||
|
if (opening != null && !opening.IsCompleted) return opening;
|
||||||
|
return opening = OpenSettingsCoreAsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task OpenSettingsCoreAsync()
|
||||||
|
{
|
||||||
|
ISettingService settings = promptSettings ?? GContext.container.Resolve<ISettingService>();
|
||||||
|
RequirePromptOwner(settings);
|
||||||
|
(settings as DefaultSettingService)?.RequirePromptOwner();
|
||||||
initing = true;
|
initing = true;
|
||||||
if (!isInit)
|
try
|
||||||
await Init();
|
{
|
||||||
else
|
if (!isInit) await Init();
|
||||||
NotificationCenter.OpenNotificationSettings();
|
else NotificationCenter.OpenNotificationSettings();
|
||||||
GContext.container.Resolve<ISettingService>().ShowNotice = true;
|
RequirePromptOwner(settings);
|
||||||
initing = false;
|
(settings as DefaultSettingService)?.RequirePromptOwner();
|
||||||
|
settings.ShowNotice = true;
|
||||||
|
}
|
||||||
|
finally { initing = false; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ScheduleDailyNotification(int notificationID, DateTime fireTime, string title, string text)
|
public void ScheduleDailyNotification(int notificationID, DateTime fireTime, string title, string text)
|
||||||
@@ -150,6 +228,8 @@ public class LocalNotificationService : ILocalNotificationService
|
|||||||
|
|
||||||
private void ScheduleRankNotification(EventRankData evt)
|
private void ScheduleRankNotification(EventRankData evt)
|
||||||
{
|
{
|
||||||
|
try { RequirePromptOwner(); }
|
||||||
|
catch (InvalidOperationException ex) { Debug.LogError(ex.Message); return; }
|
||||||
if (rankNotifyScheduled || !IsNoticeOpen || !isInit) return;
|
if (rankNotifyScheduled || !IsNoticeOpen || !isInit) return;
|
||||||
|
|
||||||
Debug.Log("[LocalNotificationService::SendNotification] RankEvent");
|
Debug.Log("[LocalNotificationService::SendNotification] RankEvent");
|
||||||
@@ -170,4 +250,4 @@ public class LocalNotificationService : ILocalNotificationService
|
|||||||
rankNotifyScheduled = true;
|
rankNotifyScheduled = true;
|
||||||
Debug.Log("[LocalNotificationService::SendRankEventNotification] ");
|
Debug.Log("[LocalNotificationService::SendRankEventNotification] ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
|||||||
341
Client/Assets/Scripts/Services/KVUserService.cs
Normal file
341
Client/Assets/Scripts/Services/KVUserService.cs
Normal file
@@ -0,0 +1,341 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Net.Http;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using asap.core;
|
||||||
|
using game.PlayerDataStorage;
|
||||||
|
using GameCore;
|
||||||
|
using tysdk;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace game
|
||||||
|
{
|
||||||
|
// One service belongs to one login lifetime. A revoked instance is never rebound.
|
||||||
|
public sealed class KVUserService : IUserService, IKVUserLoadReceiver, IKVUserLifecycle
|
||||||
|
{
|
||||||
|
[Inject] public ICustomServerMgr customServerMgr { get; set; }
|
||||||
|
[Inject] public IPlayerSaveStore SaveStore { get; set; }
|
||||||
|
readonly PlayerKVRuntimeSelection selection;
|
||||||
|
readonly Func<CookieContainer, HttpMessageHandler> handlerFactory;
|
||||||
|
readonly CancellationTokenSource lifetime = new CancellationTokenSource();
|
||||||
|
readonly Dictionary<string, PlayInfo> profiles = new Dictionary<string, PlayInfo>();
|
||||||
|
readonly Dictionary<string, int> levels = new Dictionary<string, int>();
|
||||||
|
PlayerKVGameLoadCoordinator coordinator;
|
||||||
|
PlayerKVGameSessionHandle handle;
|
||||||
|
PlayerKVInitializationIntents intents;
|
||||||
|
bool attempted, loading, closing, published, promptsBound;
|
||||||
|
Task closeTask;
|
||||||
|
long epoch;
|
||||||
|
string playerId;
|
||||||
|
uint internalId;
|
||||||
|
public string CustomId { get; set; }
|
||||||
|
public string UserId => IsAuthorized ? playerId : null;
|
||||||
|
public string ApiPlayerId => UserId;
|
||||||
|
public uint InternalId => IsAuthorized ? internalId : 0;
|
||||||
|
public bool IsLogin => IsAuthorized;
|
||||||
|
public bool IsAuthorized => published && KVHandoffReady;
|
||||||
|
public CancellationToken LoginLifetime => lifetime.Token;
|
||||||
|
public DateTime LastLoginTime { get; private set; }
|
||||||
|
public DateTime LoginTime { get; private set; }
|
||||||
|
public DateTime CreateTime { get; private set; }
|
||||||
|
public string DisplayName { get; private set; }
|
||||||
|
public string AvatarUrl { get; private set; }
|
||||||
|
public string Language { get; private set; }
|
||||||
|
public string ContinentCode { get; private set; }
|
||||||
|
public Dictionary<string, string> EAccoutUrl { get; private set; } = new Dictionary<string, string>();
|
||||||
|
internal int KVTapJoyBalance { get; private set; }
|
||||||
|
internal PlayerKVGameLoadError KVLastError { get; private set; }
|
||||||
|
internal bool KVHandoffReady => !closing && handle != null && coordinator != null &&
|
||||||
|
coordinator.TryGetCurrentGameHandle(epoch, out var current) && ReferenceEquals(current, handle);
|
||||||
|
bool IKVUserLifecycle.KVHandoffReady => KVHandoffReady;
|
||||||
|
PlayerKVGameLoadError IKVUserLifecycle.KVLastError => KVLastError;
|
||||||
|
|
||||||
|
public KVUserService() : this(SubBoostrap.RuntimeSelection, jar => new HttpClientHandler
|
||||||
|
{ CookieContainer = jar, UseCookies = true, AllowAutoRedirect = false }) { }
|
||||||
|
|
||||||
|
internal KVUserService(PlayerKVRuntimeSelection selection, Func<CookieContainer, HttpMessageHandler> handlerFactory)
|
||||||
|
{
|
||||||
|
this.selection = selection;
|
||||||
|
this.handlerFactory = handlerFactory ?? throw new ArgumentNullException(nameof(handlerFactory));
|
||||||
|
Application.quitting += Logout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<ELoginStep> Login(Action<int> progress, bool tyrLoginByToken = true)
|
||||||
|
{
|
||||||
|
if (attempted || closing || selection == null || !selection.IsKV ||
|
||||||
|
!selection.TryAdmitPlayer(CustomId, out var canonicalId))
|
||||||
|
{ KVLastError = PlayerKVGameLoadError.Input; return ELoginStep.Api; }
|
||||||
|
// Set before the first await: duplicate calls cannot authenticate or subscribe twice.
|
||||||
|
attempted = true;
|
||||||
|
var requestedId = CustomId;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (customServerMgr is not CustomServerMgr server ||
|
||||||
|
server.ApiBaseUri.AbsoluteUri != PlayerKVRuntimeSelection.FormalApiUrl)
|
||||||
|
throw new InvalidOperationException("Formal KV transport required.");
|
||||||
|
loading = true;
|
||||||
|
var transaction = PlayerKVGameplayBindings.Bind(this);
|
||||||
|
coordinator = new PlayerKVGameLoadCoordinator(transaction,
|
||||||
|
() => loading && !closing && !published && handle == null,
|
||||||
|
() => { }, () => intents?.Count ?? 0, server.BindKVForGame, server.ClearKVForGame);
|
||||||
|
server.KVUnauthorized += OnUnauthorized;
|
||||||
|
var identity = new PlayerKVIdentitySnapshot(null, false, PlayerKVIdentityChannel.none,
|
||||||
|
Array.Empty<PlayerKVIdentityChannel>());
|
||||||
|
var snapshot = PlayerKVGameplayBindings.Snapshot(DateTime.UtcNow, "formal-v1");
|
||||||
|
var capability = PlayerKVGameLoadCapability.CreateForGame(identity, snapshot, selection.Api,
|
||||||
|
Application.persistentDataPath, handlerFactory, handlerFactory, handlerFactory);
|
||||||
|
var result = await coordinator.LoadForGameAsync(canonicalId, capability, LoginLifetime,
|
||||||
|
() => !closing && CustomId == requestedId);
|
||||||
|
KVLastError = result.Error;
|
||||||
|
if (result.State != PlayerKVGameLoadState.GameLoaded || closing || CustomId != requestedId ||
|
||||||
|
result.Account == null || result.Account.PlayerId != canonicalId || result.Account.Epoch != result.Epoch ||
|
||||||
|
!coordinator.TryGetCurrentGameHandle(result.Epoch, out var original))
|
||||||
|
{ Logout(); return ELoginStep.Api; }
|
||||||
|
epoch = result.Epoch;
|
||||||
|
handle = original;
|
||||||
|
if (SaveStore is not KVPlayerSaveStore store) throw new InvalidOperationException("KV save store required.");
|
||||||
|
store.Bind(original, LoginLifetime);
|
||||||
|
PrepareProfile(result.Account);
|
||||||
|
BindPromptServices(original);
|
||||||
|
// Chat subscribes before the unique success event. No SDK or analytics initialization here.
|
||||||
|
GContext.container.Resolve<IChatService>().WaitingForLogin();
|
||||||
|
if (!KVHandoffReady || CustomId != requestedId) throw new InvalidOperationException("Stale KV login.");
|
||||||
|
server.EnableKVBusiness(epoch);
|
||||||
|
playerId = result.Account.PlayerId;
|
||||||
|
internalId = result.Account.InternalId;
|
||||||
|
published = true;
|
||||||
|
GContext.Publish(new EvtAPISvrLoginSuccess { playerId = playerId, internalId = internalId });
|
||||||
|
if (!IsAuthorized) return ELoginStep.Api;
|
||||||
|
_ = RunSaveScheduleAsync(store);
|
||||||
|
progress?.Invoke(2);
|
||||||
|
return ELoginStep.Done;
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
KVLastError = PlayerKVGameLoadError.Apply;
|
||||||
|
Debug.LogError("KV login failed: " + ex.GetType().Name);
|
||||||
|
Logout();
|
||||||
|
return ELoginStep.Api;
|
||||||
|
}
|
||||||
|
finally { loading = false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
void PrepareProfile(PlayerKVAccountDescriptor account)
|
||||||
|
{
|
||||||
|
if (account.InternalId == 0 || account.CreateTimeUtc == DateTime.MinValue || account.ServerTimeUtc == DateTime.MinValue)
|
||||||
|
throw new InvalidOperationException("Authenticated account metadata required.");
|
||||||
|
CreateTime = account.CreateTimeUtc;
|
||||||
|
LoginTime = account.ServerTimeUtc;
|
||||||
|
var previous = Read("LastLoginTimeUtc");
|
||||||
|
LastLoginTime = ParseLastLoginTime(previous.Value, previous.Found.Value);
|
||||||
|
DisplayName = Read("DisplayName").Value;
|
||||||
|
if (string.IsNullOrEmpty(DisplayName)) DisplayName = GetDefaultName(account.PlayerId);
|
||||||
|
AvatarUrl = Read("AvatarUrl").Value ?? string.Empty;
|
||||||
|
Language = Read("Language").Value;
|
||||||
|
if (string.IsNullOrEmpty(Language)) Language = GContext.container.Resolve<ISettingService>().Lang;
|
||||||
|
var continent = Read("ContinentCode").Value;
|
||||||
|
ContinentCode = new[] { "AF", "AN", "AS", "EU", "NA", "OC", "SA" }.Contains(continent) ? continent : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static DateTime ParseLastLoginTime(string value, bool found)
|
||||||
|
{
|
||||||
|
if (!found) return DateTime.MinValue;
|
||||||
|
if (!DateTime.TryParseExact(value, "O", CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out var time) ||
|
||||||
|
time == DateTime.MinValue || time.Kind == DateTimeKind.Unspecified)
|
||||||
|
throw new FormatException("Invalid LastLoginTimeUtc.");
|
||||||
|
return time.ToUniversalTime();
|
||||||
|
}
|
||||||
|
|
||||||
|
PlayerSaveReadResult Read(string key)
|
||||||
|
{
|
||||||
|
var result = SaveStore.Read(key);
|
||||||
|
if (!result.Success) throw new InvalidOperationException("KV profile read failed: " + result.Error);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BindPromptServices(PlayerKVGameSessionHandle original)
|
||||||
|
{
|
||||||
|
if (promptsBound || !KVHandoffReady) throw new InvalidOperationException("Prompt binding is stale.");
|
||||||
|
var settings = GContext.container.Resolve<ISettingService>() as DefaultSettingService;
|
||||||
|
var notifications = GContext.container.Resolve<ILocalNotificationService>() as LocalNotificationService;
|
||||||
|
var club = GContext.container.Resolve<ClubService>();
|
||||||
|
if (settings == null || notifications == null || club == null ||
|
||||||
|
!ReferenceEquals(settings, GContext.container.Resolve<ISettingService>()) ||
|
||||||
|
!ReferenceEquals(notifications, GContext.container.Resolve<ILocalNotificationService>()) ||
|
||||||
|
!ReferenceEquals(club, GContext.container.Resolve<ClubService>()))
|
||||||
|
throw new InvalidOperationException("Formal prompt services required.");
|
||||||
|
settings.PreflightFormalPromptOwner(original);
|
||||||
|
club.PreflightFormalPromptOwner(original);
|
||||||
|
notifications.PreflightFormalPromptSettings(settings);
|
||||||
|
promptsBound = true;
|
||||||
|
settings.BindFormalPromptOwner(original);
|
||||||
|
club.BindFormalPromptOwner(original);
|
||||||
|
notifications.BindFormalPromptSettings(settings);
|
||||||
|
if (!settings.HasFormalPromptOwner(original) || !club.HasFormalPromptOwner(original) ||
|
||||||
|
!notifications.HasFormalPromptSettings(settings) || !KVHandoffReady)
|
||||||
|
throw new InvalidOperationException("Formal prompt binding changed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
void OnUnauthorized(int version)
|
||||||
|
{
|
||||||
|
if (version == customServerMgr.SessionVersion) Logout();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Logout() => ObserveClose(CloseKVForValidationAsync());
|
||||||
|
async void ObserveClose(Task task)
|
||||||
|
{
|
||||||
|
try { await task; }
|
||||||
|
catch (Exception ex) { Debug.LogError("KV close failed: " + ex.GetType().Name); }
|
||||||
|
}
|
||||||
|
internal Task CloseKVForValidationAsync()
|
||||||
|
{
|
||||||
|
if (closeTask != null) return closeTask;
|
||||||
|
closing = true;
|
||||||
|
published = false;
|
||||||
|
(SaveStore as KVPlayerSaveStore)?.Dispose();
|
||||||
|
playerId = null; internalId = 0; handle = null; epoch = 0;
|
||||||
|
DisplayName = AvatarUrl = Language = ContinentCode = null;
|
||||||
|
ClearPlayInfos();
|
||||||
|
Application.quitting -= Logout;
|
||||||
|
if (customServerMgr is CustomServerMgr server)
|
||||||
|
{
|
||||||
|
server.KVUnauthorized -= OnUnauthorized;
|
||||||
|
server.DisableKVBusiness();
|
||||||
|
}
|
||||||
|
// Revoke first; a synchronous cancellation callback must already see invalid identity.
|
||||||
|
closeTask = coordinator?.Revoke() ?? Task.CompletedTask;
|
||||||
|
lifetime.Cancel();
|
||||||
|
return closeTask;
|
||||||
|
}
|
||||||
|
Task IKVUserLifecycle.CloseKVForValidationAsync() => CloseKVForValidationAsync();
|
||||||
|
internal Task<PlayerKVShutdownStatus> ObserveKVQuitAsync() =>
|
||||||
|
coordinator?.ObserveQuitAsync() ?? Task.FromResult(PlayerKVShutdownStatus.Ready);
|
||||||
|
Task<PlayerKVShutdownStatus> IKVUserLifecycle.ObserveKVQuitAsync() => ObserveKVQuitAsync();
|
||||||
|
|
||||||
|
void IKVUserLoadReceiver.ResetForKVLoad()
|
||||||
|
{
|
||||||
|
if ((!loading && !closing) || published || handle != null)
|
||||||
|
throw new InvalidOperationException("KV identity must be unpublished during load/reset.");
|
||||||
|
intents?.Discard(); intents = null;
|
||||||
|
EAccoutUrl = new Dictionary<string, string>(); KVTapJoyBalance = 0;
|
||||||
|
}
|
||||||
|
void IKVUserLoadReceiver.ReplaceFromKVDecoded(PlayerKVLoginState state, long loadEpoch, IReadOnlyDictionary<string, string> raw)
|
||||||
|
{
|
||||||
|
if (!loading || closing || published || handle != null || state == null || raw == null)
|
||||||
|
throw new InvalidOperationException("KV load receiver is not current.");
|
||||||
|
intents = new PlayerKVInitializationIntents(loadEpoch, state.Channel);
|
||||||
|
foreach (var pair in state.Normalizations) intents.Add(loadEpoch, pair.Key, pair.Value);
|
||||||
|
EAccoutUrl = state.AccountUrls.ToDictionary(p => p.Key, p => p.Value, StringComparer.Ordinal);
|
||||||
|
KVTapJoyBalance = state.TapJoyBalance;
|
||||||
|
}
|
||||||
|
void IKVUserLoadReceiver.DiscardKVIntents() => intents?.Discard();
|
||||||
|
|
||||||
|
async Task SaveProfile(string key, string value)
|
||||||
|
{
|
||||||
|
var store = SaveStore;
|
||||||
|
if (!IsAuthorized || store == null) throw new InvalidOperationException("KV identity unavailable.");
|
||||||
|
var result = await store.WriteAndConfirmAsync(key, value, LoginLifetime);
|
||||||
|
if (!IsAuthorized || !ReferenceEquals(store, SaveStore) || !store.IsCurrent || !result.Confirmed)
|
||||||
|
throw new InvalidOperationException("KV profile save was not confirmed.");
|
||||||
|
}
|
||||||
|
|
||||||
|
async Task RunSaveScheduleAsync(IPlayerSaveStore store)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
while (IsAuthorized && store.IsCurrent)
|
||||||
|
{
|
||||||
|
await Task.Delay(TimeSpan.FromSeconds(40), LoginLifetime);
|
||||||
|
if (!IsAuthorized || !store.IsCurrent) return;
|
||||||
|
var result = await store.FlushAsync(LoginLifetime);
|
||||||
|
if (!result.Confirmed && !LoginLifetime.IsCancellationRequested)
|
||||||
|
Debug.LogWarning("KV scheduled save: " + result.Status);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (OperationCanceledException) { }
|
||||||
|
catch (Exception ex) { Debug.LogError("KV save scheduler failed: " + ex.GetType().Name); }
|
||||||
|
}
|
||||||
|
public async Task<string> ChangeDisplayName(string newName)
|
||||||
|
{
|
||||||
|
await SaveProfile("DisplayName", newName);
|
||||||
|
DisplayName = newName; GContext.Publish(new ChangeAvatarEvent()); UpdateProfile(); return newName;
|
||||||
|
}
|
||||||
|
public async Task<string> UpdateAvatarUrl(string url)
|
||||||
|
{
|
||||||
|
await SaveProfile("AvatarUrl", url);
|
||||||
|
AvatarUrl = url; GContext.Publish(new ChangeAvatarEvent()); UpdateProfile(); return url;
|
||||||
|
}
|
||||||
|
public async Task<string> UpdateLanguage(string code)
|
||||||
|
{ await SaveProfile("Language", code); Language = code; return code; }
|
||||||
|
public double CreateTotalSeconds() => (ZZTimeHelper.UtcNow() - CreateTime).TotalSeconds;
|
||||||
|
// The non-AGG channel has no account-link operation; never manufacture a successful binding.
|
||||||
|
public Task<(int code, int userid)> LinkAccount(EAccoutType type) => Task.FromResult((1, 0));
|
||||||
|
public Task<bool> GetLinkState(EAccoutType type) => Task.FromResult(false);
|
||||||
|
public string GetDefaultName(string id) => "Angler#" + (string.IsNullOrEmpty(id) ? string.Empty : id.Substring(0, Math.Min(5, id.Length)));
|
||||||
|
public void SetPlayerLv(string id, int level) => levels[id] = id == UserId ? GContext.container.Resolve<PlayerData>().lv : level;
|
||||||
|
public int GetPlayerLv(string id) => levels.TryGetValue(id, out var level) ? level : 1;
|
||||||
|
public Task<(string, int)> GetPlayLv(string id)
|
||||||
|
{
|
||||||
|
var level = id == UserId && IsAuthorized ? (int)GContext.container.Resolve<PlayerData>().lv :
|
||||||
|
id != null && levels.TryGetValue(id, out var cachedLevel) ? cachedLevel : -1;
|
||||||
|
return level >= 0 ? Task.FromResult((id, level)) :
|
||||||
|
Task.FromException<(string, int)>(new InvalidOperationException("Public player level has not been loaded."));
|
||||||
|
}
|
||||||
|
public PlayInfo GetPlayInfo(string id)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(id)) return null;
|
||||||
|
if (!profiles.TryGetValue(id, out var profile))
|
||||||
|
{
|
||||||
|
profile = new PlayInfo { name = GetDefaultName(id) };
|
||||||
|
profiles.Add(id, profile);
|
||||||
|
SetPlayInfo(id, profile);
|
||||||
|
}
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
async void SetPlayInfo(string id, PlayInfo profile)
|
||||||
|
{
|
||||||
|
if (id == UserId)
|
||||||
|
{
|
||||||
|
profile.name = DisplayName;
|
||||||
|
profile.avatarUrl = AvatarUrl;
|
||||||
|
GContext.Publish(new GetClubPlayInfoEvent { id = id, name = profile.name, avatarUrl = profile.avatarUrl });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var json = await customServerMgr.FriendRequest("SearchFriend", new SearchFriendReq { PlayFabId = id });
|
||||||
|
if (string.IsNullOrEmpty(json)) return;
|
||||||
|
SearchFriendResp result;
|
||||||
|
try { result = Newtonsoft.Json.JsonConvert.DeserializeObject<SearchFriendResp>(json); }
|
||||||
|
catch (Newtonsoft.Json.JsonException ex)
|
||||||
|
{
|
||||||
|
Debug.LogError("KV player profile response failed: " + ex.GetType().Name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (result != null && result.Code > 0 && result.Info != null)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrEmpty(result.Info.DisplayName)) profile.name = result.Info.DisplayName;
|
||||||
|
profile.avatarUrl = result.Info.AvatarUrl;
|
||||||
|
GContext.Publish(new GetClubPlayInfoEvent { id = id, name = profile.name, avatarUrl = profile.avatarUrl });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public void SetPlayInfo(string id, string name, string avatarUrl)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(id)) return;
|
||||||
|
profiles[id] = new PlayInfo { name = string.IsNullOrEmpty(name) ? GetDefaultName(id) : name, avatarUrl = avatarUrl };
|
||||||
|
}
|
||||||
|
public void ClearPlayInfos() { profiles.Clear(); levels.Clear(); }
|
||||||
|
public void UpdateProfile()
|
||||||
|
{
|
||||||
|
if (IsAuthorized) customServerMgr.AccountRequest("UpdateProfile", new LoginRequest { playerId = ApiPlayerId,
|
||||||
|
playerProfile = new PlayerProfile { Level = GContext.container.Resolve<PlayerData>().lv, Avatar = AvatarUrl, DisplayName = DisplayName } });
|
||||||
|
}
|
||||||
|
public void UpdateProfileLv()
|
||||||
|
{
|
||||||
|
if (IsAuthorized) customServerMgr.AccountRequest("UpdateProfile", new LoginRequest { playerId = ApiPlayerId,
|
||||||
|
playerProfile = new PlayerProfile { Level = GContext.container.Resolve<PlayerData>().lv } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Client/Assets/Scripts/Services/KVUserService.cs.meta
Normal file
2
Client/Assets/Scripts/Services/KVUserService.cs.meta
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: e146290e7ecd4db58dbeb536ace8a092
|
||||||
8
Client/Assets/Scripts/Services/PlayerData.meta
Normal file
8
Client/Assets/Scripts/Services/PlayerData.meta
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 761582591ce048769d522f8410c647cc
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace game.PlayerDataStorage
|
||||||
|
{
|
||||||
|
internal interface IKVUserLifecycle
|
||||||
|
{
|
||||||
|
bool KVHandoffReady { get; }
|
||||||
|
PlayerKVGameLoadError KVLastError { get; }
|
||||||
|
Task CloseKVForValidationAsync();
|
||||||
|
Task<PlayerKVShutdownStatus> ObserveKVQuitAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 12a766df765ed0d4981d8da38eead5e3
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace game.PlayerDataStorage
|
||||||
|
{
|
||||||
|
internal interface IKVUserLoadReceiver
|
||||||
|
{
|
||||||
|
void ResetForKVLoad();
|
||||||
|
void ReplaceFromKVDecoded(PlayerKVLoginState state, long epoch, IReadOnlyDictionary<string, string> raw);
|
||||||
|
void DiscardKVIntents();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 8cda3d2b981ada043af2162ca707d8bf
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
using System;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace game.PlayerDataStorage
|
||||||
|
{
|
||||||
|
// A store belongs to one login. Callers retain this instance across awaits.
|
||||||
|
public interface IPlayerSaveStore
|
||||||
|
{
|
||||||
|
bool IsCurrent { get; }
|
||||||
|
PlayerSaveReadResult Read(string key);
|
||||||
|
PlayerSaveWriteResult Write(string key, string value, bool remoteStore = true);
|
||||||
|
Task<PlayerSaveConfirmation> WriteAndConfirmAsync(string key, string value, CancellationToken token = default);
|
||||||
|
Task<PlayerSaveConfirmation> ConfirmAsync(PlayerSaveReceipt receipt, CancellationToken token = default);
|
||||||
|
Task<PlayerSaveConfirmation> FlushAsync(CancellationToken token = default);
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class PlayerSaveReadResult
|
||||||
|
{
|
||||||
|
public bool Success => Error == null;
|
||||||
|
public bool? Found { get; }
|
||||||
|
public string Value { get; }
|
||||||
|
public string Error { get; }
|
||||||
|
internal PlayerSaveReadResult(bool found, string value) { Found = found; Value = value; }
|
||||||
|
internal PlayerSaveReadResult(string error) { Error = error ?? "ReadFailed"; }
|
||||||
|
public string ValueOrThrow()
|
||||||
|
{
|
||||||
|
if (!Success) throw new InvalidOperationException("Player save read failed: " + Error);
|
||||||
|
return Value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class PlayerSaveReceipt
|
||||||
|
{
|
||||||
|
internal readonly IPlayerSaveStore Store;
|
||||||
|
internal readonly object Ticket;
|
||||||
|
internal PlayerSaveReceipt(IPlayerSaveStore store, object ticket) { Store = store; Ticket = ticket; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public sealed class PlayerSaveWriteResult
|
||||||
|
{
|
||||||
|
public bool Accepted => Error == null;
|
||||||
|
public string Error { get; }
|
||||||
|
public PlayerSaveReceipt Receipt { get; }
|
||||||
|
internal PlayerSaveWriteResult(PlayerSaveReceipt receipt) { Receipt = receipt; }
|
||||||
|
internal PlayerSaveWriteResult(string error) { Error = error ?? "WriteRejected"; }
|
||||||
|
public void RequireAccepted()
|
||||||
|
{
|
||||||
|
if (!Accepted) throw new InvalidOperationException("Player save write rejected: " + Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buffered and LocalOnly are deliberately different from cloud confirmation.
|
||||||
|
public enum PlayerSaveStatus { Confirmed, Buffered, LocalOnly, Rejected, Superseded, Unknown, Cancelled }
|
||||||
|
public sealed class PlayerSaveConfirmation
|
||||||
|
{
|
||||||
|
public PlayerSaveStatus Status { get; }
|
||||||
|
public bool Confirmed => Status == PlayerSaveStatus.Confirmed;
|
||||||
|
public string Error { get; }
|
||||||
|
internal PlayerSaveConfirmation(PlayerSaveStatus status, string error = null) { Status = status; Error = error; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: f7a9c9b2dab8e5a4ca300f0bcf6637e8
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
105
Client/Assets/Scripts/Services/PlayerData/PlayerKVCacheStore.cs
Normal file
105
Client/Assets/Scripts/Services/PlayerData/PlayerKVCacheStore.cs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Security;
|
||||||
|
using System.Text;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace game.PlayerDataStorage
|
||||||
|
{
|
||||||
|
// Internal seam for deterministic disk-failure tests; no production callback is supplied.
|
||||||
|
internal enum KVCacheWriteStage { BeforeWrite, AfterWrite, AfterFlush, BeforeReplace, AfterReplace }
|
||||||
|
|
||||||
|
internal sealed class PlayerKVCacheStore : IDisposable
|
||||||
|
{
|
||||||
|
const long MaxBytes = 64L * 1024 * 1024;
|
||||||
|
readonly KVIdentity identity;
|
||||||
|
readonly FileStream lease;
|
||||||
|
readonly Action<KVCacheWriteStage> fault;
|
||||||
|
readonly string main, temporary, backup;
|
||||||
|
bool disposed;
|
||||||
|
|
||||||
|
PlayerKVCacheStore(KVIdentity identity, FileStream lease, Action<KVCacheWriteStage> fault)
|
||||||
|
{
|
||||||
|
this.identity = identity; this.lease = lease; this.fault = fault;
|
||||||
|
main = Path.Combine(identity.DirectoryPath, "state.json");
|
||||||
|
temporary = main + ".tmp"; backup = main + ".bak";
|
||||||
|
}
|
||||||
|
|
||||||
|
internal static PlayerKVOpenError Open(KVIdentity identity, Action<KVCacheWriteStage> fault,
|
||||||
|
out PlayerKVCacheStore store, out KVSnapshot snapshot)
|
||||||
|
{
|
||||||
|
store = null; snapshot = null;
|
||||||
|
FileStream lease = null;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Directory.CreateDirectory(identity.DirectoryPath);
|
||||||
|
try { lease = new FileStream(Path.Combine(identity.DirectoryPath, "state.lock"), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.None); }
|
||||||
|
catch (IOException ex) when ((ex.HResult & 0xffff) == 32 || (ex.HResult & 0xffff) == 33)
|
||||||
|
{ return PlayerKVOpenError.Busy; }
|
||||||
|
store = new PlayerKVCacheStore(identity, lease, fault);
|
||||||
|
if (!File.Exists(store.main))
|
||||||
|
{
|
||||||
|
if (File.Exists(store.backup) || File.Exists(store.temporary)) throw KVSnapshot.Invalid();
|
||||||
|
snapshot = new KVSnapshot();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (new FileInfo(store.main).Length > MaxBytes) throw KVSnapshot.Invalid();
|
||||||
|
snapshot = KVSnapshot.Decode(File.ReadAllText(store.main, new UTF8Encoding(false, true)), identity);
|
||||||
|
}
|
||||||
|
return PlayerKVOpenError.None;
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (ex is JsonException || ex is OverflowException || ex is FormatException || ex is DecoderFallbackException)
|
||||||
|
{
|
||||||
|
store?.Dispose(); lease?.Dispose(); store = null;
|
||||||
|
return PlayerKVOpenError.RecoveryRequired;
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (DiskError(ex))
|
||||||
|
{
|
||||||
|
store?.Dispose(); lease?.Dispose(); store = null;
|
||||||
|
return PlayerKVOpenError.StorageError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal bool Save(KVSnapshot snapshot, out bool mayHaveCommitted)
|
||||||
|
{
|
||||||
|
mayHaveCommitted = false;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (disposed) throw new ObjectDisposedException(nameof(PlayerKVCacheStore));
|
||||||
|
snapshot.Validate();
|
||||||
|
var bytes = new UTF8Encoding(false, true).GetBytes(snapshot.Encode(identity));
|
||||||
|
if (bytes.LongLength > MaxBytes) throw new IOException("KV cache capacity exceeded.");
|
||||||
|
fault?.Invoke(KVCacheWriteStage.BeforeWrite);
|
||||||
|
using (var stream = new FileStream(temporary, FileMode.Create, FileAccess.Write, FileShare.None))
|
||||||
|
{
|
||||||
|
stream.Write(bytes, 0, bytes.Length);
|
||||||
|
fault?.Invoke(KVCacheWriteStage.AfterWrite);
|
||||||
|
stream.Flush(true);
|
||||||
|
fault?.Invoke(KVCacheWriteStage.AfterFlush);
|
||||||
|
}
|
||||||
|
fault?.Invoke(KVCacheWriteStage.BeforeReplace);
|
||||||
|
mayHaveCommitted = true;
|
||||||
|
// The temp file is on the same filesystem. Never delete the main file first.
|
||||||
|
if (File.Exists(main)) File.Replace(temporary, main, backup);
|
||||||
|
else File.Move(temporary, main);
|
||||||
|
fault?.Invoke(KVCacheWriteStage.AfterReplace);
|
||||||
|
mayHaveCommitted = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
catch (Exception ex) when (DiskError(ex) || ex is JsonException || ex is EncoderFallbackException)
|
||||||
|
{ return false; }
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool DiskError(Exception ex) => ex is IOException || ex is UnauthorizedAccessException ||
|
||||||
|
ex is SecurityException || ex is NotSupportedException || ex is ObjectDisposedException;
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
if (disposed) return;
|
||||||
|
disposed = true;
|
||||||
|
lease.Dispose();
|
||||||
|
// Keep files, including failed temporary writes, for explicit recovery diagnosis.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bb1e30eab9b24686a5b5110bc68c19b6
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user