Skip to content

Commit e830392

Browse files
authored
feat(reward): 实现统一奖励发放接口一期 (#85)
新增玩家粒度统一奖励发放入口 RewardGrantComponentAgent.GrantAsync, 作为邮件/补偿/兑换码/活动等业务发放资产的唯一接口: - Apps 契约层:RewardType(普通道具 + 5 预留位)/RewardSourceType/ RewardItem/RewardGrantRequest/Result/ItemResult/Record/RecordState/ RewardGrantComponent,全部带中文 XML 注释 - Hotfix:RewardGrantComponentAgent.[Service] GrantAsync,幂等键 RoleId:SourceType:SourceId:TraceId(B6)短路返回上次结果; 按 RewardType 路由,NormalItem 复用 BagComponentAgent.UpdateChanged 写背包(在线推 notify、离线只持久化),其余类型返回 Unsupported - Proto:OperationStatusCode 追加 Unsupported/InvalidReward/PartialSuccess - BagComponentAgent.UpdateChanged 加 null 通道守卫以支持离线发放 一期不实现邮件系统与隐藏资产路径,仅落地普通道具路由并预留扩展位。 Linear: GFX-137
1 parent c8074f1 commit e830392

11 files changed

Lines changed: 777 additions & 1 deletion

File tree

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// ==========================================================================================
2+
// GameFrameX 组织及其衍生项目的版权、商标、专利及其他相关权利
3+
// GameFrameX organization and its derivative projects' copyrights, trademarks, patents, and related rights
4+
// 均受中华人民共和国及相关国际法律法规保护。
5+
// are protected by the laws of the People's Republic of China and relevant international regulations.
6+
//
7+
// 使用本项目须严格遵守相应法律法规及开源许可证之规定。
8+
// Usage of this project must strictly comply with applicable laws, regulations, and open-source licenses.
9+
//
10+
// 本项目采用 MIT 许可证与 Apache License 2.0 双许可证分发,
11+
// This project is dual-licensed under the MIT License and Apache License 2.0,
12+
// 完整许可证文本请参见源代码根目录下的 LICENSE 文件。
13+
// please refer to the LICENSE file in the root directory of the source code for the full license text.
14+
//
15+
// 禁止利用本项目实施任何危害国家安全、破坏社会秩序、
16+
// It is prohibited to use this project to engage in any activities that endanger national security, disrupt social order,
17+
// 侵犯他人合法权益等法律法规所禁止的行为!
18+
// or infringe upon the legitimate rights and interests of others, as prohibited by laws and regulations!
19+
// 因基于本项目二次开发所产生的一切法律纠纷与责任,
20+
// Any legal disputes and liabilities arising from secondary development based on this project
21+
// 本项目组织与贡献者概不承担。
22+
// shall be borne solely by the developer; the project organization and contributors assume no responsibility.
23+
//
24+
// GitHub 仓库:https://github.com/GameFrameX
25+
// GitHub Repository: https://github.com/GameFrameX
26+
// Gitee 仓库:https://gitee.com/GameFrameX
27+
// Gitee Repository: https://gitee.com/GameFrameX
28+
// 官方文档:https://gameframex.doc.alianblank.com/
29+
// Official Documentation: https://gameframex.doc.alianblank.com/
30+
// ==========================================================================================
31+
32+
using GameFrameX.Apps.Player.Reward.Entity;
33+
34+
namespace GameFrameX.Apps.Player.Reward.Component;
35+
36+
/// <summary>
37+
/// 统一奖励发放组件,挂载玩家粒度的发放幂等账本 <see cref="RewardGrantRecordState"/>。
38+
/// </summary>
39+
/// <remarks>
40+
/// 通过 <c>[ComponentType(GlobalConst.ActorTypePlayer)]</c> 绑定到玩家 Actor,
41+
/// 与背包、玩家等组件并列;发放代理 <c>RewardGrantComponentAgent</c> 提供跨组件可调用的 <c>GrantAsync</c>。
42+
/// </remarks>
43+
[ComponentType(GlobalConst.ActorTypePlayer)]
44+
public sealed class RewardGrantComponent : StateComponent<RewardGrantRecordState>
45+
{
46+
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// ==========================================================================================
2+
// GameFrameX 组织及其衍生项目的版权、商标、专利及其他相关权利
3+
// GameFrameX organization and its derivative projects' copyrights, trademarks, patents, and related rights
4+
// 均受中华人民共和国及相关国际法律法规保护。
5+
// are protected by the laws of the People's Republic of China and relevant international regulations.
6+
//
7+
// 使用本项目须严格遵守相应法律法规及开源许可证之规定。
8+
// Usage of this project must strictly comply with applicable laws, regulations, and open-source licenses.
9+
//
10+
// 本项目采用 MIT 许可证与 Apache License 2.0 双许可证分发,
11+
// This project is dual-licensed under the MIT License and Apache License 2.0,
12+
// 完整许可证文本请参见源代码根目录下的 LICENSE 文件。
13+
// please refer to the LICENSE file in the root directory of the source code for the full license text.
14+
//
15+
// 禁止利用本项目实施任何危害国家安全、破坏社会秩序、
16+
// It is prohibited to use this project to engage in any activities that endanger national security, disrupt social order,
17+
// 侵犯他人合法权益等法律法规所禁止的行为!
18+
// or infringe upon the legitimate rights and interests of others, as prohibited by laws and regulations!
19+
// 因基于本项目二次开发所产生的一切法律纠纷与责任,
20+
// Any legal disputes and liabilities arising from secondary development based on this project
21+
// 本项目组织与贡献者概不承担。
22+
// shall be borne solely by the developer; the project organization and contributors assume no responsibility.
23+
//
24+
// GitHub 仓库:https://github.com/GameFrameX
25+
// GitHub Repository: https://github.com/GameFrameX
26+
// Gitee 仓库:https://gitee.com/GameFrameX
27+
// Gitee Repository: https://gitee.com/GameFrameX
28+
// 官方文档:https://gameframex.doc.alianblank.com/
29+
// Official Documentation: https://gameframex.doc.alianblank.com/
30+
// ==========================================================================================
31+
32+
namespace GameFrameX.Apps.Player.Reward.Entity;
33+
34+
/// <summary>
35+
/// 统一奖励发放接口的单项发放结果。
36+
/// </summary>
37+
/// <remarks>
38+
/// 该结构同时作为幂等账本 <see cref="RewardGrantRecord"/> 的逐项快照持久化,使重复提交可短路返回上次结果(B6)。
39+
/// </remarks>
40+
public sealed class RewardGrantItemResult
41+
{
42+
/// <summary>
43+
/// 奖励类型。
44+
/// </summary>
45+
public RewardType RewardType { get; set; }
46+
47+
/// <summary>
48+
/// 物品 ID。
49+
/// </summary>
50+
public int ItemId { get; set; }
51+
52+
/// <summary>
53+
/// 数量。
54+
/// </summary>
55+
public long Count { get; set; }
56+
57+
/// <summary>
58+
/// 是否发放成功。
59+
/// </summary>
60+
public bool Success { get; set; }
61+
62+
/// <summary>
63+
/// 该项错误码(<c>OperationStatusCode</c> 整数值):<c>Ok</c>/<c>Unsupported</c>/<c>InvalidReward</c> 等。
64+
/// </summary>
65+
public int ErrorCode { get; set; }
66+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
// ==========================================================================================
2+
// GameFrameX 组织及其衍生项目的版权、商标、专利及其他相关权利
3+
// GameFrameX organization and its derivative projects' copyrights, trademarks, patents, and related rights
4+
// 均受中华人民共和国及相关国际法律法规保护。
5+
// are protected by the laws of the People's Republic of China and relevant international regulations.
6+
//
7+
// 使用本项目须严格遵守相应法律法规及开源许可证之规定。
8+
// Usage of this project must strictly comply with applicable laws, regulations, and open-source licenses.
9+
//
10+
// 本项目采用 MIT 许可证与 Apache License 2.0 双许可证分发,
11+
// This project is dual-licensed under the MIT License and Apache License 2.0,
12+
// 完整许可证文本请参见源代码根目录下的 LICENSE 文件。
13+
// please refer to the LICENSE file in the root directory of the source code for the full license text.
14+
//
15+
// 禁止利用本项目实施任何危害国家安全、破坏社会秩序、
16+
// It is prohibited to use this project to engage in any activities that endanger national security, disrupt social order,
17+
// 侵犯他人合法权益等法律法规所禁止的行为!
18+
// or infringe upon the legitimate rights and interests of others, as prohibited by laws and regulations!
19+
// 因基于本项目二次开发所产生的一切法律纠纷与责任,
20+
// Any legal disputes and liabilities arising from secondary development based on this project
21+
// 本项目组织与贡献者概不承担。
22+
// shall be borne solely by the developer; the project organization and contributors assume no responsibility.
23+
//
24+
// GitHub 仓库:https://github.com/GameFrameX
25+
// GitHub Repository: https://github.com/GameFrameX
26+
// Gitee 仓库:https://gitee.com/GameFrameX
27+
// Gitee Repository: https://gitee.com/GameFrameX
28+
// 官方文档:https://gameframex.doc.alianblank.com/
29+
// Official Documentation: https://gameframex.doc.alianblank.com/
30+
// ==========================================================================================
31+
32+
namespace GameFrameX.Apps.Player.Reward.Entity;
33+
34+
/// <summary>
35+
/// 统一奖励发放的一次幂等账本记录,存储在玩家 <see cref="RewardGrantRecordState"/> 中。
36+
/// </summary>
37+
/// <remarks>
38+
/// 该记录是发放幂等(B6)的事实来源:同一 <see cref="TraceKey"/> 再次提交时,发放接口直接读取本记录返回上次结果,
39+
/// 不重复写背包、不重复扣附件。记录一旦写入即不可变(不更新、不删除,一期无 TTL / 容量回收)。
40+
/// </remarks>
41+
public sealed class RewardGrantRecord
42+
{
43+
/// <summary>
44+
/// 幂等键,格式 <c>RoleId:SourceType:SourceId:TraceId</c>。
45+
/// </summary>
46+
public string TraceKey { get; set; }
47+
48+
/// <summary>
49+
/// 来源类型(冗余存储,便于审计)。
50+
/// </summary>
51+
public int SourceType { get; set; }
52+
53+
/// <summary>
54+
/// 来源 ID(冗余存储,便于审计)。
55+
/// </summary>
56+
public string SourceId { get; set; }
57+
58+
/// <summary>
59+
/// 调用方追踪 ID(冗余存储,便于审计)。
60+
/// </summary>
61+
public string TraceId { get; set; }
62+
63+
/// <summary>
64+
/// 发放完成的 unix 秒。
65+
/// </summary>
66+
public long GrantedAt { get; set; }
67+
68+
/// <summary>
69+
/// 是否全部成功。
70+
/// </summary>
71+
public bool AllSuccess { get; set; }
72+
73+
/// <summary>
74+
/// 整体错误码(<c>OperationStatusCode</c> 整数值)。
75+
/// </summary>
76+
public int ErrorCode { get; set; }
77+
78+
/// <summary>
79+
/// 逐项发放结果快照。重复提交时据此重建返回结果。
80+
/// </summary>
81+
public List<RewardGrantItemResult> Items { get; set; } = new List<RewardGrantItemResult>();
82+
}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// ==========================================================================================
2+
// GameFrameX 组织及其衍生项目的版权、商标、专利及其他相关权利
3+
// GameFrameX organization and its derivative projects' copyrights, trademarks, patents, and related rights
4+
// 均受中华人民共和国及相关国际法律法规保护。
5+
// are protected by the laws of the People's Republic of China and relevant international regulations.
6+
//
7+
// 使用本项目须严格遵守相应法律法规及开源许可证之规定。
8+
// Usage of this project must strictly comply with applicable laws, regulations, and open-source licenses.
9+
//
10+
// 本项目采用 MIT 许可证与 Apache License 2.0 双许可证分发,
11+
// This project is dual-licensed under the MIT License and Apache License 2.0,
12+
// 完整许可证文本请参见源代码根目录下的 LICENSE 文件。
13+
// please refer to the LICENSE file in the root directory of the source code for the full license text.
14+
//
15+
// 禁止利用本项目实施任何危害国家安全、破坏社会秩序、
16+
// It is prohibited to use this project to engage in any activities that endanger national security, disrupt social order,
17+
// 侵犯他人合法权益等法律法规所禁止的行为!
18+
// or infringe upon the legitimate rights and interests of others, as prohibited by laws and regulations!
19+
// 因基于本项目二次开发所产生的一切法律纠纷与责任,
20+
// Any legal disputes and liabilities arising from secondary development based on this project
21+
// 本项目组织与贡献者概不承担。
22+
// shall be borne solely by the developer; the project organization and contributors assume no responsibility.
23+
//
24+
// GitHub 仓库:https://github.com/GameFrameX
25+
// GitHub Repository: https://github.com/GameFrameX
26+
// Gitee 仓库:https://gitee.com/GameFrameX
27+
// Gitee Repository: https://gitee.com/GameFrameX
28+
// 官方文档:https://gameframex.doc.alianblank.com/
29+
// Official Documentation: https://gameframex.doc.alianblank.com/
30+
// ==========================================================================================
31+
32+
namespace GameFrameX.Apps.Player.Reward.Entity;
33+
34+
/// <summary>
35+
/// 玩家统一奖励发放幂等账本状态。每玩家一份,挂在玩家 Actor 的 <see cref="Component.RewardGrantComponent"/> 上。
36+
/// </summary>
37+
/// <remarks>
38+
/// 账本键为发放幂等键 <c>RoleId:SourceType:SourceId:TraceId</c>(B6)。
39+
/// 一期无 TTL / 容量回收(邮件附件每玩家有限,实际增长受玩法约束;retention 留 follow-up)。
40+
/// </remarks>
41+
public sealed class RewardGrantRecordState : CacheState
42+
{
43+
/// <summary>
44+
/// 幂等键到发放记录的映射。键格式 <c>RoleId:SourceType:SourceId:TraceId</c>。
45+
/// </summary>
46+
public Dictionary<string, RewardGrantRecord> Records { get; set; } = new Dictionary<string, RewardGrantRecord>();
47+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// ==========================================================================================
2+
// GameFrameX 组织及其衍生项目的版权、商标、专利及其他相关权利
3+
// GameFrameX organization and its derivative projects' copyrights, trademarks, patents, and related rights
4+
// 均受中华人民共和国及相关国际法律法规保护。
5+
// are protected by the laws of the People's Republic of China and relevant international regulations.
6+
//
7+
// 使用本项目须严格遵守相应法律法规及开源许可证之规定。
8+
// Usage of this project must strictly comply with applicable laws, regulations, and open-source licenses.
9+
//
10+
// 本项目采用 MIT 许可证与 Apache License 2.0 双许可证分发,
11+
// This project is dual-licensed under the MIT License and Apache License 2.0,
12+
// 完整许可证文本请参见源代码根目录下的 LICENSE 文件。
13+
// please refer to the LICENSE file in the root directory of the source code for the full license text.
14+
//
15+
// 禁止利用本项目实施任何危害国家安全、破坏社会秩序、
16+
// It is prohibited to use this project to engage in any activities that endanger national security, disrupt social order,
17+
// 侵犯他人合法权益等法律法规所禁止的行为!
18+
// or infringe upon the legitimate rights and interests of others, as prohibited by laws and regulations!
19+
// 因基于本项目二次开发所产生的一切法律纠纷与责任,
20+
// Any legal disputes and liabilities arising from secondary development based on this project
21+
// 本项目组织与贡献者概不承担。
22+
// shall be borne solely by the developer; the project organization and contributors assume no responsibility.
23+
//
24+
// GitHub 仓库:https://github.com/GameFrameX
25+
// GitHub Repository: https://github.com/GameFrameX
26+
// Gitee 仓库:https://gitee.com/GameFrameX
27+
// Gitee Repository: https://gitee.com/GameFrameX
28+
// 官方文档:https://gameframex.doc.alianblank.com/
29+
// Official Documentation: https://gameframex.doc.alianblank.com/
30+
// ==========================================================================================
31+
32+
namespace GameFrameX.Apps.Player.Reward.Entity;
33+
34+
/// <summary>
35+
/// 统一奖励发放接口的请求。
36+
/// </summary>
37+
/// <remarks>
38+
/// 调用方必须保证 <see cref="RoleId"/> 命中目标玩家、<see cref="SourceType"/>/<see cref="SourceId"/>/<see cref="TraceId"/> 三者共同唯一。
39+
/// 幂等键 = <c>RoleId:SourceType:SourceId:TraceId</c>(B6),重复提交不重复发奖、短路返回上次结果。
40+
/// </remarks>
41+
public sealed class RewardGrantRequest
42+
{
43+
/// <summary>
44+
/// 目标玩家 ID(玩家 Actor 的 <c>ActorId</c>,等同玩家 <c>PlayerState.Id</c>)。
45+
/// </summary>
46+
public long RoleId { get; set; }
47+
48+
/// <summary>
49+
/// 奖励来源类型。禁止使用 <see cref="RewardSourceType.None"/> 拼接幂等键。
50+
/// </summary>
51+
public RewardSourceType SourceType { get; set; }
52+
53+
/// <summary>
54+
/// 来源 ID。建议形如 <c>mail:&lt;MailId&gt;:attachment:&lt;AttachmentId&gt;</c>,与调用方业务一一对应。
55+
/// </summary>
56+
public string SourceId { get; set; }
57+
58+
/// <summary>
59+
/// 调用方追踪 ID。与 <see cref="SourceType"/>/<see cref="SourceId"/> 组成幂等键的一部分。
60+
/// </summary>
61+
public string TraceId { get; set; }
62+
63+
/// <summary>
64+
/// 待发放奖励列表。逐项独立判定成功 / 失败。
65+
/// </summary>
66+
public List<RewardItem> Rewards { get; set; } = new List<RewardItem>();
67+
}
68+
69+
/// <summary>
70+
/// 统一奖励发放接口的结果。
71+
/// </summary>
72+
public sealed class RewardGrantResult
73+
{
74+
/// <summary>
75+
/// 逐项发放结果。
76+
/// </summary>
77+
public List<RewardGrantItemResult> Items { get; set; } = new List<RewardGrantItemResult>();
78+
79+
/// <summary>
80+
/// 整体错误码(<c>OperationStatusCode</c> 整数值):
81+
/// 全部成功 <c>Ok</c>;部分成功 <c>PartialSuccess</c>;全部失败取首个失败项错误码。
82+
/// </summary>
83+
public int ErrorCode { get; set; }
84+
85+
/// <summary>
86+
/// 是否全部奖励发放成功。
87+
/// </summary>
88+
public bool AllSuccess { get; set; }
89+
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// ==========================================================================================
2+
// GameFrameX 组织及其衍生项目的版权、商标、专利及其他相关权利
3+
// GameFrameX organization and its derivative projects' copyrights, trademarks, patents, and related rights
4+
// 均受中华人民共和国及相关国际法律法规保护。
5+
// are protected by the laws of the People's Republic of China and relevant international regulations.
6+
//
7+
// 使用本项目须严格遵守相应法律法规及开源许可证之规定。
8+
// Usage of this project must strictly comply with applicable laws, regulations, and open-source licenses.
9+
//
10+
// 本项目采用 MIT 许可证与 Apache License 2.0 双许可证分发,
11+
// This project is dual-licensed under the MIT License and Apache License 2.0,
12+
// 完整许可证文本请参见源代码根目录下的 LICENSE 文件。
13+
// please refer to the LICENSE file in the root directory of the source code for the full license text.
14+
//
15+
// 禁止利用本项目实施任何危害国家安全、破坏社会秩序、
16+
// It is prohibited to use this project to engage in any activities that endanger national security, disrupt social order,
17+
// 侵犯他人合法权益等法律法规所禁止的行为!
18+
// or infringe upon the legitimate rights and interests of others, as prohibited by laws and regulations!
19+
// 因基于本项目二次开发所产生的一切法律纠纷与责任,
20+
// Any legal disputes and liabilities arising from secondary development based on this project
21+
// 本项目组织与贡献者概不承担。
22+
// shall be borne solely by the developer; the project organization and contributors assume no responsibility.
23+
//
24+
// GitHub 仓库:https://github.com/GameFrameX
25+
// GitHub Repository: https://github.com/GameFrameX
26+
// Gitee 仓库:https://gitee.com/GameFrameX
27+
// Gitee Repository: https://gitee.com/GameFrameX
28+
// 官方文档:https://gameframex.doc.alianblank.com/
29+
// Official Documentation: https://gameframex.doc.alianblank.com/
30+
// ==========================================================================================
31+
32+
namespace GameFrameX.Apps.Player.Reward.Entity;
33+
34+
/// <summary>
35+
/// 单个奖励项,统一奖励发放接口的输入单元。
36+
/// </summary>
37+
public sealed class RewardItem
38+
{
39+
/// <summary>
40+
/// 奖励类型。决定发放路由:普通道具写背包,其余类型一期返回 <c>Unsupported</c>。
41+
/// </summary>
42+
public RewardType RewardType { get; set; }
43+
44+
/// <summary>
45+
/// 物品 ID。普通道具对应 <c>TbItemConfig</c> 配置 ID。
46+
/// </summary>
47+
public int ItemId { get; set; }
48+
49+
/// <summary>
50+
/// 数量。必须大于 0,否则该项被判为 <c>InvalidReward</c>。
51+
/// </summary>
52+
public long Count { get; set; }
53+
54+
/// <summary>
55+
/// 扩展数据(预留)。一期发放接口不解析,仅随账本原样持久化。
56+
/// </summary>
57+
public string ExtraData { get; set; }
58+
}

0 commit comments

Comments
 (0)